Skip to content

Commit a85b78b

Browse files
committed
feat: add dir to the document based on locale
Also improve the way locales are declared.
1 parent 8c1597d commit a85b78b

File tree

8 files changed

+65
-5
lines changed

8 files changed

+65
-5
lines changed

docusaurus/docs/what-is-included/internationalization.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ The integration of `react-intl` into Next.js is made with [`@moxy/next-intl`](ht
1717

1818
## Adding a new locale
1919

20-
1. Add the locale to the `next.config.js` file.
20+
1. Add the locale to the `intl/index.js` file.
2121
2. Add the messages file to `intl/<locale>.json`.
2222

2323
## Removing this feature
2424

2525
If you are really sure internationalization is not needed in your project, you'll want to remove all the unnecessary `intl` related code. Be sure to follow these steps in order to clean your project properly:
2626

2727
1. Uninstall `react-intl`, `@moxy/next-intl`.
28-
2. Remove the `intl` folder.
28+
2. Remove the `intl` folder and update the files that were requiring that folder, removing any related localization code: `next.config.js`, `app/App.js` and `document/Document.js`;
2929
3. Search globally for `react-intl` and `@moxy/next-intl` and remove the corresponding code across the project.
3030
4. Update your unit tests if necessary so that they all pass!

intl/index.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
const locales = [
2+
{ tag: 'en-US', label: 'English', dir: 'ltr' },
3+
];
4+
5+
const defaultLocale = 'en-US';
6+
7+
const localesMap = locales.reduce((localesMap, locale) => {
8+
localesMap[locale.tag] = locale;
9+
10+
return localesMap;
11+
}, {});
12+
13+
// eslint-disable-next-line import/no-commonjs
14+
module.exports = {
15+
locales,
16+
localesMap,
17+
defaultLocale,
18+
};

jest.setup.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
import { defaultLocale as mockDefaultLocale } from './intl';
2+
13
// Mock Next.js router so that useRouter hook works.
24
jest.mock('next/router', () => {
35
const router = {
46
pathname: '/',
57
query: {},
68
asPath: '/',
9+
locale: mockDefaultLocale,
710
events: {
811
on: jest.fn(),
912
off: jest.fn(),

next.config.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const withPlugins = require('next-compose-plugins');
77
const withSitemap = require('@moxy/next-sitemaps/plugin');
88
const envVar = require('env-var');
99
const { PHASE_DEVELOPMENT_SERVER, PHASE_PRODUCTION_BUILD } = require('next/constants');
10+
const { locales, defaultLocale } = require('./intl');
1011

1112
const isEnvRequired = (phase) => phase === PHASE_DEVELOPMENT_SERVER || phase === PHASE_PRODUCTION_BUILD;
1213

@@ -85,8 +86,8 @@ module.exports = (phase, params) => {
8586
ignoreDuringBuilds: true,
8687
},
8788
i18n: {
88-
locales: ['en-US'],
89-
defaultLocale: 'en-US',
89+
locales: locales.map(({ tag }) => tag),
90+
defaultLocale,
9091
},
9192
env: {
9293
...nextConfig.env,

pages/_document.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from '../www/document';

www/app/App.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
import React, { useCallback } from 'react';
1+
import React, { useCallback, useEffect } from 'react';
22
import PropTypes from 'prop-types';
33
import Head from 'next/head';
44
import KeyboardOnlyOutlines from '@moxy/react-keyboard-only-outlines';
55
import { withIntlApp } from '@moxy/next-intl';
66
import { LayoutTree } from '@moxy/next-layout';
77
import Seo from '@moxy/next-seo';
8+
import { useRouter } from 'next/router'; // eslint-disable-line no-restricted-imports
89
import { RouterScrollProvider } from '@moxy/next-router-scroll';
10+
import { localesMap } from '../../intl';
911
import { Debug as DebugGrid } from '../shared/react/grid';
1012
import PageSwapper from '../shared/react/page-swapper';
1113
import MainLayout from '../shared/react/main-layout';
@@ -23,9 +25,16 @@ subscribeToRouter();
2325
export const App = ({ Component, pageProps }) => {
2426
useFouc();
2527

28+
const { locale } = useRouter();
2629
const seoData = useSeoData();
2730
const pageKey = usePageKey();
2831

32+
// Update <html dir> attribute on locale change.
33+
useEffect(() => {
34+
document.documentElement.dir = localesMap[locale].dir;
35+
}, [locale]);
36+
37+
// Handler for cookie consents.
2938
const handleCookieConsents = useCallback((cookieConsents) => {
3039
if (cookieConsents.includes('analytics')) {
3140
initGTM();

www/document/Document.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React from 'react';
2+
import Document, { Html, Head, Main, NextScript } from 'next/document';
3+
import { localesMap } from '../../intl';
4+
5+
class MyDocument extends Document {
6+
static async getInitialProps(ctx) {
7+
const initialProps = await Document.getInitialProps(ctx);
8+
9+
return { ...initialProps, locale: ctx.locale };
10+
}
11+
12+
render() {
13+
const dir = localesMap[this.props.locale].dir;
14+
15+
return (
16+
<Html dir={ dir }>
17+
<Head />
18+
<body>
19+
<Main />
20+
<NextScript />
21+
</body>
22+
</Html>
23+
);
24+
}
25+
}
26+
27+
export default MyDocument;

www/document/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from './Document';

0 commit comments

Comments
 (0)