├── .eslintignore
├── .eslintrc.json
├── .github
└── workflows
│ ├── deploy.yml
│ └── test.yml
├── .gitignore
├── .npmignore
├── .tool-versions
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── config
├── env.js
├── jest
│ ├── cssTransform.js
│ └── fileTransform.js
├── paths.js
├── polyfills.js
├── webpack.config.demo.js
├── webpack.config.dev.js
├── webpack.config.prod.js
└── webpackDevServer.config.js
├── package.json
├── public
├── favicon.ico
├── index.html
└── manifest.json
├── scripts
├── build.js
├── demo.js
├── start.js
└── test.js
├── src
├── demo
│ ├── App.js
│ ├── App.test.js
│ ├── I18n.js
│ ├── __snapshots__
│ │ └── App.test.js.snap
│ ├── index.js
│ └── registerServiceWorker.js
└── lib
│ ├── components
│ └── I18n
│ │ ├── __snapshots__
│ │ ├── createI18n.test.js.snap
│ │ └── withLocale.test.js.snap
│ │ ├── createI18n.js
│ │ ├── createI18n.test.js
│ │ ├── index.js
│ │ ├── withLocale.js
│ │ └── withLocale.test.js
│ └── index.js
└── yarn.lock
/.eslintignore:
--------------------------------------------------------------------------------
1 | /build/
2 | /demo/
3 | /config/
4 | /scripts/
5 | /src/demo/index.js
6 | /src/demo/registerServiceWorker.js
7 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 | "parser": "babel-eslint",
4 | "rules": {
5 | "react/jsx-filename-extension": [1, { "extensions": [".js"] }],
6 | "react/jsx-props-no-spreading": 0
7 | },
8 | "overrides": [
9 | {
10 | "files": [
11 | "**/*.test.js"
12 | ],
13 | "env": {
14 | "jest": true
15 | },
16 | "plugins": ["jest"],
17 | "rules": {
18 | "jest/no-disabled-tests": "warn",
19 | "jest/no-focused-tests": "error",
20 | "jest/no-identical-title": "error",
21 | "jest/prefer-to-have-length": "warn",
22 | "jest/valid-expect": "error",
23 | "react/prop-types": [0]
24 | },
25 | "globals": {
26 | "window": true
27 | }
28 | }
29 | ]
30 | }
31 |
--------------------------------------------------------------------------------
/.github/workflows/deploy.yml:
--------------------------------------------------------------------------------
1 | name: deploy
2 |
3 | on:
4 | push:
5 | branches: [master]
6 |
7 | jobs:
8 | deploy:
9 | runs-on: ubuntu-latest
10 |
11 | steps:
12 | - uses: actions/checkout@v2
13 |
14 | - uses: actions/setup-node@v2-beta
15 | with:
16 | node-version: '14'
17 |
18 | - name: Install dependencies
19 | run: yarn install
20 |
21 | - name: Run tests
22 | run: yarn test --coverage
23 | env:
24 | CI: true
25 |
26 | - name: Build
27 | run: yarn demo
28 | env:
29 | PUBLIC_URL: /react-router-i18n
30 |
31 | - name: Deploy GitHub
32 | uses: JamesIves/github-pages-deploy-action@releases/v3
33 | with:
34 | GITHUB_TOKEN: ${{ github.token }}
35 | BRANCH: gh-pages
36 | FOLDER: demo
37 | CLEAN: true
38 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Run tests
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | test:
7 | runs-on: ubuntu-latest
8 | strategy:
9 | matrix:
10 | node: ['10', '12', '14']
11 | name: Node ${{ matrix.node }} test
12 | steps:
13 | - uses: actions/checkout@v2
14 |
15 | - uses: actions/setup-node@v1
16 | with:
17 | node-version: ${{ matrix.node }}
18 |
19 | - name: Install dependencies
20 | run: yarn install
21 |
22 | - name: Lint code
23 | run: yarn lint
24 |
25 | # Ideally yarn audit would be part of the CI flow
26 | # but currently there is too much noise
27 | # See e.g. https://github.com/facebook/create-react-app/issues/8529
28 | # - name: Audit dependencies
29 | # - run: yarn audit
30 |
31 | - name: Run tests
32 | run: yarn test --coverage
33 | env:
34 | CI: true
35 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # production
7 | /build
8 | /demo
9 |
10 | # testing
11 | /coverage
12 |
13 | # misc
14 | .DS_Store
15 | .env.local
16 | .env.development.local
17 | .env.test.local
18 | .env.production.local
19 |
20 | npm-debug.log*
21 | package-lock.json
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # dependencies
2 | /node_modules
3 |
4 | # testing
5 | /coverage
6 |
7 | # misc
8 | .DS_Store
9 | .env.local
10 | .env.development.local
11 | .env.test.local
12 | .env.production.local
13 |
14 | npm-debug.log*
15 | yarn-debug.log*
16 | yarn-error.log*
17 |
18 | # Development folders and files
19 | public
20 | src
21 | scripts
22 | config
23 | demo
24 | .travis.yml
25 | .eslintignore
26 | .eslintrc.json
27 | .tool-versions
28 | yarn.lock
29 | /.github
30 |
--------------------------------------------------------------------------------
/.tool-versions:
--------------------------------------------------------------------------------
1 | nodejs 12.6.0
2 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to make participation in react-router-i18n and
7 | its associated community a harassment-free experience for everyone, regardless of age,
8 | body size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies within project spaces and when
49 | an individual is officially representing the project or its community.
50 | Examples of representing a project or community include using an official
51 | project e-mail address, posting via an official social media account, or acting
52 | as an appointed representative at an online or offline event. Representation of
53 | a project may be further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at zf.node [at] gmail [dot] com. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2021 The Perseids Project, zfletch
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React Router I18n
2 |
3 | This is a small opinionated library for I18n (internationalization) using React Router.
4 |
5 | ## Demo
6 |
7 | [https://zfletch.github.io/react-router-i18n/](https://zfletch.github.io/react-router-i18n/)
8 |
9 | ## Installation
10 |
11 | `yarn add react-router-i18n`
12 |
13 | Note that this package has the following peer dependencies:
14 |
15 | ```json
16 | {
17 | "react": "^16.8.4",
18 | "react-dom": "^16.8.1",
19 | "react-router-dom": "^4.3.0 || ^5.0.0"
20 | }
21 | ```
22 |
23 | (See project on [npm](https://www.npmjs.com/package/react-router-i18n))
24 |
25 | ## How to use
26 |
27 | ### Demo
28 |
29 | See the demo [App.js](/src/demo/App.js) and [I18n.js](/src/demo/I18n.js).
30 |
31 | ### Setup
32 |
33 | First, create a component called `I18n`. It should look like this:
34 |
35 | ```jsx
36 | import { createI18n } from 'react-router-i18n';
37 |
38 | // Array of supported locales
39 | // The first in the array is treated as the default locale
40 | const locales = ['en', 'fr'];
41 |
42 | // Dictionary of translations
43 | const translations = {
44 | en: {
45 | hello: 'Hello',
46 | },
47 | fr: {
48 | hello: 'Bonjour',
49 | }
50 | }
51 |
52 | const I18n = createI18n(
53 | locales,
54 | translations,
55 | );
56 |
57 | export default I18n;
58 | ```
59 |
60 | Then make the following changes to your routes:
61 |
62 | ```jsx
63 | import React from 'react';
64 | import { BrowserRouter as Router, Route } from 'react-router-dom';
65 |
66 | // Match locales with regular expression containing each locale separated by `|`
67 | const base = '/:locale(en|fr)?';
68 |
69 | const App = () => (
70 |