中文

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.ts
pages

Configure the internationalization plugin in .umirc.ts:

export default {
locale: {
// Default to using src/locales/zh-CN.ts as a multilingual file
default: 'zh-CN',
baseSeparator: '-',
},
};

For more introductions to configuration, see the Configuring Plugins section.

Now, add your first multilingual content:

// src/locales/zh-CN.ts
export default {
welcome: '欢迎光临 Umi 的世界!',
};
// src/locales/en-US.ts
export 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.ts
export default {
user: {
welcome: '{name},今天也是美好的一天!',
},
};
// src/locales/en-US.ts
export 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 switching
setLocale('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 switching
setLocale('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.ts
export default {
table: {
submit: '提交表单',
},
};
// src/locales/en-US.ts
export 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:

ParameterTypeDescription
nameStringKey of the multilingual
messageObjectMultilingual content object
optionsObjectmomentLocale 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:

ParameterTypeDescription
langStringThe language to switch to
realReloadBooleanWhether to refresh the page when switching, default is true to refresh
import { setLocale } from 'umi';
// Refresh the page when switching
setLocale('en-US');
// Do not refresh the page when switching
setLocale('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 true
baseNavigator: true,
baseSeparator: '-',
default: 'zh-CN',
title: false,
useLocalStorage: true,
},
};

The detailed introduction to the configuration is as follows:

Configuration ItemTypeDefault ValueDescription
antdBooleanfalse; if the project contains antd dependency, then trueantd internationalization support. For more introduction, refer to this document.
baseNavigatorBooleantrueEnable 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
baseSeparatorString-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.
defaultStringzh-CNDefault language of the project. When a specific language is not detected, use the default language set by default.
titleBooleanfalseEnable title internationalization.
useLocalStorageBooleantrueAutomatically 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.ts
export default {
'site.title': 'Umi - 企业级 React 应用开发框架',
'about.title': 'Umi - 关于我',
};
// src/locales/en-US.ts
export default {
'site.title': 'Umi - Enterprise-level React Application Framework',
'about.title': 'Umi - About me',
};

Configure the route content as follows:

// .umirc.ts
export default {
title: 'site.title',
routes: [
{
path: '/',
component: 'Index',
},
{
path: '/about',
component: 'About',
title: 'about.title',
},
],
};

When visiting the page:

  • / route. When the multilingual option is zh-CN, the page title is Umi - 企业级 React 应用开发框架; for en-US, the page title is Umi - Enterprise-level React Application Framework.
  • /about route. When the multilingual option is zh-CN, the page title is Umi - 关于我; for en-US, the page title is Umi - About me.

Runtime Expansion

The internationalization plugin allows you to expand and customize it at runtime.

Custom getLocale

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.ts
import 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.ts
import { 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

Why not use the formatMessage syntax sugar directly?

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.

Last updated:

TABLE OF CONTENTS