i18n:在 JavaScript 中访问语言环境解析逻辑

i18n: Access locale resolution logic in JavaScript

我正在开发和国际化具有 2 种本地化文本的单页应用程序:

  1. 'static' 文本,通常是我的 HTML 模板中的文本。
  2. 'dynamic' 文本, 即存在于数据库中的文本,通常是电子商务网站上的产品描述。

我遇到问题的是类型 2。假设我的应用程序正式支持英语、法语和德语,并且我从我的数据库中获取了一个对象,例如:

{
  description: {
    'en': "It's an awesome product.",
    'en_UK': "This product is ace.",
    'fr': "C'est un excellent produit."
    // German's missing
  }
}

现在的挑战是,根据用户的区域设置以及此特定对象中可用的区域设置,动态选择应选择显示的区域设置。

我假设大多数 i18n JavaScript 库都有自己的 'locale resolution' 逻辑 内置,但我还没有找到一个公开此逻辑的库要使用的客户端。

有没有人知道解决这个问题的 JS 库,或者解决这个问题的好方法?(如果是 AngularJs-兼容,甚至更好)。

提前致谢!

Disclaimer: I'm a co-author of L20n and one of the developers of l10n.js used in Firefox OS.

通常用于描述此逻辑的术语是语言协商

大多数本地化库都应该包含某种语言协商算法。它可以像尝试将 navigator.language 的值与可用语言列表相匹配一样基本。更复杂的方法将同时查看语言标签(en-US 中的en)和区域标签(en-US 中的US)以尝试找到最佳匹配。

在 ECMAScript 的 Intl object 上有一个 proposal to expose a language negotiation method,但目前还不能将其内部逻辑用于此目的。

获取用户首选语言的列表并不像预期的那样容易。在大多数浏览器中有 navigator.language(在 Firefox 和 language of the browser UI in Chrome 中是用户的首选语言),在 Internet Explorer 中有 navigator.userLanguage,而新的 navigator.languages 是一个有序列表用户的首选语言。

server-side 替代方法是使用 HTTP 请求的 Accept-Language header,这是目前找出用户偏好的最可靠方法。

获得用户首选语言列表后,您可以执行语言协商。

以下是执行语言协商的几个库示例:

对于您的特定 use-case,您可以选择执行以下两项操作之一:

  1. 使用navigator.language || navigator.userLanguage在客户端执行语言协商并向数据库发送请求指定您感兴趣的语言,或者

  2. 用用户的Accept-Languageheader发送请求并在服务器端进行语言协商,然后查询数据库得到正确的翻译。

这两种解决方案的好处是当最终只使用一个时,不会将整套翻译发送给客户。

对于解决方案 #1,鉴于您使用的是 Angular,我建议您使用 L20n 1.0.x which integrates with Angular via the ng-l20n module. You should be able to use the supportedLocales property 获取协商的语言列表,并使用该列表的第一个元素查询数据库.

对于解决方案 #2,这完全取决于您的 server-side 设置,但如果您使用 node.js,您可以尝试使用以下模块之一:

Staś Małolepszy 的 answer 是该问题领域可用资源的很好参考。

然而,我发现这些库中 none 符合我的需要(要么是因为它们的语言协商逻辑过于简单,要么是因为它没有真正公开)。

因此,我实现了自己的语言协商自定义解决方案。您可以在 this Plunkr: http://plnkr.co/edit/Cfv49ZcQWJcqwOXYcjtw?p=preview

中进行试验

API 是一个函数 negotiate(availableLocales, requestedLocales, defaultLocale),有点类似于 ECMAScript proposal (不同之处在于它 returns 是一个单一的语言环境值,而不是一个列表) .

// simple cases
negotiate(["fr"], ["de","fr"], 'en'); // => fr
negotiate(["en"], ["de","en-US","en"], 'en'); // => en

// less natural cases, where the solution is more opinionated
negotiate(["fr-FR"], ["fr"], 'en'); // => fr-FR
negotiate(["en","en-UK","fr"], ["fr-FR"], 'en'); // => fr
negotiate(["fr","de"], ["fr-FR","de"], 'en'); // => fr

我选择以 non-trivial 固执己见的方式解释 'locale inheritance'(例如 en-US 源自 en)。我不声称这符合关于该主题的任何标准。

令我惊讶的是,我找不到任何提供此类功能的库。我最好的解释是动态内容的国际化并不经常需要。

最后,关于我从哪里获得所请求语言的列表,因为我在单页应用程序配置中,我选择向我的服务器发送一个 AJAX 请求,其中包含 Accept-Language header 在响应中。