Library to integrate react-intl
with Next.js, making it easy to manage the current locale based on configurable policies.
$ npm install --save @moxy/next-intl react-intl
All the polyfilling will be taken care by this library automatically, so that you don't need to worry about react-intl
runtime requirements.
ℹ️ 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
.
const withNextIntl = require('@moxy/next-intl/plugin');
module.exports = withNextIntl()({ ...nextConfig });
This plugin will make some modifications to your webpack config to circuvent a few issues related to JSDOM, which is a runtime dependency of react-intl
for the server.
intl/
index.js
messages/
en-US.json
The index.js
file should have the following contents:
import { cookiePolicy, acceptLanguagePolicy, defaultPolicy } from '@moxy/next-intl';
export default {
locales: [
{
id: 'en-US',
name: 'English',
loadMessages: async () => {
const module = await import(/* webpackChunkName: "intl-messages/en-US" */ './messages/en-US.json');
return module.default;
},
},
],
policies: [
cookiePolicy(),
acceptLanguagePolicy(),
defaultPolicy('en-US'),
],
};
The messages/en-US.json
file contains the messages for the en-US
locale:
{
"hello": "Hello World"
}
import React from 'react';
import Document, { Html, Head, Main, NextScript } from 'next/document';
import { NextIntlScript } from '@moxy/next-intl';
export default class MyDocument extends Document {
render() {
const { assetPrefix } = this.props.__NEXT_DATA__;
return (
<Html>
<Head />
<body>
<Main />
<NextIntlScript assetPrefix={ assetPrefix } />
<NextScript />
</body>
</Html>
);
}
}
import React from 'react';
import App from 'next/app';
import { withNextIntlSetup } from '@moxy/next-intl';
import nextIntlConfig from '../intl';
export default withNextIntlSetup(nextIntlConfig)(App);
Here's an example if you have a custom app:
import React from 'react';
import App from 'next/app';
import { withNextIntlSetup } from '@moxy/next-intl';
import nextIntlConfig from '../intl';
import Layout from '../components/layout';
class MyApp extends App {
render() {
const { Component, pageProps } = this.props;
return (
<Layout>
<Component { ...pageProps } />
</Layout>
);
}
}
export default withNextIntlSetup(nextIntlConfig)(MyApp);
You may now use react-intl
as you normally would. Moreover, you will receive the current locale in your pages' getInitialProps
static function.
import React, { Component } from 'react';
import { FormattedMessage } from 'react-intl';
export default class Homepage extends Component {
static getInitialProps({ locale }) {
// You may do something with `locale`, such as
// fetching localized information from a CMS
}
render() {
return (
<main>
<FormattedMessage id="hello" />
</main>
);
}
}
<NextIntlScript>
is a React component responsible for conditionally loading Intl polyfills and locale data if necessary.
Please check the setup guide to know how to set it up.
Available props:
Type: string
The configured assetPrefix if any.
An higher-order React component that wraps App
, setting up getInitialProps
and <NextIntlProvider>
automatically.
Please check the setup guide to know how to set it up.
Type: object
ℹ️ You may pass any of the supported
react-intl
's<IntlProvider>
props as well, except forlocale
andmessages
.
Type: Array
The list of supported locales. Each locale is an object with the following shape:
{
id: 'en-US',
name: 'English',
loadMessages: async () => {
// Usually you would use an `import()` statement here,
// but you may load messages from some API such as a CMS.
},
}
Type: Array
The list of policies ordered by preference.
Type: Component
The App component that will be wrapped.
A React component that sets up react-intl
's <IntlProvider>
and automatically manages the current locale based on the configured locales and policies.
⚠️ Please note that you should usewithNextIntlSetup
rather than setting up the provider yourself.
The provider value is an object with the following shape:
const nextIntl = {
// The current locale object
locale,
// The array of supported locales
locales,
// A function to change the locale
// Receives the locale id and returns a promise
changeLocale,
// The react-intl's intl object
intl,
};
A React component that gives you access to the <NextIntlProvider>
value.
This may be useful to render a language selection dropdown:
import { NextIntlConsumer } from '@moxy/next-intl';
const LanguageSelect = () => (
<NextIntlConsumer>
{ ({ locales, locale, changeLocale }) => (
<select
value={ locale.id }
onChange={ (event) => changeLocale(event.target.value) }>
{ locales.map(({ id, name }) => (
<option key={ id } value={ id }>{ name }</option>
)) }
</select>
) }
</NextIntlConsumer>
);
export default LanguageSelect;
The changeLocale(localeId)
function returns a promise, giving you the ability to render a loading while the switch is happening and display an error message if the switch failed.
The hook version of <NextIntlConsumer>
.
Again, this may be useful to render a language selection dropdown:
import { useCallback } from 'react';
import { useNextIntl } from '@moxy/next-intl';
const LanguageSelect = () => {
const { locales, locale, changeLocale } = useNextIntl();
const handleHange = useCallback(
(event) => changeLocale(event.target.value),
[changeLocale],
);
return (
<select value={ locale.id } onChange={ handleHange }>
{ locales.map(({ id, name }) => (
<option key={ id } value={ id }>{ name }</option>
)) }
</select>
);
};
export default LanguageSelect;
The higher order component version of <NextIntlConsumer>
, injecting the <NextIntlProvider>
value as the nextIntl
prop.
import { useCallback } from 'react';
import { useNextIntl } from '@moxy/next-intl';
const LanguageSelect = ({ nextIntl }) => {
const { locales, locale, changeLocale } = nextIntl;
// ...
};
export default LanguageSelect;
A policy that saves the locale preference in a cookie and then matches against the Cookie
request header or document.cookie
.
Type: object
ℹ️ Any options from the
universal-cookie
set method are available as well.
Type: string
Default: locale
The cookie name.
A policy that uses the browser's language by matching against the Accept-Language
request header or navigator.languages
.
A policy the simply returns localeId
to serve as the fallback locale.
Type: string
The locale id to use as the default locale.
You may want to create custom policies for certain use-cases. One common use-case is to have a policy that matches against the locale saved in the account preferences of authenticated users.
A policy is a simple object that must have a match
method and optionally a watch
, act
and save
methods. Please check out the built-in policies to know how to implement one.
$ npm t
$ npm t -- --watch # To run watch mode
Released under the MIT License.