i18n 国际化支持

此功能分为两部分,middleware 层面的支持和模板引擎层面的支持,基于 i18next 实现。

配置

应用配置:

i18n: {
  enable: true, // default false,
  forceLng: undefined, // default undefined, will always use this language if set.
  defaultLng: 'zh-CN', // default zh-CN, the default and fallback language
  cookieKey: 'lng', // default lng, whick cookie key to find when detect lanaguage
  resources: 'locales', // default locales, relative to options.root
  resourceFormat: 'yml', // default yml, can be json
  defaultNS: 'translation', // default translation, the default and fallback namespace
  whitelist: ['zh-CN', 'en-US'], // default undefined, the list of allowed language
},

资源文件:

请以 {resources}/{namespace}/{lng}.{resourceFormat} 格式放置资源文件,例如:

project/locales
├── ns
│   ├── en-US.yml
│   └── zh-CN.yml
└── translation
    ├── en-US.yml
    └── zh-CN.yml

每个文件中都是 k-v 对。

Tips: 如果某个资源文本的 key 和 value 是一样的,为了避免重复书写,可以选择不写整个 k-v 或者使用 null 作为 value 。

语言检测

遵循以下步骤:

  • 判断 forceLng 是否被设置,是就使用 forceLng
  • 判断 cookies[cookieKey] 是否存在,存在就使用
  • headers['Accept-Language'] 按 q 排序后从前到后顺序获取
  • 未取到则使用 defaultLng
  • 如果设置了 whitelist ,将上面步骤中获取的可能语言顺序去 whitelist 中尝试进行模糊匹配
  • 如未设置 whitelist ,将上面步骤中获取的可能语言顺序尝试使用 defaultNS 逐个查找资源是否存在,存在则匹配(不支持模糊匹配)

模糊匹配:en 可匹配到 en 、en-US 、en-UK;en-US 也可匹配到 en 、en-US 、en-UK。原则上是优先全部匹配,否则优先语言再是地区。

使用

注:如果 key 未匹配到语言文本,则会使用 key 本身作为文本。

  • Middleware 中

    在启用 i18n 后,在 koa 上下文 ctx 下会存在两个相关对象。

    • ctx.i18n 包含内容

      {
        t, // 调用 i18n 的方法
        lng, // 当前检测到的语言
        ns, // namespace 数组
        defaultNS, // 默认 namespace
      }
      
    • ctx.lng === ctx.i18n.lng

  • Handlebars helpers

    提供一个 { {i18n key [...index_params] [...key=value] [bundle=namespace]} } 的 helper 。除第一个参数必选,为文本 key 之外;可通过参数传入编号参数,可通过 hash 传入命名参数,可通过 bundle 指定 namespace 。

    { {i18n "Text { {0} } { {1} }" "haha" "hehe"} } -> Text haha hehe
    { {i18n "Text { {p1} } { {p2} }" p1="haha" p2="hehe"} } -> Text haha hehe
    

    后端渲染直接使用即可,前端见下节 。

前端使用

前端需要组合使用两个库来使用后端的 i18n 资源并渲染:@terminus/i18n-frontend@terminus/i18n-handlebars-helpers

使用一个后端 i18n helper 来输出一些必须信息:{ {i18nEnv} }

还要保证一个前提,资源文件可以被前端访问到(例如通过 nginx 代理)。

  • 使用 browserify 或 webpack

    在下面的 js 被加载前,与页面上放置标签:

    <script>
      {
        {
          i18nEnv;
        }
      }
    </script>
    
    require("@terminus/i18n-handlebars-helpers")(Handlebars); // 传入 Handlebars 来注册 helpers
    require("@terminus/i18n-frontend")({
      callback: function () {
        // 把初始化代码放在这个回调里,否则你的前端渲染动作可能无法正确获取资源
        // 因为 i18n-frontend 通过 xhr 异步获取远端资源
      },
      resourceFormat: "yml", // 可选,默认为 yml ,可以为 json
      resourcePath: "/resources", // 可选,默认访问路径为 /resources ,会使用 ${resourcePath}/${ns}/${lng}.${resourceFormat} 去尝试获取资源文件
      yamlImpl: window.jsyaml, // 可选,当 resourceFormat 为 yml 时才需要,如果不填就去寻找 window.jsyaml ,暂时只支持 js-yaml 这个库
      cache: {
        // 可选,以下为默认配置,使用 localStorage 来 cache 资源
        enable: true,
        prefix: "i18next_res_",
        expire: 7 * 24 * 60 * 60 * 1000,
      },
    });
    
  • 直接使用 js

    <script src="http://registry.terminus.io/packages/i18n-helpers/0.1.0/index.js"></script>
    <script src="http://registry.terminus.io/packages/i18n-frontend/0.1.0/browser.js"></script>
    <script>
      {
        {
          i18nEnv;
        }
      }
      i18nIniter({
        callback: function () {
          // 参考上一部分的注释说明
        },
      });
    </script>
    

    第一个 js 资源在被加载执行前,需要确保 window.Handlebars 对象的存在。

    第二个 js 资源在被加载执行后,会创建 window.i18nIniter 方法供接下来的使用。

results matching ""

    No results matching ""