简体   繁体   English

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

[英]i18n: Access locale resolution logic in JavaScript

I'm developing and internationalized Single Page App with 2 sorts of localized text: 我正在开发和国际化具有2种本地化文本的Single Page App:

  1. 'static' text, typically text in my HTML templates. “静态”文本,通常是我的HTML模板中的文本。
  2. 'dynamic' text, ie text that lives in the database, typically the description of a product on an e-commerce site. “动态”文本,即驻留在数据库中的文本,通常是电子商务网站上产品的描述。

It's type 2 I'm having trouble with. 我遇到麻烦的是2型。 Say my app officially supports English, French and German, and I get from my database an object such as : 假设我的应用正式支持英语,法语和德语,并且我从数据库中得到一个对象,例如:

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

Now the challenge is to dynamically choose what locale should be chosen for display, given the user's locale and what locales are available in this particular object. 现在的挑战是,根据用户的语言环境以及在此特定对象中可用的语言环境,动态选择应选择哪种语言环境进行显示。

I assume most i18n JavaScript libraries have their own 'locale resolution' logic built-in, but I haven't found one that exposes this logic for the client to use. 我假设大多数i18n JavaScript库都内置了自己的“语言环境解析”逻辑 ,但是我还没有找到一个可以公开此逻辑供客户端使用的逻辑。

Does anyone know a JS library that addresses this, or a good way to solve this issue? 有谁知道解决这个问题的JS库,或者解决此问题的好方法? (if it's AngularJs-compatible, it's even better). (如果它与AngularJs兼容,那就更好了)。

Thanks in advance! 提前致谢!

Disclaimer: I'm a co-author of L20n and one of the developers of l10n.js used in Firefox OS. 免责声明:我是L20n的合著者,也是Firefox OS中使用的l10n.js的开发人员之一。

The term that's commonly used to describe this logic is language negotiation . 通常用于描述此逻辑的术语是语言协商

Most localization libraries should have some sort of language negotiation algorithm included. 大多数本地化库应包含某种语言协商算法。 It can be as basic as trying to match the value of navigator.language with a list of available languages. 它可以像尝试将navigator.language的值与可用语言列表匹配一样基本。 More sophisticated approaches will look at both the language tag ( en in en-US ) and the region tag ( US in en-US ) to try to find a best match. 更复杂的方法将着眼于双方语言标签( enen-US )和区域标志( USen-US ),试图找到一个最佳匹配。

There's a proposal to expose a language negotiation method on the ECMAScript's Intl object, but for now it's not possible to use its internal logic for this purpose. 有人建议在ECMAScript的Intl对象上公开一种语言协商方法 ,但目前无法为此目的使用其内部逻辑。

Getting the list of languages preferred by the user is not as easy as it should be. 获取用户偏爱的语言列表并不容易。 There's navigator.language in most browsers (which is the user's preferred language in Firefox and the language of the browser UI in Chrome ), navigator.userLanguage in Internet Explorer, and the new navigator.languages which is an ordered list of user's preferred languages. navigator.language在大多数浏览器(这是在Firefox用户的首选语言和在Chrome浏览器的用户界面语言 ), navigator.userLanguage在Internet Explorer中,新navigator.languages ,这是用户的首选语言的有序列表。

A server-side alternative is to use the Accept-Language header of the HTTP request which currently is the most reliable way of finding out what the user's preferences are. 服务器端的替代方法是使用HTTP请求的Accept-Language标头,这是目前找出用户首选项的最可靠方法。

Once you have the list of user's preferred languages you can perform the language negotiation. 获得用户的首选语言列表后,即可执行语言协商。

Here are a few examples of libraries that perform language negotiation: 以下是一些进行语言协商的库示例:

For your particular use-case, you can choose to do one of the two following things: 对于您的特定用例,您可以选择执行以下两项操作之一:

  1. perform the language negotiation on the client side using navigator.language || navigator.userLanguage 使用navigator.language || navigator.userLanguage在客户端执行语言协商。 navigator.language || navigator.userLanguage and send a request to the database specifying which language you're interested in, or navigator.language || navigator.userLanguage并将请求发送到数据库,以指定您感兴趣的语言,或者

  2. send the request with the user's Accept-Language header and perform the language negotiation on the server side, and then query the database for the correct translation. 发送带有用户的Accept-Language标头的请求,并在服务器端执行语言协商,然后在数据库中查询正确的翻译。

Both solutions have the benefit of not sending the entire set of translations to the client when only one will be eventually used. 两种解决方案的好处是,当最终只使用一套翻译时,不会将整个翻译集发送给客户端。

For solution #1, given that you're using Angular, I can suggest using L20n 1.0.x which integrates with Angular via the ng-l20n module . 对于解决方案1,鉴于您使用的是Angular,我建议您使用L20n 1.0.x ,它通过ng-l20n模块与Angular集成。 You should be able to use the supportedLocales property to get the negotiated list of languages and use the first element of that list to query the database. 您应该能够使用supportedLocales属性来获取协商的语言列表,并使用该列表的第一个元素来查询数据库。

For solution #2, it all depends on your server-side setup, but if you're using node.js, you can try using one of the following modules: 对于解决方案2,这完全取决于您的服务器端设置,但是如果您使用的是node.js,则可以尝试使用以下模块之一:

Staś Małolepszy's answer is a good reference of the resources available for this problem domain. StaśMałolepszy的答案很好地说明了此问题领域的可用资源。

However, I found that none of these libraries suited my needs (either because their language negotiation logic was too simplistic, or because it wasn't really exposed). 但是,我发现这些库都不符合我的需求(要么是因为它们的语言协商逻辑过于简单,要么是因为它并未真正公开)。

Therefore, I implemented my own custom solution for language negotiation. 因此,我实现了自己的语言协商自定义解决方案。 You can experiment with it in this Plunkr: http://plnkr.co/edit/Cfv49ZcQWJcqwOXYcjtw?p=preview 您可以在此Plunkr中进行实验:http://plnkr.co/edit/Cfv49ZcQWJcqwOXYcjtw?p=preview

The API is a function negotiate(availableLocales, requestedLocales, defaultLocale) , a bit similar to the ECMAScript proposal (with the difference that it returns a single locale value, not a list). 该API是一个函数negotiate(availableLocales, requestedLocales, defaultLocale) ,有点类似于ECMAScript建议 (区别在于它返回的是单个语言环境值,而不是列表)。

// 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

I made the choice to account for 'locale inheritance' (eg en-US is derived from en ) in a non-trivial, opinionated manner . 我选择以一种不平凡的,自以为是的方式考虑“语言环境继承”(例如, en-US源自en )。 I do not claim this is in compliance with whatever standards exist on this topic. 我不声称这符合该主题上存在的任何标准。

It surprised me that I couldn't find any library that provides this sort of functionality. 我找不到提供这种功能的库,这让我感到惊讶。 My best explanation is that i18n of dynamic content isn't needed that often. 我最好的解释是,动态内容的使用并不是经常需要的。

Finally, as to where I get the list of requested languages, as I was in an Single Page App configuration I chose to send an AJAX request to my server, with the content of the Accept-Language header in the response. 最后,关于我在哪里获得请求的语言列表,就像在单页面应用程序配置中一样,我选择将AJAX请求发送到服务器,并在响应中包含Accept-Language标头的内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM