Skip to content

Commit eae0751

Browse files
authored
Merge branch 'master' into shallow-routing-support
2 parents 5ca42f9 + 98797ef commit eae0751

10 files changed

+1675
-1251
lines changed

README.md

+75-48
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# next-i18next
2+
23
[![npm version](https://badge.fury.io/js/next-i18next.svg)](https://badge.fury.io/js/next-i18next)
34
[![CircleCI](https://circleci.com/gh/isaachinman/next-i18next.svg?style=shield)](https://circleci.com/gh/isaachinman/next-i18next)
45
[![Package Quality](https://npm.packagequality.com/shield/next-i18next.svg)](https://packagequality.com/#?package=next-i18next)
@@ -17,6 +18,23 @@ While `next-i18next` uses [i18next](https://www.i18next.com/) and [react-i18next
1718

1819
A live demo is [available here](http://next-i18next.com/). This demo app is the [simple example](./examples/simple/) - nothing more, nothing less.
1920

21+
## Why next-i18next?
22+
23+
Easy to set up, easy to use: setup only takes a few steps, and configuration is simple.
24+
25+
No other requirements: `next-i18next` simplifies internationalisation for your [NextJs](https://nextjs.org/) app without extra dependencies.
26+
27+
Production ready: `next-i18next` supports passing translations and configuration options into pages as props with SSG/SSR support.
28+
29+
## How does it work?
30+
31+
Your `next-i18next.config.js` file will provide configuration for `next-i18next`.
32+
After configuration, `appWithTranslation` allows us to use the `t` (translate) function in our components via hooks.
33+
34+
Then we add `serverSideTranslation` to [getStaticProps](https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation) or [getServerSideProps](https://nextjs.org/docs/basic-features/data-fetching#getserversideprops-server-side-rendering) (depending on your case) in our page-level components.
35+
36+
Now our NextJs app is fully translatable!
37+
2038
## Setup
2139

2240
### 1. Installation
@@ -30,6 +48,7 @@ You need to also have `react` and `next` installed.
3048
### 2. Translation content
3149

3250
By default, `next-i18next` expects your translations to be organised as such:
51+
3352
```
3453
.
3554
└── public
@@ -46,7 +65,7 @@ If you want to structure your translations/namespaces in a custom way, you will
4665

4766
### 3. Project setup
4867

49-
First, create a `next-i18next.config.js` file in the root of your project. The syntax for the nested `i18n` object [comes from NextJs directly](https://nextjs.org/docs/advanced-features/i18n-routing).
68+
First, create a `next-i18next.config.js` file in the root of your project. The syntax for the nested `i18n` object [comes from NextJs directly](https://nextjs.org/docs/advanced-features/i18n-routing).
5069

5170
This tells `next-i18next` what your `defaultLocale` and other locales are, so that it can preload translations on the server:
5271

@@ -58,19 +77,19 @@ module.exports = {
5877
defaultLocale: 'en',
5978
locales: ['en', 'de'],
6079
},
61-
}
80+
};
6281
```
6382

6483
Now, create or modify your `next.config.js` file, by passing the `i18n` object into your `next.config.js` file, to enable localised URL routing:
6584

66-
#### `next.config.js`
85+
#### [`next.config.js`](https://nextjs.org/docs/api-reference/next.config.js/introduction)
6786

6887
```js
69-
const { i18n } = require('./next-i18next.config')
88+
const { i18n } = require('./next-i18next.config');
7089

7190
module.exports = {
7291
i18n,
73-
}
92+
};
7493
```
7594

7695
There are three functions that `next-i18next` exports, which you will need to use to translate your project:
@@ -80,27 +99,30 @@ There are three functions that `next-i18next` exports, which you will need to us
8099
This is a HOC which wraps your [`_app`](https://nextjs.org/docs/advanced-features/custom-app):
81100

82101
```tsx
83-
import { appWithTranslation } from 'next-i18next'
102+
import { appWithTranslation } from 'next-i18next';
84103

85-
const MyApp = ({ Component, pageProps }) => <Component {...pageProps} />
104+
const MyApp = ({ Component, pageProps }) => <Component {...pageProps} />;
86105

87-
export default appWithTranslation(MyApp)
106+
export default appWithTranslation(MyApp);
88107
```
89108

90-
The `appWithTranslation` HOC is primarily responsible for adding a `I18nextProvider`.
109+
The `appWithTranslation` HOC is primarily responsible for adding a [`I18nextProvider`](https://react.i18next.com/latest/i18nextprovider).
91110

92111
#### serverSideTranslations
93112

94113
This is an async function that you need to include on your page-level components, via either [`getStaticProps`](https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation) or [`getServerSideProps`](https://nextjs.org/docs/basic-features/data-fetching#getserversideprops-server-side-rendering) (depending on your use case):
95114

96115
```tsx
97-
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
98-
99-
export const getStaticProps = async ({ locale }) => ({
100-
props: {
101-
...await serverSideTranslations(locale, ['common', 'footer']),
102-
}
103-
})
116+
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
117+
118+
export async function getStaticProps({ locale }) {
119+
return {
120+
props: {
121+
...(await serverSideTranslations(locale, ['common', 'footer'])),
122+
// Will be passed to the page component as props
123+
},
124+
};
125+
}
104126
```
105127

106128
Note that `serverSideTranslations` must be imported from `next-i18next/serverSideTranslations` – this is a separate module that contains NodeJs-specific code.
@@ -114,47 +136,43 @@ The `serverSideTranslations` HOC is primarily responsible for passing translatio
114136
This is the hook which you'll actually use to do the translation itself. The `useTranslation` hook [comes from `react-i18next`](https://react.i18next.com/latest/usetranslation-hook), but can be imported from `next-i18next` directly:
115137

116138
```tsx
117-
import { useTranslation } from 'next-i18next'
139+
import { useTranslation } from 'next-i18next';
118140

119141
export const Footer = () => {
120-
121-
const { t } = useTranslation('footer')
142+
const { t } = useTranslation('footer');
122143

123144
return (
124145
<footer>
125-
<p>
126-
{t('description')}
127-
</p>
146+
<p>{t('description')}</p>
128147
</footer>
129-
)
130-
}
148+
);
149+
};
131150
```
132151

133152
### 4. Declaring namespace dependencies
134153

135154
By default, `next-i18next` will send _all your namespaces_ down to the client on each initial request. This can be an appropriate approach for smaller apps with less content, but a lot of apps will benefit from splitting namespaces based on route.
136155

137-
To do that, you can pass an array of required namespaces for each page into `serverSideTranslations`. You can see this approach in [examples/simple/pages/index.js](./examples/simple/pages/index.js).
156+
To do that, you can pass an array of required namespaces for each page into `serverSideTranslations`. You can see this approach in [examples/simple/pages/index.js](./examples/simple/pages/index.js). Passing in an empty array of required namespaces will send no namespaces.
138157

139158
Note: `useTranslation` provides namespaces to the component that you use it in. However, `serverSideTranslations` provides the total available namespaces to the entire React tree and belongs on the page level. Both are required.
140159

141160
### 5. Advanced configuration
142161

143-
144162
#### Passing other config options
145163

146164
If you need to modify more advanced configuration options, you can pass them via `next-i18next.config.js`. For example:
147165

148166
```js
149-
const path = require('path')
167+
const path = require('path');
150168

151169
module.exports = {
152170
i18n: {
153171
defaultLocale: 'en',
154172
locales: ['en', 'de'],
155173
},
156-
localePath: path.resolve('./my/custom/path')
157-
}
174+
localePath: path.resolve('./my/custom/path'),
175+
};
158176
```
159177

160178
#### Unserialisable configs
@@ -171,42 +189,52 @@ Reason: `function` cannot be serialized as JSON. Please only return JSON seriali
171189
To fix this, you'll need to set `config.serializeConfig` to `false`, and manually pass your config into `appWithTranslation`:
172190

173191
```tsx
174-
import { appWithTranslation } from 'next-i18next'
175-
import nextI18NextConfig from '../next-i18next.config.js'
192+
import { appWithTranslation } from 'next-i18next';
193+
import nextI18NextConfig from '../next-i18next.config.js';
176194

177-
const MyApp = ({ Component, pageProps }) => <Component {...pageProps} />
195+
const MyApp = ({ Component, pageProps }) => <Component {...pageProps} />;
178196

179-
export default appWithTranslation(MyApp, nextI18NextConfig)
197+
export default appWithTranslation(MyApp, nextI18NextConfig);
180198
```
181199

182200
```tsx
183-
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
201+
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
184202

185-
import nextI18NextConfig from '../next-i18next.config.js'
203+
import nextI18NextConfig from '../next-i18next.config.js';
186204

187205
export const getStaticProps = async ({ locale }) => ({
188206
props: {
189-
...await serverSideTranslations(locale, ['common', 'footer'], nextI18NextConfig),
190-
}
191-
})
207+
...(await serverSideTranslations(
208+
locale,
209+
['common', 'footer'],
210+
nextI18NextConfig
211+
)),
212+
},
213+
});
192214
```
193215

194216
#### Options
195217

196-
| Key | Default value |
197-
| ------------- | ------------- |
198-
| `defaultNS` | `'common'` |
199-
| `localeExtension` | `'json'` |
200-
| `localePath` | `'./public/locales'` |
201-
| `localeStructure` | `'{{lng}}/{{ns}}'` |
202-
| `serializeConfig` | `true` |
203-
| `strictMode` | `true` |
204-
| `use` (for plugins) | `[]` |
218+
| Key | Default value |
219+
| ------------------- | -------------------- |
220+
| `defaultNS` | `'common'` |
221+
| `localeExtension` | `'json'` |
222+
| `localePath` | `'./public/locales'` |
223+
| `localeStructure` | `'{{lng}}/{{ns}}'` |
224+
| `serializeConfig` | `true` |
225+
| `strictMode` | `true` |
226+
| `use` (for plugins) | `[]` |
205227

206228
All other [i18next options](https://www.i18next.com/overview/configuration-options) can be passed in as well.
207229

230+
## Migration to v8
231+
232+
To migrate from previous versions to the version 8, check out the [v8-migration guide](https://github.com/isaachinman/next-i18next/tree/master/docs/v8-migration.md)
233+
208234
## Notes
235+
209236
For Docker deployment, note that if you use the `Dockerfile` from [Next.js docs](https://nextjs.org/docs/deployment#docker-image) do not forget to copy `next.config.js` and `next-i18next.config.js` into the Docker image.
237+
210238
```
211239
COPY --from=builder /app/next.config.js ./next.config.js
212240
COPY --from=builder /app/next-i18next.config.js ./next-i18next.config.js
@@ -232,4 +260,3 @@ This project follows the [all-contributors](https://github.com/kentcdodds/all-co
232260
<a href="https://www.browserstack.com/" target="_blank">
233261
<img src="https://miro.medium.com/max/560/0*dLdslKvNsmtaH2uQ.png" width="240px">
234262
</a>
235-

docs/v8-migration.md

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Migration Guide v7 to v8
2+
3+
Please read the [full documentation](https://github.com/isaachinman/next-i18next/blob/master/README.md), before migrating from previous versions to v8.
4+
5+
This is a guide which will cover most use cases to migrate from v7 to v8.
6+
We advise migrating as soon as possible, as new versions of NextJs won't be compatible with the v7 of this package `next-i18next`.
7+
8+
## What is new?
9+
10+
This package, `next-i18next`, has changed a lot because it now is _not_ providing internationalised routing anymore, as [NextJs has first class support for it.](https://nextjs.org/docs/advanced-features/i18n-routing)
11+
12+
Before the translation functionality was initialised on a global level, in `_app.js`. Now, you must use a new method, called `serverSideTranslations` on *each* page in your `pages` directory.
13+
14+
The object `i18n` which was imported directly from `i18n.js` in `next-i18next@<8` suppored only client-side-rendering. Now in the v8 the `i18n` object also supports server-side rendering. So you can use the `i18n.language` for server-side rendered elements.
15+
16+
## What is the same?
17+
18+
1. `appWithTranslation` still wraps the App in `_app.js`
19+
2. `withTranslation` works the same way
20+
3. `useTranslation` works the same way
21+
4. The [translation content structure](https://github.com/isaachinman/next-i18next/blob/master/README.md#2-translation-content) remains the same
22+
23+
24+
## What is different?
25+
26+
1. `getInitialProps` is not supported anymore, using `serverSideTranslations` is mandatory for all pages.
27+
If you require `getInitialProps` keep using the last `7.x` version.
28+
29+
## Step By Step Migration Guide
30+
31+
1. Remove `i18n.js` and add `next-i18next.config.js` as described in [the docs](https://github.com/isaachinman/next-i18next#3-project-setup) to your `next.config.js` file
32+
2. Replace `import { appWithTranslation } from 'i18n'` with `import { appWithTranslation } from 'next-i18next'`
33+
3. Replace all instances of `import { withTranslation } from 'i18n` to `import { withTranslation } from 'next-i18next'`
34+
4. Replace all instances of `import { useTranslation } from 'i18n` to `import { useTranslation } from 'next-i18next'`
35+
5. Add to `getServerSideProps` or `getStaticProps` in the return as props`...(await serverSideTranslations(locale, [<YOUR_NAMESPACES>]))` in every single page where you have translations. Note that if you have a component in `_app` that needs translations, you will have to do this for _all_ pages. Follow [the docs.](https://github.com/isaachinman/next-i18next#serversidetranslations)
36+
6. Remove `namespacesRequired: ['common'],` in `_app.js` (not used anymore)
37+
7. To change language imperatively, you can now do: `router.push(router.asPath, undefined, { locale: <YOUR_LOCALE>, });`
38+
39+
## Optional
40+
41+
1. Add to the custom 404 page the `...(await serverSideTranslations(locale, [<YOUR_NAMESPACES>])),` as a return in props in `getStaticProps` so the 404 page works with translations as well
42+
2. Add to the custom 500 page the `...(await serverSideTranslations(locale, [<YOUR_NAMESPACES>])),` as a return in props in `getStaticProps` so the 500 page works with translations as well
43+
3. Add set cookie `NEXT_LOCALE` for language recognition. More about that in [the NextJs docs](https://nextjs.org/docs/advanced-features/i18n-routing#leveraging-the-next_locale-cookie)
44+
4. Adjust the Jest test settings to mock `withTranslation`,`useTranslation`, and `t()` or/and `i18n` in props.
45+
46+
More info in the [full documentation](https://github.com/isaachinman/next-i18next/blob/master/README.md), or in the [next.js documentation.](https://nextjs.org/docs/advanced-features/i18n-routing)

examples/simple/yarn.lock

+4-4
Original file line numberDiff line numberDiff line change
@@ -959,9 +959,9 @@ color-name@^1.0.0, color-name@~1.1.4:
959959
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
960960

961961
color-string@^1.5.4:
962-
version "1.5.4"
963-
resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.4.tgz#dd51cd25cfee953d138fe4002372cc3d0e504cb6"
964-
integrity sha512-57yF5yt8Xa3czSEW1jfQDE79Idk0+AkN/4KWad6tbdxUmAs3MvjxlWSWD4deYytcRfoZ9nhKyFl1kj5tBvidbw==
962+
version "1.5.5"
963+
resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.5.tgz#65474a8f0e7439625f3d27a6a19d89fc45223014"
964+
integrity sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg==
965965
dependencies:
966966
color-name "^1.0.0"
967967
simple-swizzle "^0.2.2"
@@ -2492,7 +2492,7 @@ neo-async@^2.5.0, neo-async@^2.6.1, neo-async@^2.6.2:
24922492
integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
24932493

24942494
"next-i18next@link:../..":
2495-
version "8.2.0"
2495+
version "8.5.1"
24962496
dependencies:
24972497
"@babel/runtime" "^7.13.17"
24982498
"@types/hoist-non-react-statics" "^3.3.1"

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "next-i18next",
3-
"version": "8.2.0",
3+
"version": "8.6.0",
44
"repository": "git@github.com:isaachinman/next-i18next.git",
55
"author": "Isaac Hinman <isaac@isaachinman.com>",
66
"funding": {
@@ -74,7 +74,7 @@
7474
"@babel/preset-typescript": "^7.10.4",
7575
"@testing-library/react": "^11.2.5",
7676
"@types/jest": "^26.0.20",
77-
"@types/node": "^15.0.2",
77+
"@types/node": "^16.7.1",
7878
"@types/react": "^17.0.3",
7979
"@types/react-dom": "^17.0.3",
8080
"@types/testing-library__cypress": "^5.0.8",

0 commit comments

Comments
 (0)