Internationalization

12003

To facilitate the development of multilingual applications, the framework has built-in internationalization (I18n) support, provided by the egg-i18n plugin.

Default Language

The default language is en-US. If we want to change the default language to Simplified Chinese, we can make the following configuration:

// config/config.default.js
exports.i18n = {
  defaultLocale: 'zh-CN',
};

Switching Languages

We can modify the current language of the application through several methods (the changes will be recorded in the locale cookie), and the next request will directly use the set language. The priority from high to low is as follows:

  1. query: /?locale=en-US
  2. cookie: locale=zh-TW
  3. header: Accept-Language: zh-CN,zh;q=0.5

If you need to change the query or cookie parameter names, you can configure it as follows:

// config/config.default.js
exports.i18n = {
  queryField: 'locale',
  cookieField: 'locale',
  // The cookie expires by default after one year; if set to a Number, the unit is ms
  cookieMaxAge: '1y',
};

Writing I18n Multilingual Files

Configuration files for different languages are stored independently, uniformly placed in the config/locale/*.js directory. For example:

- config/locale/
  - en-US.js
  - zh-CN.js
  - zh-TW.js

Settings are effective whether in the application directory, framework, or plugin's config/locale directory. Note that the spelling of the word should be locale, not locals.

For example, you can configure the Chinese language file like this:

// config/locale/zh-CN.js
module.exports = {
  Email: '邮箱',
};

You can also use JSON format for language files:

// config/locale/zh-CN.json
{
  "Email": "邮箱"
}

Getting Multilingual Text

We can use the __ (alias: gettext) function to retrieve multilingual text from the locale folder.

Note: __ consists of two underscores.

Using the multilingual configurations set above as an example:

ctx.__('Email');
// zh-CN => 邮箱
// en-US => Email

If the text contains format functions like %s, %j, etc., you can call it in a manner similar to util.format():

// config/locale/zh-CN.js
module.exports = {
  'Welcome back, %s!': '欢迎回来,%s!',
};

ctx.__('Welcome back, %s!', 'Shawn');
// zh-CN => 欢迎回来,Shawn!
// en-US => Welcome back, Shawn!

It also supports array index placeholder methods, for example:

// config/locale/zh-CN.js
module.exports = {
  'Hello {0}! My name is {1}.': '你好 {0}!我的名字叫 {1}。',
};

ctx.__('Hello {0}! My name is {1}.', ['foo', 'bar']);
// zh-CN => 你好 foo!我的名字叫 bar。
// en-US => Hello foo! My name is bar.

Using in Controller

class HomeController extends Controller {
  async index() {
    const ctx = this.ctx;
    ctx.body = {
      message: ctx.__('Welcome back, %s!', ctx.user.name),
      // Or use gettext, which is an alias for the `__` function
      // message: ctx.gettext('Welcome back', ctx.user.name)
      user: ctx.user
    };
  }
}

Using in View

Assuming the template engine we are using is Nunjucks.

<li>{{ __('Email') }}:{{ user.email }}</li>
<li>{{ __('Welcome back, %s!', user.name) }}</li>
<li>{{ __('Hello {0}! My name is {1}.', ['foo', 'bar']) }}</li>