Package Exports
- @moxy/next-intl
- @moxy/next-intl/es/polyfill.browser.js
- @moxy/next-intl/es/react/NextIntlScript.browser.js
- @moxy/next-intl/lib/polyfill.browser.js
- @moxy/next-intl/lib/react/NextIntlScript.browser.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@moxy/next-intl) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
next-intl
Library to integrate react-intl
with Next.js, making it easy to manage the current locale based on configurable policies.
Installation
$ 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
or useNODE_ICU_DATA=node_modules/full-icu
.
Setup
1 Add the plugin to your next.config.js
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.
2. Create a root folder named intl
with the following structure:
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"
}
3. Include <NextIntlScript>
in pages/_document.js
:
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() {
return (
<Html>
<Head />
<body>
<Main />
<NextIntlScript />
<NextScript />
</body>
</Html>
);
}
}
4. Wrap your app with withNextIntlSetup
in pages/_app.js
:
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);
5. Ready!
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>
);
}
}
API
<NextIntlScript>
<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.
withNextIntlSetup(config)(App)
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.
config
Type: object
ℹ️ You may pass any of the supported
react-intl
's<IntlProvider>
props as well, except forlocale
andmessages
.
locales
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.
},
}
policies
Type: Array
The list of policies ordered by preference.
App
Type: Component
The App component that will be wrapped.
<NextIntlProvider>
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 use
withNextIntlSetup
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,
};
<NextIntlConsumer>
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.
useNextIntl()
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 handleChange = useCallback(
(event) => changeLocale(event.target.value),
[changeLocale],
);
return (
<select value={ locale.id } onChange={ handleChange }>
{ locales.map(({ id, name }) => (
<option key={ id } value={ id }>{ name }</option>
)) }
</select>
);
};
export default LanguageSelect;
withNextIntl(Component)
The higher order component version of <NextIntlConsumer>
, injecting the <NextIntlProvider>
value as the nextIntl
prop.
import { useCallback } from 'react';
import { withNextIntl } from '@moxy/next-intl';
const LanguageSelect = ({ nextIntl }) => {
const { locales, locale, changeLocale } = nextIntl;
// ...
};
export default withNextIntl(LanguageSelect);
Policies
cookiePolicy(options?)
A policy that saves the locale preference in a cookie and then matches against the Cookie
request header or document.cookie
.
options
Type: object
ℹ️ Any options from the
universal-cookie
set method are available as well.
name
Type: string
Default: locale
The cookie name.
acceptLanguagePolicy()
A policy that uses the browser's language by matching against the Accept-Language
request header or navigator.languages
.
defaultPolicy(localeId)
A policy the simply returns localeId
to serve as the fallback locale.
localeId
Type: string
The locale id to use as the default locale.
Custom policies
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.
Tests
$ npm t
$ npm t -- --watch # To run watch mode
License
Released under the MIT License.