modified-next-i18next
Version:
A slightly modified version of next-i18next to allow for different folder structure.
256 lines (170 loc) • 12.8 kB
Markdown
# next-i18next
[](https://badge.fury.io/js/next-i18next)
[](https://circleci.com/gh/isaachinman/next-i18next)
[](https://packagequality.com/#?package=next-i18next)
**The easiest way to translate your NextJs apps.**
If you are using next-i18next in production, please consider [sponsoring the package](https://github.com/sponsors/isaachinman) with any amount you think appropriate.
## What is this?
Although NextJs [provides internationalised routing directly](https://nextjs.org/docs/advanced-features/i18n-routing), it does not handle any management of translation content, or the actual translation functionality itself. All NextJs does is keep your locales and URLs in sync.
To complement this, `next-i18next` provides the remaining functionality – management of translation content, and components/hooks to translate your React components – while fully supporting SSG/SSR, multiple [namespaces](https://www.i18next.com/principles/namespaces), codesplitting, etc.
While `next-i18next` uses [i18next](https://www.i18next.com/) and [react-i18next](https://github.com/i18next/react-i18next) under the hood, users of `next-i18next` simply need to include their translation content as JSON files and don't have to worry about much else.
A live demo is [available here](http://next-i18next.com/). This demo app is the [simple example](./examples/simple/) - nothing more, nothing less.
## Why next-i18next?
Easy to set up, easy to use: setup only takes a few steps, and configuration is simple.
No other requirements: `next-i18next` simplifies internationalisation for your [NextJs](https://nextjs.org/) app without extra dependencies.
Production ready: `next-i18next` supports passing translations and configuration options into pages as props with SSG/SSR support.
## How does it work?
Your `next-i18next.config.js` file will provide configuration for `next-i18next`.
After configuration, `appWithTranslation` allows us to use the `t` (translate) function in our components via hooks.
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.
Now our NextJs app is fully translatable!
## Setup
### 1. Installation
```jsx
yarn add next-i18next
```
You need to also have `react` and `next` installed.
### 2. Translation content
By default, `next-i18next` expects your translations to be organised as such:
```
.
└── public
└── locales
├── en
| └── common.json
└── de
└── common.json
```
This structure can also be seen in the [simple example](./examples/simple).
If you want to structure your translations/namespaces in a custom way, you will need to pass modified `localePath` and `localeStructure` values into the initialisation config.
### 3. Project setup
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).
This tells `next-i18next` what your `defaultLocale` and other locales are, so that it can preload translations on the server:
#### `next-i18next.config.js`
```js
module.exports = {
i18n: {
defaultLocale: 'en',
locales: ['en', 'de'],
},
}
```
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:
#### [`next.config.js`](https://nextjs.org/docs/api-reference/next.config.js/introduction)
```js
const { i18n } = require('./next-i18next.config')
module.exports = {
i18n,
}
```
There are three functions that `next-i18next` exports, which you will need to use to translate your project:
#### appWithTranslation
This is a HOC which wraps your [`_app`](https://nextjs.org/docs/advanced-features/custom-app):
```tsx
import { appWithTranslation } from 'next-i18next'
const MyApp = ({ Component, pageProps }) => <Component {...pageProps} />
export default appWithTranslation(MyApp)
```
The `appWithTranslation` HOC is primarily responsible for adding a [`I18nextProvider`](https://react.i18next.com/latest/i18nextprovider).
#### serverSideTranslations
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):
```tsx
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
export async function getStaticProps({ locale }) {
return {
props: {
...(await serverSideTranslations(locale, ['common', 'footer'])),
// Will be passed to the page component as props
}
}
}
```
Note that `serverSideTranslations` must be imported from `next-i18next/serverSideTranslations` – this is a separate module that contains NodeJs-specific code.
Also, note that `serverSideTranslations` is not compatible with `getInitialProps`, as it _only_ can execute in a server environment, whereas `getInitialProps` is called on the client side when navigating between pages.
The `serverSideTranslations` HOC is primarily responsible for passing translations and configuration options into pages, as props.
### useTranslation
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:
```tsx
import { useTranslation } from 'next-i18next'
export const Footer = () => {
const { t } = useTranslation('footer')
return (
<footer>
<p>
{t('description')}
</p>
</footer>
)
}
```
### 4. Declaring namespace dependencies
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.
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).
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.
### 5. Advanced configuration
#### Passing other config options
If you need to modify more advanced configuration options, you can pass them via `next-i18next.config.js`. For example:
```js
const path = require('path')
module.exports = {
i18n: {
defaultLocale: 'en',
locales: ['en', 'de'],
},
localePath: path.resolve('./my/custom/path')
}
```
#### Unserialisable configs
Some `i18next` plugins (which you can pass into `config.use`) are unserialisable, as they contain functions and other JavaScript primitives.
You may run into this if your use case is more advanced. You'll see NextJs throw an error like:
```
Error: Error serializing `._nextI18Next.userConfig.use[0].process` returned from `getStaticProps` in "/my-page".
Reason: `function` cannot be serialized as JSON. Please only return JSON serializable data types.
```
To fix this, you'll need to set `config.serializeConfig` to `false`, and manually pass your config into `appWithTranslation`:
```tsx
import { appWithTranslation } from 'next-i18next'
import nextI18NextConfig from '../next-i18next.config.js'
const MyApp = ({ Component, pageProps }) => <Component {...pageProps} />
export default appWithTranslation(MyApp, nextI18NextConfig)
```
```tsx
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
import nextI18NextConfig from '../next-i18next.config.js'
export const getStaticProps = async ({ locale }) => ({
props: {
...await serverSideTranslations(locale, ['common', 'footer'], nextI18NextConfig),
}
})
```
#### Options
| Key | Default value |
| ------------- | ------------- |
| `defaultNS` | `'common'` |
| `localeExtension` | `'json'` |
| `localePath` | `'./public/locales'` |
| `localeStructure` | `'{{lng}}/{{ns}}'` |
| `serializeConfig` | `true` |
| `strictMode` | `true` |
| `use` (for plugins) | `[]` |
All other [i18next options](https://www.i18next.com/overview/configuration-options) can be passed in as well.
## Notes
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.
```
COPY --from=builder /app/next.config.js ./next.config.js
COPY --from=builder /app/next-i18next.config.js ./next-i18next.config.js
```
## Contributors
Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds/all-contributors#emoji-key)):
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore -->
<table cellspacing="0" cellpadding="1"><tr><td><a href="https://github.com/capellini"><img src="https://avatars3.githubusercontent.com/u/75311?v=4" width="100px;" height="100px;" alt="Rob Capellini"/><br /><sub><b>Rob Capellini</b></sub></a><br /><a href="https://github.com/isaachinman/next-i18next/commits?author=capellini" title="Code">💻</a> <a href="https://github.com/isaachinman/next-i18next/commits?author=capellini" title="Tests">⚠️</a></td><td><a href="https://en.kachkaev.ru"><img src="https://avatars3.githubusercontent.com/u/608862?v=4" width="100px;" height="100px;" alt="Alexander Kachkaev"/><br /><sub><b>Alexander Kachkaev</b></sub></a><br /><a href="#talk-kachkaev" title="Talks">📢</a> <a href="#question-kachkaev" title="Answering Questions">💬</a> <a href="#ideas-kachkaev" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/isaachinman/next-i18next/commits?author=kachkaev" title="Code">💻</a> <a href="https://github.com/isaachinman/next-i18next/commits?author=kachkaev" title="Tests">⚠️</a></td><td><a href="https://kandelborg.dk"><img src="https://avatars1.githubusercontent.com/u/33042011?v=4" width="100px;" height="100px;" alt="Mathias Wøbbe"/><br /><sub><b>Mathias Wøbbe</b></sub></a><br /><a href="https://github.com/isaachinman/next-i18next/commits?author=MathiasKandelborg" title="Code">💻</a> <a href="#ideas-MathiasKandelborg" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/isaachinman/next-i18next/commits?author=MathiasKandelborg" title="Tests">⚠️</a></td><td><a href="http://lucasfeliciano.com"><img src="https://avatars3.githubusercontent.com/u/968014?v=4" width="100px;" height="100px;" alt="Lucas Feliciano"/><br /><sub><b>Lucas Feliciano</b></sub></a><br /><a href="#ideas-lucasfeliciano" title="Ideas, Planning, & Feedback">🤔</a> <a href="#review-lucasfeliciano" title="Reviewed Pull Requests">👀</a></td><td><a href="http://www.fifteenprospects.com"><img src="https://avatars2.githubusercontent.com/u/6932550?v=4" width="100px;" height="100px;" alt="Ryan Leung"/><br /><sub><b>Ryan Leung</b></sub></a><br /><a href="https://github.com/isaachinman/next-i18next/commits?author=minocys" title="Code">💻</a></td><td><a href="http://nathanfriemel.com"><img src="https://avatars3.githubusercontent.com/u/1325835?v=4" width="100px;" height="100px;" alt="Nathan Friemel"/><br /><sub><b>Nathan Friemel</b></sub></a><br /><a href="https://github.com/isaachinman/next-i18next/commits?author=nathanfriemel" title="Code">💻</a> <a href="https://github.com/isaachinman/next-i18next/commits?author=nathanfriemel" title="Documentation">📖</a> <a href="#example-nathanfriemel" title="Examples">💡</a> <a href="#ideas-nathanfriemel" title="Ideas, Planning, & Feedback">🤔</a></td></tr></table>
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
## Sponsors
<a href="https://locize.com/" target="_blank">
<img src="https://raw.githubusercontent.com/i18next/i18next/master/assets/locize_sponsor_240.gif" width="240px">
</a>
<a href="https://www.browserstack.com/" target="_blank">
<img src="https://miro.medium.com/max/560/0*dLdslKvNsmtaH2uQ.png" width="240px">
</a>