Skip to content

Commit

Permalink
feat: upgrade react-intl workflow in example
Browse files Browse the repository at this point in the history
  • Loading branch information
longlho committed Aug 18, 2020
1 parent 2e8068f commit 0d6ffc0
Show file tree
Hide file tree
Showing 24 changed files with 340 additions and 328 deletions.
10 changes: 10 additions & 0 deletions examples/with-react-intl/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"presets": ["next/babel"],
"plugins": [
["babel-plugin-react-intl", {
"ast": true,
"idInterpolationPattern": "[sha512:contenthash:base64:6]",
"extractFromFormatMessageCall": true
}]
]
}
1 change: 1 addition & 0 deletions examples/with-react-intl/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@ yarn-error.log*

# vercel
.vercel
compiled-lang
3 changes: 3 additions & 0 deletions examples/with-react-intl/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"editor.formatOnSave": true
}
24 changes: 4 additions & 20 deletions examples/with-react-intl/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,13 @@ Deploy it to the cloud with [Vercel](https://vercel.com/import?filter=next.js&ut
- React Intl locale data loading via `pages/_document.js` customization
- React Intl integration with [custom App](https://github.com/vercel/next.js#custom-app) component
- `<IntlProvider>` creation with `locale`, `messages` props
- Default message extraction via `babel-plugin-react-intl` integration
- Default message extraction via `@formatjs/cli` integration
- Pre-compile messages into AST with `babel-plugin-react-intl` for performance
- Translation management via build script and customized Next server

### Translation Management

This app stores translations and default strings in the `lang/` dir. This dir has `.messages/` subdir which is where React Intl's Babel plugin outputs the default messages it extracts from the source code. The default messages (`en.json` in this example app) is also generated by the build script. This file can then be sent to a translation service to perform localization for the other locales the app should support.
This app stores translations and default strings in the `lang/` dir. The default messages (`en.json` in this example app) is also generated by the build script. This file can then be sent to a translation service to perform localization for the other locales the app should support.

The translated messages files that exist at `lang/*.json` are only used during production, and are automatically provided to the `<IntlProvider>`. During development the `defaultMessage`s defined in the source code are used. To prepare the example app for localization and production run the build script and start the server in production mode:

Expand All @@ -57,21 +58,4 @@ $ npm start

You can then switch your browser's language preferences to French and refresh the page to see the UI update accordingly.

### FormattedHTMLMessage support (react-intl pre-v4)

Out of the box, this example does not support the use of the `FormattedHTMLMessage` component on the server due to `DOMParser` not being present in a Node environment.
This functionality is deprecated and has been removed as of react-intl 4.0
If you still want to enable this feature, you should install a `DOMParser` implementation (e.g. `xmldom` or `jsdom`) and enable the polyfill in `server.js`:

```js
// Polyfill Node with `DOMParser` required by formatjs.
// See: https://github.com/vercel/next.js/issues/10533
const { DOMParser } = require('xmldom')
global.DOMParser = DOMParser
```

[react intl]: https://github.com/yahoo/react-intl

### Transpile react-intl

According to [react-intl docs](https://github.com/formatjs/react-intl/blob/53f2c826c7b1e50ad37215ce46b5e1c6f5d142cc/docs/Getting-Started.md#esm-build), react-intl and its underlying libraries must be transpiled to support older browsers (eg IE11). This is done by [next-transpile-modules](https://www.npmjs.com/package/next-transpile-modules) in next.config.js.
[react intl]: https://formatjs.io
29 changes: 0 additions & 29 deletions examples/with-react-intl/components/Layout.js

This file was deleted.

28 changes: 28 additions & 0 deletions examples/with-react-intl/components/Layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import * as React from 'react';
import {useIntl} from 'react-intl';
import Head from 'next/head';
import Nav from './Nav';

export default function Layout({title, children}) {
const intl = useIntl();

return (
<div>
<Head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>
{title ||
intl.formatMessage({
defaultMessage: 'React Intl Next.js Example',
})}
</title>
</Head>

<header>
<Nav />
</header>

{children}
</div>
);
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import { FormattedMessage } from 'react-intl'
import Link from 'next/link'
import * as React from 'react';
import {FormattedMessage} from 'react-intl';
import Link from 'next/link';

export default function Nav() {
return (
<nav>
<li>
<Link href="/">
<a>
<FormattedMessage id="nav.home" defaultMessage="Home" />
<FormattedMessage defaultMessage="Home" />
</a>
</Link>
</li>
<li>
<Link href="/about">
<a>
<FormattedMessage id="nav.about" defaultMessage="About" />
<FormattedMessage defaultMessage="About" />
</a>
</Link>
</li>
Expand All @@ -29,5 +30,5 @@ export default function Nav() {
}
`}</style>
</nav>
)
);
}
10 changes: 5 additions & 5 deletions examples/with-react-intl/lang/en.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"title": "React Intl Next.js Example",
"nav.home": "Home",
"nav.about": "About",
"description": "An example app integrating React Intl with Next.js",
"greeting": "Hello, World!"
"11754": "An example app integrating React Intl with Next.js",
"65a8e": "Hello, World!",
"8cf04": "Home",
"8f7f4": "About",
"9c817": "React Intl Next.js Example"
}
10 changes: 5 additions & 5 deletions examples/with-react-intl/lang/fr.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"title": "React Intl Next.js Exemple",
"nav.home": "Accueil",
"nav.about": "À propos de nous",
"description": "Un exemple d'application intégrant React Intl avec Next.js",
"greeting": "Bonjour le monde!"
"11754": "Un exemple d'application intégrant React Intl avec Next.js",
"65a8e": "Bonjour le monde!",
"8cf04": "Accueil",
"8f7f4": "À propos de nous",
"9c817": "React Intl Next.js Exemple"
}
2 changes: 2 additions & 0 deletions examples/with-react-intl/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/// <reference types="next" />
/// <reference types="next/types/global" />
10 changes: 0 additions & 10 deletions examples/with-react-intl/next.config.js

This file was deleted.

31 changes: 21 additions & 10 deletions examples/with-react-intl/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,39 @@
"name": "with-react-intl",
"version": "1.0.0",
"scripts": {
"dev": "node --icu-data-dir=node_modules/full-icu server.js",
"build": "next build && npm run extract",
"extract": "node ./scripts/extract '{pages,components}/*.{js,ts,tsx}'",
"dev": "next dev",
"build": "next build && npm run extract:i18n && npm run compile:i18n",
"extract:i18n": "formatjs extract '{pages,components}/*.{js,ts,tsx}' --format simple --out-file lang/en.json",
"compile:i18n": "formatjs compile-folder --ast --format simple lang/ compiled-lang/",
"start": "NODE_ENV=production node --icu-data-dir=node_modules/full-icu server.js"
},
"dependencies": {
"@formatjs/cli": "1.1.12",
"@formatjs/intl-relativetimeformat": "^2.8.2",
"@formatjs/intl-utils": "^0.6.1",
"@formatjs/cli": "^2.7.3",
"@formatjs/intl-datetimeformat": "^2.4.3",
"@formatjs/intl-getcanonicallocales": "^1.3.2",
"@formatjs/intl-numberformat": "^5.4.1",
"@formatjs/intl-pluralrules": "^3.4.0",
"@formatjs/intl-relativetimeformat": "^7.1.1",
"accepts": "^1.3.7",
"babel-plugin-react-intl": "^8.1.1",
"full-icu": "^1.3.0",
"glob": "^7.1.4",
"intl": "^1.2.5",
"intl-locales-supported": "1.8.4",
"next": "latest",
"react": "^16.9.0",
"react-dom": "^16.9.0",
"react-intl": "^3.1.12"
"react-intl": "^5.6.3"
},
"license": "ISC",
"devDependencies": {
"@types/accepts": "^1.3.5",
"cross-spawn": "7.0.3",
"next-transpile-modules": "^4.0.2"
"prettier": "2.0.5"
},
"prettier": {
"singleQuote": true,
"trailingComma": "es5",
"bracketSpacing": false,
"endOfLine": "lf",
"arrowParens": "avoid"
}
}
36 changes: 0 additions & 36 deletions examples/with-react-intl/pages/_app.js

This file was deleted.

30 changes: 30 additions & 0 deletions examples/with-react-intl/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import * as React from 'react';
import {IntlProvider} from 'react-intl';
import {polyfill} from '../polyfills';
import App from 'next/app';

function MyApp({Component, pageProps, locale, messages}) {
return (
<IntlProvider locale={locale} messages={messages}>
<Component {...pageProps} />
</IntlProvider>
);
}

const getInitialProps: typeof App.getInitialProps = async appContext => {
const {
ctx: {req},
} = appContext;
const locale = (req as any)?.locale ?? 'en';
const messages = (req as any)?.messages ?? {};
const [appProps] = await Promise.all([
polyfill(locale),
App.getInitialProps(appContext),
]);

return {...appProps, locale, messages};
};

MyApp.getInitialProps = getInitialProps;

export default MyApp;
38 changes: 0 additions & 38 deletions examples/with-react-intl/pages/_document.js

This file was deleted.

19 changes: 0 additions & 19 deletions examples/with-react-intl/pages/about.js

This file was deleted.

14 changes: 14 additions & 0 deletions examples/with-react-intl/pages/about.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import * as React from 'react';
import {FormattedRelativeTime, useIntl} from 'react-intl';
import Layout from '../components/Layout';

export default function About() {
const intl = useIntl();
return (
<Layout title={intl.formatMessage({defaultMessage: 'About'})}>
<p>
<FormattedRelativeTime numeric="auto" value={1} unit="hour" />
</p>
</Layout>
);
}
Loading

0 comments on commit 0d6ffc0

Please sign in to comment.