Skip to content

Commit 2c60c1f

Browse files
committed
feat: use i18next plugin system to get the i18next instance.
1 parent d3863d9 commit 2c60c1f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+408
-386
lines changed

README.md

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ $ npm install --save-dev i18next-hmr
1919

2020
## Usage
2121

22-
Add the plugin to your webpack config (or nextjs).
22+
Add the plugin to your webpack config (or next.config.js).
2323

2424
<!-- prettier-ignore-start -->
2525

2626
```js
2727
// webpack.config.js
28-
const { I18NextHMRPlugin } = require('i18next-hmr/plugin');
28+
const { I18NextHMRPlugin } = require('i18next-hmr/webpack');
2929

3030
module.exports = {
3131
...
@@ -44,12 +44,22 @@ module.exports = {
4444

4545
```js
4646
// i18next.config.js
47+
const Backend = require('i18next-http-backend');
4748
const i18next = require('i18next');
48-
i18next.init(options, callback);
49+
const { HMRPlugin } = require('i18next-hmr/plugin');
50+
51+
const instance = i18next.use(Backend); // http-backend is required for client side reloading
52+
4953
if (process.env.NODE_ENV !== 'production') {
50-
const { applyClientHMR } = require('i18next-hmr/client');
51-
applyClientHMR(i18next);
54+
instance.use(new HMRPlugin({
55+
client: typeof window !== 'undefined', // enabled client side HMR
56+
server: typeof window === 'undefined' // enabled server side HMR
57+
}));
5258
}
59+
60+
instance.init(options, callback);
61+
62+
module.exports = instance;
5363
```
5464

5565
<!-- prettier-ignore-start -->
@@ -58,13 +68,6 @@ if (process.env.NODE_ENV !== 'production') {
5868
// server.js
5969
const express = require('express');
6070

61-
const i18n = require('./i18n');
62-
63-
if (process.env.NODE_ENV !== 'production') {
64-
const { applyServerHMR } = require('i18next-hmr/server');
65-
applyServerHMR(i18n);
66-
}
67-
6871
const port = process.env.PORT || 3000;
6972

7073
(async () => {
@@ -85,8 +88,8 @@ The lib will trigger [`i18n.reloadResources([lang], [ns])`](https://www.i18next.
8588
⚠️ If your server side is bundled using Webpack, the lib will use the native HMR (if enabled), for it to work properly the lib must be **bundled**, therefore, you should specify the lib as not [external](https://webpack.js.org/configuration/externals/).
8689
There are 2 ways to do that:
8790

88-
1. if you are using [webpack-node-externals](https://github.com/liady/webpack-node-externals) specify `i18next-hmr` in the [`whitelist`](https://github.com/liady/webpack-node-externals#optionswhitelist-).
89-
2. use a relative path to `node_modules`, something like:
91+
1. If you are using [webpack-node-externals](https://github.com/liady/webpack-node-externals) specify `i18next-hmr` in the [`whitelist`](https://github.com/liady/webpack-node-externals#optionswhitelist-).
92+
2. (deprecated method) use a relative path to `node_modules`, something like:
9093
```js
9194
// server.entry.js
9295
if (process.env.NODE_ENV !== 'production') {

__tests__/loader.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const loader = require('../lib/loader');
1+
const loader = require('../lib/webpack/loader');
22

33
describe('loader', () => {
44
let context;

__tests__/server-hmr.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ jest.mock('../lib/trigger.js', () => {
44
return changedData;
55
});
66
const applyServerHMR = require('../lib/server-hmr');
7-
const plugin = require('../lib/plugin');
7+
const plugin = require('../lib/webpack/plugin');
88
const applyClientHMR = require('../lib/client-hmr');
99

1010
function whenNativeHMRTriggeredWith(changedFiles) {

examples/next-with-next-i18next-v11/pages/_app.js

Lines changed: 0 additions & 17 deletions
This file was deleted.

examples/next-with-next-i18next-v11/pages/index.js

Lines changed: 0 additions & 73 deletions
This file was deleted.

examples/next-with-next-i18next-v11/pages/second-page.js

Lines changed: 0 additions & 36 deletions
This file was deleted.

examples/next-with-next-i18next-v11/next-i18next.config.js renamed to examples/next-with-next-i18next-v13/next-i18next.config.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const HttpBackend = require('i18next-http-backend/cjs');
2+
const { HMRPlugin } = require('i18next-hmr/plugin');
23

34
module.exports = {
45
// https://www.i18next.com/overview/configuration-options#logging
@@ -13,5 +14,11 @@ module.exports = {
1314
},
1415
}
1516
: {}),
16-
use: typeof window !== 'undefined' ? [HttpBackend] : [],
17+
serializeConfig: false,
18+
use:
19+
process.env.NODE_ENV !== 'production'
20+
? typeof window !== 'undefined'
21+
? [HttpBackend, new HMRPlugin({ client: true })]
22+
: [new HMRPlugin({ server: true })]
23+
: [],
1724
};

examples/next-with-next-i18next-v11/next.config.js renamed to examples/next-with-next-i18next-v13/next.config.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ const path = require('path');
44
module.exports = {
55
i18n,
66
webpack(config, { isServer }) {
7-
if (config.mode === 'development') {
8-
const { I18NextHMRPlugin } = require('i18next-hmr/plugin');
7+
if (!isServer && config.mode === 'development') {
8+
const { I18NextHMRPlugin } = require('i18next-hmr/webpack');
99
config.plugins.push(
1010
new I18NextHMRPlugin({
1111
localesDir: path.resolve(__dirname, 'public/locales'),

examples/next-with-next-i18next-v11/package.json renamed to examples/next-with-next-i18next-v13/package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,16 @@
99
"start": "next start -p ${PORT:=3000}"
1010
},
1111
"dependencies": {
12+
"i18next": "^22.5.0",
1213
"i18next-http-backend": "^1.4.1",
1314
"next": "12.2.2",
14-
"next-i18next": "11.2.2",
15+
"next-i18next": "13.2.2",
1516
"prop-types": "15.8.1",
1617
"react": "18.2.0",
17-
"react-dom": "18.2.0"
18+
"react-dom": "18.2.0",
19+
"react-i18next": "^12.3.1"
1820
},
1921
"devDependencies": {
20-
"i18next-hmr": "^1.8.0"
22+
"i18next-hmr": "^2.0.0"
2123
}
2224
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { appWithTranslation } from 'next-i18next';
2+
import nextI18NextConfig from '../next-i18next.config';
3+
4+
const MyApp = ({ Component, pageProps }) => <Component {...pageProps} />;
5+
6+
// https://github.com/i18next/next-i18next#unserialisable-configs
7+
export default appWithTranslation(MyApp, nextI18NextConfig);
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import Link from 'next/link';
2+
import { useRouter } from 'next/router';
3+
4+
import { useTranslation, Trans } from 'next-i18next';
5+
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
6+
7+
import { Header } from '../components/Header';
8+
import { Footer } from '../components/Footer';
9+
10+
const Homepage = () => {
11+
const router = useRouter();
12+
const { t } = useTranslation('common');
13+
14+
return (
15+
<>
16+
<main>
17+
<Header heading={t('h1')} title={t('title')} />
18+
<div style={{ display: 'inline-flex', width: '90%' }}>
19+
<div style={{ width: '50%' }}>
20+
<h3 style={{ minHeight: 70 }}>{t('blog.optimized.question')}</h3>
21+
<p>
22+
<Trans i18nKey="blog.optimized.answer">
23+
Then you may have a look at{' '}
24+
<a href="https://locize.com/blog/next-i18next/">this blog post</a>.
25+
</Trans>
26+
</p>
27+
<a href="https://locize.com/blog/next-i18next/">
28+
<img
29+
style={{ width: '50%' }}
30+
src="https://locize.com/blog/next-i18next/next-i18next.jpg"
31+
/>
32+
</a>
33+
</div>
34+
<div style={{ width: '50%' }}>
35+
<h3 style={{ minHeight: 70 }}>{t('blog.ssg.question')}</h3>
36+
<p>
37+
<Trans i18nKey="blog.ssg.answer">
38+
Then you may have a look at{' '}
39+
<a href="https://locize.com/blog/next-i18n-static/">this blog post</a>.
40+
</Trans>
41+
</p>
42+
<a href="https://locize.com/blog/next-i18n-static/">
43+
<img
44+
style={{ width: '50%' }}
45+
src="https://locize.com/blog/next-i18n-static/title.jpg"
46+
/>
47+
</a>
48+
</div>
49+
</div>
50+
<hr style={{ marginTop: 20, width: '90%' }} />
51+
<div>
52+
<Link href="/" locale={router.locale === 'en' ? 'de' : 'en'}>
53+
<button>
54+
{t('change-locale', { changeTo: router.locale === 'en' ? 'de' : 'en' })}
55+
</button>
56+
</Link>
57+
<Link href="/second-page">
58+
<button type="button">{t('to-second-page')}</button>
59+
</Link>
60+
</div>
61+
</main>
62+
<Footer />
63+
</>
64+
);
65+
};
66+
67+
export const getStaticProps = async ({ locale }) => ({
68+
props: {
69+
...(await serverSideTranslations(locale, ['common', 'footer'])),
70+
},
71+
});
72+
73+
export default Homepage;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import Link from 'next/link';
2+
3+
import { useTranslation } from 'next-i18next';
4+
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
5+
6+
import { Header } from '../components/Header';
7+
import { Footer } from '../components/Footer';
8+
9+
const SecondPage = () => {
10+
const { t } = useTranslation('second-page');
11+
12+
return (
13+
<>
14+
<main>
15+
<Header heading={t('h1')} title={t('title')} />
16+
<Link href="/">
17+
<button type="button">{t('back-to-home')}</button>
18+
</Link>
19+
</main>
20+
<Footer />
21+
</>
22+
);
23+
};
24+
25+
export const getStaticProps = async ({ locale }) => ({
26+
props: {
27+
...(await serverSideTranslations(locale, ['second-page', 'footer'])),
28+
},
29+
});
30+
31+
export default SecondPage;
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
22
"description": "This is a non-page component that requires its own namespace"
3-
}
3+
}

0 commit comments

Comments
 (0)