本文介绍了教程:基于L20n库的node.js / Polymer i18n解决方案的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

node.js web项目中实现i18n存在一个相当常见的问题。如果您想要问题,问题似乎更糟:

There is a rather usual problem to implement i18n in node.js web project. The problem seems even worse if you want to:


  1. 使用网络组件(例如)

  2. 对服务器端和客户端文件使用单个翻译文件

  3. 翻译一些programmaticaly项目(如动态创建的字符串)

感谢全新的由Mozilla团队开发,这个问题可以很容易地解决。

Thanks to brand-new L20n library developed by Mozilla team this problem can be solved rather easily.

推荐答案

项目结构



首先我创建了一个项目结构,它将我的文件分开保存,按目的分组:

Project structure

First I created a project structure, that would keep my files separatedly, grouped by their purpose:

.
+-- app.js
+-- piblic
|   +-- locales
|       +-- app.ru.l20n
|       +-- app.en.l20n
|
+-- node_models
|   +-- l20n 
|
+-- bower_components
|   +-- Polymer libraries
|
+-- app_modules
|   +-- app-l20n-node
|       +-- index.js
|
+-- app_components
    +-- app-l20n
        +-- app-l20n.html
    +-- app-custom-component
        +-- app-custom-component.html

这个想法很简单: app-l20n- node 用作本地化所有服务器端作业的模块, app-l20n 是用户界面l10n的Polymer组件。

The idea is simple: app-l20n-node is used as module to localize all server-side jobs, app-l20n is a Polymer component for user interface l10n.

运行 npm install l20n --save

当前版本是3.5.1,它有一个小bug。 l20n的主文件是 ./ dist / compat / node / l20n.js 并且它有两个必需的变量,这些变量在代码中的任何地方都没有使用,但可以粉碎你的应用程序启动,因为它们仅在图书馆的Devdependencies中提及。为了避免它,我只是将它们直接注释到库代码中:

Run npm install l20n --save
Current version is 3.5.1 and it has a small bug. Main file of l20n is ./dist/compat/node/l20n.js and it has two required variables, that are not used anywhere in code, but can crush your app on launch, as they are mentioned only in Devdependencies of the library. To avoid it I just commented them right into the library code:

//var string_prototype_startswith = require('string.prototype.startswith');
//var string_prototype_endswith = require('string.prototype.endswith');



翻译文件



我创建了翻译文件在我的 / public / locales / 文件夹中,名称如 app.ru.l20n app .en.l20n 。根据L20n规则,文件的内容如下所示:

Translation files

I created translation files in my /public/locales/ folder, named like app.ru.l20n and app.en.l20n. According to L20n rules, the contents of files look like:

<foo "Foo translation">
<bar "Bar translation">
<register[$variant] {
    infinitive: "Register now!"
}>



Node.js + L20n



现在是时候为L20n创建一个节点模块了。
在我的例子中, app_modules\app-l20n-node\index.js 的代码如下所示:

'use strict';
const L20n = require('l20n');
var path = require('path');

module.exports = function(keys, lang){

    const env = new L20n.Env(L20n.fetchResource);

    // Don't forget nice debug feature of L20n library
    env.addEventListener('*', e => console.log(e));

    // I suppose that I'll always provide locale code for translation, 
    // but if it would not happen, module should use preset 
    var langs = [];
    if(!lang) {   
        // you should define locales here
        langs = [{code: 'ru'}, {code: 'en'}]
    } else {
        langs = [{code: lang}]
    }

    // set context, using path to locale files
    const ctx = env.createContext(langs, 
                    [path.join(__dirname, '../../public/locales/app.{locale}.l20n')]);

    const fv = ctx.formatValues;

    return fv.apply(ctx, keys);
};

现在我们可以在我们的node.js代码中使用此模块并获取按键和区域设置请求的翻译。我使用 express-sessions 而不是硬编码的语言环境,并将用户定义的语言环境存储为会话属性 req.session.locale 。但这一切都取决于项目。

Now we can use this module in our node.js code and get translation, requested by keys and locale. Instead of hard-coded locale I use express-sessions and store user-defined locale as session attribute req.session.locale. But it all depends on project.

var l20n =  require('../../app_modules/app-l20n-node');

l20n(['foo','bar'], 'en')
    .then((t)=>{
        console.log(t); // ["Foo translation", "Bar translation"]
    });



Polymer + L20n



现在我们应该为L20n创建一个Polymer组件。

首先,添加库并链接到翻译文件到你的html < head>

<script src="/node_modules/l20n/dist/compat/web/l20n.js"></script>
<link rel="localization" href="/locales/app.{locale}.l20n">

现在是时候创建一个聚合物组件 app-l20n.html 带有新举动。

Now it's time to create a Polymer component app-l20n.html with a new behavior.

<script>

    /**
     * Create namespace for custom behavior or use existing one.
     */
    window.MB = window.MB || {};

    MB.i18n = {

        /**
         * Use l20n.js to translate certain strings
         * @param component A Polymer component, usually "this.translate(this, props);"
         * @param props An array of keys to translate: strings or arrays.
         */
        translate: function(component, props) {
            var view = document.l10n;
            var promise = view.formatValues.apply(view, props);
            promise.then(function(args){
                for (var i in args){

                    var prop = props[i];

                    // strings with parameters represented by arrays: 
                    // ["string", {param: value}]
                    if (Array.isArray(prop)) {

                        // get property name - usually the same, as translation key
                        // so the object would have properties obj.Foo and obj.Bar
                        var propName = prop[0];

                        // if it is needed to create multiple translations of the same 
                        // string in one component, but with different parameters, 
                        // the best way is to use suffix: 
                        // ["string", {param: value}, "_suffix"]
                        if (prop.length == 3) propName = propName + prop[2];

                        component.set(propName, args[i]);
                    }

                    // common strings
                    else component.set(prop, args[i]);

                }
            });
        }
    };
</script>

不,由于新行为准备就绪,我们可以在我们的自定义Polymer组件中实现它。您可以通过Polymer Behavior以编程方式获得翻译或使用L20n自定义标签属性功能。

No, as the new behavior is ready, we can implement it in our custom Polymer components. You can get translation programmatically by Polymer Behavior or using L20n custom tag attributes feature.

<link rel="import" href="/bower_components/polymer/polymer.html">
<link rel="import" href="/bower_components/gold-email-input/gold-email-input.html">
<link rel="import" href="/bower_components/paper-button/paper-button.html">

<link rel="import" href="/app_components/app-l20n/app-l20n.html">

<dom-module id="app-custom-component">
    <template>
        <gold-email-input
            auto-validate
            required
            name="email"
            value="{{Foo}}"
            label="{{Bar}}">
        </gold-email-input>

        <paper-button onclick="regFormSubmit(event)">
            <iron-icon icon="perm-identity"></iron-icon>
            <span data-l10n-id="Register" data-l10n-args='{"variant": "infinitive"}'></span>
        </paper-button>
    </template>
    <script>
        function regFormSubmit(event){}
        Polymer({
            is: 'app-custom-component',
            behaviors: [
                MB.i18n
            ],
            ready: function(){
                this.$.passwordValidator.validate = this._validatePasswords.bind(this);

                // add your component properties to array. They can be simple like in this example, or
                // more complex, with parameters: ["Some_key", {param: "xxx"}].
                // you can even translate the same string in different properties, using custom suffix:
                // ["Some_key", {param: "yyy"}, "_suffix"] and place it in template with shortcut: {{Some_key_suffix}}
                var translateProps = ["Foo", "Bar"];

                // now translate, using behavior
                this.translate(this, translateProps);
            }
        });
    </script>
</dom-module>

希望这个小教程会有所帮助。

Hope this little tutorial would be helpful.

这篇关于教程:基于L20n库的node.js / Polymer i18n解决方案的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

11-02 17:48