I18n
Midway provides a multi-language component that allows the business to quickly specify different languages and display different texts. It can also be used in HTTP scenarios with request parameters and request first-class methods.
Related information:
Description | |
---|---|
Can be used for standard projects | ✅ |
Can be used for Serverless | ✅ |
Can be used for integration | ✅ |
Contains independent main framework | ❌ |
Contains independent logs | ❌ |
Installation Components
$ npm i @midwayjs/i18n@3 --save
Or reinstall the following dependencies in package.json
.
{
"dependencies": {
"@midwayjs/i18n": "^3.0.0",
// ...
},
}
Use components
Configure the i18n component into the code.
import { Configuration } from '@midwayjs/core';
import * as i18n from '@midwayjs/i18n';
@Configuration({
imports: [
// ...
i18n
]
})
export class MainConfiguration {
//...
}
Use
The component provides MidwayI18nService
services for translating multilingual text.
Using translate
method, pass in different text keywords and parameters to return text content in different languages.
@Controller('/')
export class UserController {
@Inject()
i18nService: MidwayI18nService;
@Get('/')
async index(@Query('username') username: string) {
return this.i18nService.translate('HELLO_MESSAGE', {
args: {
username
},
});
}
}
Configure i18n messages
You can configure it directly in the configuration file, but in most cases, there will be a lot of copy, and sometimes it may even be on remote services. Direct configuration is not realistic at this time.
Generally speaking, we will put the copy into a copy configuration directory, such as src/locales
.
Take the src/locale
directory as an example, let's take an example, the structure is as follows:
.
├── src
│ ├── locales
| │ ├── en_US.json
| │ └── zh_CN.json
│ └── controller
│ └── home.controller.ts
├── package.json
└── tsconfig.json
Here we have created two multilingual files, en_US.json
and zh_CN.json
, representing English and Chinese respectively.
The contents of the documents are as follows:
// src/locales/en_US.json
{
"hello": "Hello {username} ",
"email": "email id ",
"login": "login account ",
"createdAt": "register date"
}
// src/locales/zh_CN.json
{
"hello": "你好 {username}",
"email": "邮箱",
"login": "帐号",
"createdAt": "注册时间"
}
Each line has a string pair, which is a standard JSON format. You can also use js/ts files. The curly brackets are filled with replaceable parameters.
At the same time, you need to add these two JSON to the configuration, and default
property is a default group name.
// src/config/config.default.ts
export default {
// ...
i18n: {
// Put your translated text here
localeTable: {
en_US: {
default: require('../locale/en_US'),
},
zh_CN: {
default: require('../locale/zh_CN'),
}
},
}
}
In this way, it can be used. The output is as follows.
this.i18nService.translate('hello', {
args: {
username: 'harry',
},
locale: 'en_US',
});
// output: Hello harry.
this.i18nService.translate('hello', {
args: {
username: 'harry',
},
locale: 'zh_CN',
});
// output: 你好 harry.
I18n message group
In the following configuration, the multi-language message configured by the user is in the default
group.
// src/config/config.default.ts
export default {
// ...
i18n: {
// Put your translated text here
localeTable: {
en_US: {
default: require('../locale/en_US'),
},
zh_CN: {
default: require('../locale/zh_CN'),
}
},
}
}
The advantage of this is that in other components or business codes, we can also use different group names to add other multilingual texts.
For example:
// src/config/config.default.ts
export default {
// ...
i18n: {
// Put your translated text here
localeTable: {
en_US: {
default: require('../locale/en_US'),
user: require('../locale/user_en_US'),
},
zh_CN: {
default: require('../locale/zh_CN'),
user: require('../locale/user_zh_CN'),
}
},
}
}
In the code, if you call a different group, you need to specify the group parameters.
this.i18nService.translate('user.hello', {
args: {
username: 'harry',
},
group: 'user', // Specify other groups
locale: 'en_US',
});
I18n message format
Parameters can be added to multilingual text, and parameters can have two forms: object
and array
.
The object form is as follows, using curly braces as placeholders.
Hello {username}
When used, passed by configuration, overriding variables by object key.
async index(@Query('username') username: string) {
return this.i18nService.translate('hello', {
args: {
username
},
});
}
The array form is as follows, using numbers as placeholders.
Hello {0}
When used, it is passed through configuration, and the format is in the form of an array, overwriting the numeric variables in the order of the array.
async index(@Query('username') username: string) {
return this.i18nService.translate('hello', {
args: [username]
});
}
Dynamically add i18n message
Sometimes, i18n message may be placed remotely, such as databases, etc., and we can add them dynamically through addLocale
methods.
For example, after the configuration is loaded, before the code is used.
// configuration.ts
// ...
@Configuration({
imports: [
koa
i18n
]
})
export class MainConfiguration {
@Inject()
i18nService: MidwayI18nService;
async onReady() {
this.i18nService.addLocale('zh_TW', {
hello: '你好,{username} 美麗的世界'
});
}
// ...
}
It can be used in code.
async index(@Query('username') username: string) {
return this.i18nService.translate('hello', {
args: [username]
locale: 'zh_TW'
});
}
Specify the current language through parameters
In general, the default language is en_US
, and the user's browser will usually have an Accept-Language
header, so the language will be correctly identified. For example, if you use a Chinese browser to access, Chinese can be displayed normally.
In addition, in HTTP scenarios, you can specify the language through URL Query, Cookie, and Header.
By default, you can specify URL Query,Cookie, and Header.
Priority from top to bottom:
- query: /?locale=en-US
- cookie: locale=zh-TW
- header: Accept-Language: zh-CN,zh;q=0.5
After these parameters are passed, the multilingual data will be automatically saved to the current user's Cookie, and the next request will directly use the set language.
Set language manually
The current language can be set by calling the saveRequestLocale
.
async index() {
// ...
this.i18nService.saveRequestLocale('zh_CN');
}
If the writeCookie
configuration is turned on, the settings will be saved to the current user's Cookie and will be used in the next request.
Language selection priority
These multiple ways of setting up languages have different priorities, from high to low:
-
- The language explicitly specified by the
i18nService.translate
method
- The language explicitly specified by the
-
- Languages set by other decorators, such as
@Validate
the parameters of the decorator (essentially calling thei18nService.translate
method)
- Languages set by other decorators, such as
-
- The current language directly set through the
saveRequestLocale
API
- The current language directly set through the
-
- Language set by browser Query,Cookie and Header (essentially,
saveRequestLocale
is called)
- Language set by browser Query,Cookie and Header (essentially,
-
- default language in i18n component configuration
About Language Case
Inside the code, we will replace all multilingual, fallback rules, written text strings, and returned locale results with the following rules
-
- Use the middle dash instead of the underscore
-
- Use lowercase instead of uppercase
All en_US
changes to en-us
and zh_CN
changes to zh-cn
.
This will safely adapt URL and Cookie.
Used in View
In the Web type framework, we add locals variable support by default, which can be used in the template engine.
Assuming that the template engine we use is Nunjucks, it can be directly referenced to the i18n
method.
The multilingual copy is as follows:
{
"hello": "Hello {username} ",
}
The template is as follows:
<span>{{ i18n('hello', user) }}</span>
Examples are as follows:
// ...
@Controller('/')
export class UserController {
@Inject()
ctx: Context;
@Get('/')
async index() {
await this.ctx.render('index', {
// Note that this is the entire object passed to the template
user: {
username: 'harry',
}
});
}
}
The i18n method is defined as follows:
function i18n(templateName: string, args: Record<string, any>) {
// ...
}
The method name can be modified by configuration.
// src/config/config.default.ts
export default {
// ...
i18n: {
localsField: 'i18n',
}
}
Configuration
Default configuration
In most cases, you only need to add your own multilingual translation localeTable
the configuration.
The following is the complete configuration, which you can find in the configuration definition.
// src/config/config.default.ts
export default {
// ...
i18n: {
// Default language "en_US"
defaultLocale: 'en_US',
// Put your translated text here
localeTable: {
en_US: {
// group name
default: {
// hello: 'hello'
}
},
zh_CN: {
// group name
default: {
// hello: '你好'
}
},
},
// Language mapping, you can use * to match
fallbacks: {
// 'en_* ': ' en_US',
// pt: 'pt-BR',
},
// Whether to write the request parameter to the cookie
writeCookie: true
resolver: {
// url query parameter, default is "locale"
queryField: 'locale',
cookieField: {
// The key in Cookie is "locale" by default"
fieldName: 'locale',
// Cookie domain name, which is empty by default, indicates that the current domain name is valid.
cookieDomain: '',
// The default expiration time of the cookie. Default is one year.
cookieMaxAge: FORMAT.MS.ONE_YEAR
},
},
localsField: 'i18n',
}
}
Write back to Cookie
By default, the multilingual component will write back the current user's language to the Cookie to avoid searching for the next request to improve performance. We can turn off this behavior by configuration.
// src/config/config.default.ts
export default {
// ...
i18n: {
writeCookie: false
}
}
Request resolution configuration
In the HTTP scenario, we provide the ability to specify the current language through parameters.
By default, components are found through the fields below.
locale
field of querylocale
field of cookieAccept-Language
of header
We can modify the fields of the query by configuration.
For example, modify the fields of Query.
// src/config/config.default.ts
export default {
// ...
i18n: {
resolver: {
queryField: 'abc'
},
}
}
You can use /?abc = en-US
to request language changes.
If you do not want to set the language by request, you can turn off the entire resolver
parsing and write-back to Cookie will stop at the same time.
// src/config/config.default.ts
export default {
// ...
I18n: {
resolver: false,
}
}
Common language
Language | Language package name |
---|---|
Arabia | ar_EG |
Armenia | hy_AM |
Bulgarian | bg_BG |
Catalan | ca_ES |
Czech | cs_CZ |
Danish | da_DK |
German | de_DE |
Greek | el_GR |
English | en_GB |
English (American) | en_US |
Spanish | es_ES |
Estonian | et_EE |
Persian | Fa_IR |
Finnish | fi_FI |
French (Belgium) | fr_BE |
French | fr_FR |
Hebrew | He_IL |
Hindi | Hi_IN |
Croatian | hr_HR |
Hungary | Hu_HU |
Icelandic | is_IS |
Indonesian | id_ID |
Italian | it_IT |
Japanese | ja_JP |
Georgian | Ka_GE |
Kannada | Kn_IN |
Korean/Korean | ko_KR |
Kurdish | ku_IQ |
Latvian | lv_LV |
Malay | Ms_MY |
Mongolian | mn_MN |
Norway | nb_NO |
Nepali | ne_NP |
Dutch (Belgium) | nl_BE |
Dutch | nl_NL |
Polish | pl_PL |
Portuguese (Brazil) | pt_BR |
Portuguese | pt_PT |
Slovak | sk_SK |
Serbia | sr_RS |
Slovenia | sl_SI |
Swedish | sv_SE |
Tamil | TA_IN |
Thai | th_TH |
Turkish | tr_TR |
Romanian | RO_RO |
Russian | ru_RU |
Ukrainian | uk_UA |
Vietnamese | vi_VN |
Simplified Chinese | zh_CN |
Traditional Chinese | zh_TW |
Common problem
1. The test configuration global language does not take effect
In general scenarios, you don't need to configure the global language, because browser access will automatically bring language information. For example, a Chinese browser will automatically return Chinese, and an English browser will automatically return English.
If you specifically wish to test the effects of global settings, be sure to do the following:
-
- If you are using a browser, please clear the page cookie before visiting again, because the cookie will record the last user's language information.
-
- If you are using tools such as Postman, please do not bring cookies and language-related Header, Query and other fields.
2. The language returned by the test is unexpected
Please use a browser to test, not Postman.
Since the Postman request does not carry a header related to the browser language, the server cannot automatically determine the language.
If you must use Postman, please refer to the browser request and add the Accept-Language
Header.