Library to integrate react-intl
with Next.js.
$ npm install --save @moxy/next-intl react-intl
ℹ️ If you are running Node.js
< 13.1.0
, you must also installfull-icu
and start node with--icu-data-dir=node_modules/full-icu
or useNODE_ICU_DATA=node_modules/full-icu
.
Please configure i18n
as explained in the official Next.js docs.
// next.config.js
module.exports = {
i18n: {
locales: ['en', 'pt'],
defaultLocale: 'en',
},
};
intl/
en.json
pt.json
The intl/en.json
file contains the messages for the en
locale, like so:
{
"hello": "Hello World"
}
// pages/_app.js
import React from 'react';
import App from 'next/app';
import { withIntlApp } from '@moxy/next-intl';
// The example below dynamically downloads translations from your JSON files,
// but you may load them from external sources, such as a CMS.
// Please note that the result will be cached on the client-side,
// to avoid fetching translations on every page change.
const loadLocale = async (locale) => {
const module = await import(/* webpackChunkName: "intl-messages" */ `../intl/${locale}.json`);
return module.default;
};
export default withIntlApp(loadLocale)(App);
Here's an example if you have a custom app:
import React from 'react';
import { withIntlApp } from '@moxy/next-intl';
import Layout from '../components/layout';
const MyApp = ({ Component, pageProps }) => (
<Layout>
<Component { ...pageProps } />
</Layout>
);
const loadLocale = async (locale) => {
const module = await import(/* webpackChunkName: "intl-messages" */ `../intl/${locale}.json`);
return module.default;
};
export default withIntlApp(loadLocale)(MyApp);
// pages/index.js
import React from 'react';
import { getIntlProps } from '@moxy/next-intl';
const Home = () => (
<main>
<FormattedMessage id="hello" />
</main>
);
export const getStaticProps = async ({ locale }) => ({
props: await getIntlProps(locale),
});
export default Home;
If you already are using getStaticProps
for something else:
export const getServerSideProps = async ({ locale }) => {
const [foo, localeProps] = await Promise.all([
fetchFoo(),
getIntlProps(locale);
]);
return {
foo,
...localeProps,
};
};
ℹ️ If you are using
getServerSideProps()
, then it works the same as the examples that usegetStaticProps()
.
// pages/index.js
import React from 'react';
import { getIntlProps } from '@moxy/next-intl';
import { FormattedMessage } from 'react-intl';
const Home = () => (
<main>
<FormattedMessage id="hello" />
</main>
);
Home.getInitialProps = async ({ locale }) => ({
...await getIntlProps(locale),
});
export default Home;
However, the locale
parameter will be undefined in the getInitialProps()
function above because Next.js doesn't pass it as of now, but there's an open pull-request to resolve it.
To circumvent this, you must override pages/_app.js
like so:
// pages/_app.js
import App from 'next/app';
const MyApp = (props) => <App { ...props } />;
MyApp.getInitialProps = async (appCtx) => {
appCtx.ctx.locale = appCtx.router.locale;
appCtx.ctx.locales = appCtx.router.locales;
appCtx.ctx.defaultLocale = appCtx.router.defaultLocale;
const appProps = await App.getInitialProps(appCtx);
return appProps;
};
export default MyApp;
⚠️ Please note that addinggetInitialProps()
to your App will disable Automatic Static Optimization in pages without Static Generation.
You can use getIntlProps()
once in your pages/_app.js
, like so:
// pages/_app.js
import App from 'next/app';
const MyApp = (props) => <App { ...props } />;
MyApp.getInitialProps = async (appCtx) => {
const [intlProps, appProps] = await Promise.all([
getIntlProps(appCtx.router.locale),
App.getInitialProps(appCtx),
]);
return {
...intlProps,
...appProps,
};
};
export default MyApp;
⚠️ Please note that addinggetInitialProps()
to your App will disable Automatic Static Optimization in pages without Static Generation.
In previous versions of this library, all polyfills were automatically downloaded. This is no longer the case. However, you may load any polyfills and locale data inside the loadLocale()
function.
Here's an example that loads the @formatjs/intl-pluralrules
polyfill.
// _app.js
import { shouldPolyfill as shouldPolyfillPluralRules } from '@formatjs/intl-pluralrules/should-polyfill';
// ...
const loadLocale = async (locale) => {
if (shouldPolyfillPluralRules()) {
await import(/* webpackChunkName: "intl-pluralrules" */ '@formatjs/intl-pluralrules/polyfill');
}
if (Intl.PluralRules.polyfilled) {
switch (locale) {
case 'pt':
await import(/* webpackChunkName: "intl-pluralrules-pt" */ '@formatjs/intl-pluralrules/locale-data/pt')
break;
default:
await import(/* webpackChunkName: "intl-pluralrules-en" */ '@formatjs/intl-pluralrules/locale-data/en')
break
}
}
const module = await import(/* webpackChunkName: "intl-messages" */ `../intl/${locale}.json`);
return module.default;
};
export default withIntlApp(loadLocale)(App);
$ npm t
$ npm t -- --watch # To run watch mode
Released under the MIT License.