Internationalization
@umi/max
comes with the Internationalization plugin, which easily integrates internationalization features into your Umi application.
Getting Started
The internationalization plugin adopts a convention-based directory structure, where we conventionally import multilingual files in the src/locales
directory.
The naming of multilingual files should follow this specification: <lang><separator><COUNTRY>.(js|json|ts)
. Here, <separator>
is a delimiter, which defaults to -
, and can be configured through the baseSeparator
option.
For example, if you need to introduce support for Simplified Chinese and English in your project, you can create zh-CN.ts
and en-US.ts
files in the src/locales
directory:
src+ locales+ zh-CN.ts+ en-US.tspages
Configure the internationalization plugin in .umirc.ts
:
export default {locale: {// Default to using src/locales/zh-CN.ts as a multilingual filedefault: 'zh-CN',baseSeparator: '-',},};
For more introductions to configuration, see the Configuring Plugins section.
Now, add your first multilingual content:
// src/locales/zh-CN.tsexport default {welcome: '欢迎光临 Umi 的世界!',};
// src/locales/en-US.tsexport default {welcome: "Welcome to Umi's world!",};
You can also use .json
files to store multilingual content:
// src/locales/zh-CN.json{"welcome": "欢迎光临 Umi 的世界!",}// src/locales/en-US.json{"welcome": "Welcome to Umi's world!",}
Everything is ready, now you can use multilingual content in Umi. Leave it to our <FormattedMessage />
component, just pass in the previous welcome
as the value of the parameter id
:
import { FormattedMessage } from 'umi';export default function Page() {return (<div><FormattedMessage id="welcome" /></div>);};
The rendered result is as follows:
<!-- zh-CN --><div>欢迎光临 Umi 的世界!</div><!-- en-US --><div>Welcome to Umi's world!</div>
Using in Component Parameters
In some cases, you need to pass multilingual content as a parameter to a certain component. This can be achieved through the intl
object:
import { Alert } from 'antd';import { useIntl } from 'umi';export default function Page() {const intl = useIntl();const msg = intl.formatMessage({id: 'welcome',});return <Alert message={msg} type="success" />;};
At the bottom layer, the internationalization plugin is encapsulated based on react-intl
and supports all its interfaces. For details, see this document.
In the code above, we used the useIntl()
interface provided by react-intl
to initialize the intl
object and called the formatMessage()
method of this object to format the string.
Formatting Strings
You may want to dynamically interpolate in multilingual translations, so you can write multilingual content like this:
// src/locales/zh-CN.tsexport default {user: {welcome: '{name},今天也是美好的一天!',},};
// src/locales/en-US.tsexport default {user: {welcome: '{name}, what a nice day!',},};
Above, we wrote special syntax {name}
, which allows us to dynamically assign values at runtime:
import { FormattedMessage } from 'umi';export default function Page() {return (<p><FormattedMessage id="user.welcome" values={{ name: '张三' }} /></p>);};
If you wish to achieve this through the intl
object, you can do so by assigning it like this:
import { useIntl } from 'umi';export default function Page() {const intl = useIntl();the msg = intl.formatMessage({id: 'user.welcome',},{name: '张三',},);return <p>{msg}</p>;};
Note that the key-value pair object used for assignment should be passed as the second parameter of the formatMessage()
method.
The rendered result is as follows:
<!-- zh-CN --><p>张三,今天也是美好的一天!</p><!-- en-US --><p>张三, what a nice day!</p>
Switching Languages
The preset <SelectLang />
component can help you quickly add the feature of switching languages to your project, just write it like this:
import { SelectLang } from 'umi';export default function Page() {return <SelectLang />;};
In many cases, you may need to write your own language-switching component. This is where the setLocale()
interface comes in handy:
import { setLocale } from 'umi';// Refresh the page when switchingsetLocale('en-US');
When switching languages using this method, the current page will be refreshed by default. You can set its second parameter to false
to switch languages without refreshing:
// Do not refresh the page when switchingsetLocale('en-US', false);
If you need to switch to the default language, just call this method without passing any parameters:
// If your default language is zh-CN// Then the following call has the same effect as setLocale('zh-CN')setLocale();
Multilingual Default Values
For the sake of page consistency, if Umi does not find the content corresponding to the id
in the current multilingual file, it will directly render the id
as the content on the page.
For example, if the following multilingual files are written:
// src/locales/zh-CN.tsexport default {table: {submit: '提交表单',},};
// src/locales/en-US.tsexport default {// table: {// submit: 'SUBMIT TABLE',// },};
With the following component:
import { Button } from 'antd';import { FormattedMessage } from 'umi';export default function Page() {return (<Button type="primary"><FormattedMessage id="table.submit" /></Button>);};
The rendered result is:
<!-- zh-CN --><button type="primary">提交表单</button><!-- en-US --><button type="primary">table.submit</button>
Especially, if you need to give a default value without completing internationalization adaptation, you can use the defaultMessage
parameter:
import { Button } from 'antd';import { FormattedMessage } from 'umi';export default function Page() {return (<Button type="primary"><FormattedMessage id="table.submit" defaultMessage="SUBMIT TABLE" /></Button>);};
When using the formatMessage()
method, you can do the same:
import { Button } from 'antd';import { useIntl } from 'umi';export default function Page() {const intl = useIntl();the msg = intl.formatMessage({id: 'table.submit',defaultMessage: 'SUBMIT TABLE',});return <Button type="primary">{msg}</Button>;};
Using defaultMessage
to configure default values is not recommended as this will result in writing a large amount of repetitive internationalization content. The best case is that during your internationalization adaptation, ensure that each multilingual file contains all the keys used.
Introduction to Common Interfaces
addLocale
Dynamically Add Language Support
Without creating and writing separate multilingual files, you can dynamically add language support at runtime using the addLocale()
interface. It accepts three parameters:
Parameter | Type | Description |
---|---|---|
name | String | Key of the multilingual |
message | Object | Multilingual content object |
options | Object | momentLocale and antd configurations |
For example, if you want to dynamically introduce Traditional Chinese multilingual support, you can write code as follows:
import { addLocale } from 'umi';import zhTW from 'antd/es/locale/zh_TW';addLocale('zh-TW',{welcome: '歡迎光臨 Umi 的世界!',},{momentLocale: 'zh-tw',antd: zhTW,},);
getAllLocales
Get Multilingual List
You can get an array of all current multilingual options through the getAllLocales()
interface, including multilingual options added through the addLocale()
method. This interface defaults to looking for files in the src/locales
directory that are like zh-CN.(js|json|ts)
and returns the Key of the multilingual.
import { getAllLocales } from 'umi';getAllLocales();// [en-US, zh-CN, ...]
getLocale
Get the Currently Selected Language
You can get the currently selected language through the getLocale()
interface:
import { getLocale } from 'umi';getLocale();// zh-CN
useIntl
Get intl
Object
useIntl()
is likely to be the most commonly used interface in your development. Through it, you can obtain the intl
object, and further execute methods such as formatMessage()
to achieve your diverse needs:
// src/locales/en-US.json{"welcome": "Hi, {name}."}
import { useIntl } from 'umi';const intl = useIntl();const msg = intl.formatMessage({id: 'welcome',},{name: 'Jackson',},);console.log(msg);// Hi, Jackson.
For more uses of the intl
object, please refer to the interface documentation of react-intl
.
setLocale
Set Language
You can dynamically set the current language using the setLocale()
interface through programming. It has two parameters:
Parameter | Type | Description |
---|---|---|
lang | String | The language to switch to |
realReload | Boolean | Whether to refresh the page when switching, default is true to refresh |
import { setLocale } from 'umi';// Refresh the page when switchingsetLocale('en-US');// Do not refresh the page when switchingsetLocale('en-US', false);
Configuring Plugins
You can configure the internationalization plugin in .umirc.ts
. The default values are as follows:
export default {locale: {antd: false, // If `antd` is included in project dependencies, then default to truebaseNavigator: true,baseSeparator: '-',default: 'zh-CN',title: false,useLocalStorage: true,},};
The detailed introduction to the configuration is as follows:
Configuration Item | Type | Default Value | Description |
---|---|---|---|
antd | Boolean | false ; if the project contains antd dependency, then true | antd internationalization support. For more introduction, refer to this document. |
baseNavigator | Boolean | true | Enable browser language detection. By default, the recognition of the current language environment follows: localStorage umi_locale value > browser detection > default set default language > zh-CN |
baseSeparator | String | - | Delimiter between Language and Country. The default is - , resulting in languages and directory files like zh-CN , en-US and sk , etc. If specified as _ , then default defaults to zh_CN . |
default | String | zh-CN | Default language of the project. When a specific language is not detected, use the default language set by default . |
title | Boolean | false | Enable title internationalization. |
useLocalStorage | Boolean | true | Automatically using localStorage to save the currently used language. |
Title Internationalization
Add a title
item in the route configuration to enable internationalization support, automatically converting the page title to the corresponding multilingual content.
For example, the multilingual files are written as follows:
// src/locales/zh-CN.tsexport default {'site.title': 'Umi - 企业级 React 应用开发框架','about.title': 'Umi - 关于我',};
// src/locales/en-US.tsexport default {'site.title': 'Umi - Enterprise-level React Application Framework','about.title': 'Umi - About me',};
Configure the route content as follows:
// .umirc.tsexport default {title: 'site.title',routes: [{path: '/',component: 'Index',},{path: '/about',component: 'About',title: 'about.title',},],};
When visiting the page:
/
route. When the multilingual option iszh-CN
, the page title isUmi - 企业级 React 应用开发框架
; foren-US
, the page title isUmi - Enterprise-level React Application Framework
./about
route. When the multilingual option iszh-CN
, the page title isUmi - 关于我
; foren-US
, the page title isUmi - About me
.
Runtime Expansion
The internationalization plugin allows you to expand and customize it at runtime.
getLocale
Custom You can customize the logic of the getLocale()
method for getting the page language, for example, by recognizing the link ?locale=en-US
, make en-US
the language of the current page:
// src/app.tsimport qs from 'qs';export const locale = {getLocale() {const { search } = window.location;const { locale = 'zh-CN'} = qs.parse(search, { ignoreQueryPrefix: true });return locale;},};
Custom Option Configuration
Umi’s i18n is implemented based on react-intl
.
When you need to configure more react-intl
initialization options, you can configure them in app.ts
. You can refer to the react-intl documentation for specific configuration options
// src/app.tsimport { RuntimeConfig } from '@umijs/max'export const locale: RuntimeConfig['locale'] = {textComponent: 'span',onError: () => {console.log('error handler...');}// locale: string// formats: CustomFormats// messages: Record<string, string> | Record<string, MessageFormatElement[]>// defaultLocale: string// defaultFormats: CustomFormats// timeZone?: string// textComponent?: React.ComponentType | keyof React.ReactHTML// wrapRichTextChunksInFragment?: boolean// defaultRichTextElements?: Record<string, FormatXMLElementFn<React.ReactNode>>// onError(err: string): void}
FAQ
formatMessage
syntax sugar directly?
Why not use the Although formatMessage
is very convenient to use directly, it is detached from React's lifecycle. The most serious issue is that switching languages cannot trigger DOM re-rendering. To solve this problem, we need to refresh the browser when switching languages, which is a poor user experience. Therefore, we recommend using useIntl
or injectIntl
, which can achieve the same functionality.