How to use Knockout observables in i18next?

后端 未结 4 439
抹茶落季
抹茶落季 2021-01-20 00:10

I\'m trying to somehow dynamically use i18next translations together with Knockout.js, but I cant figure out how.

Neither a custom Knockout binding or the i18next jQ

相关标签:
4条回答
  • 2021-01-20 00:16

    KO config:

    var language = ko.observable('');
    
    ko.i18n = function(key) {
      return ko.computed(function() {
        if (language() != null) {
          return i18n.t(key, {
            lng : language()
          });
        } else {
          return "";
        }
      }, key);
    };
    

    view-model:

    var labels = {      
    aboutUs: ko.i18n('app:labels.aboutUs'), 
    contactUsBtn: ko.i18n('app:labels.contactUsBtn') }
    

    view:

    <span data-bind="text: labels.aboutUs">
    
    0 讨论(0)
  • 2021-01-20 00:20

    I'm not very familiar with i18next, so I might be using i18next incorrectly, but you could easily achieve this by creating a bindingHandler. A very simple version of such a bindingHandler, which supports passing optional options, could look like:

    ko.bindingHandlers['translatedText'] = {
        update: function(element, valueAccessor, allBindings){
            var key = ko.unwrap(valueAccessor());
            var options = ko.toJS(allBindings.get('translationOptions') || {});
            var translation = i18n.t(key, options);
            element.innerText = translation;
        }
    };
    

    Given the following i18next initialization code:

    i18n.init({
        lng: "en",
        debug: true,
        resStore: {
            en: {
                translation: {
                    'myTextKey': 'My translated value is "__value__"',
                    'otherTextKey': 'This is just a text which does not use options'
                }
            }
        }
    });
    

    You could use it with the following HTML:

    <input type="text" data-bind="value: input, valueUpdate: 'afterkeydown'"/>
    <div data-bind="translatedText: 'myTextKey', translationOptions: { value: input }"></div>
    <div data-bind="translatedText: 'otherTextKey'"></div>
    

    And the following view model:

    function ViewModel(){
        this.input = ko.observable();
    }
    
    ko.applyBindings(new ViewModel);
    

    I have saved the above code to a jsfiddle which you can find at http://jsfiddle.net/md2Hr/

    0 讨论(0)
  • 2021-01-20 00:28

    I've updated the code to support translating HTML attributes as well.

    Here is a working demo: http://jsfiddle.net/remisture/GxEGe/

    HTML

    <label>HTML/text</label>
    <textarea data-bind="i18n: 'key', i18n-options: {var: input}"></textarea>
    <label>Attribute</label>
    <input type="text" data-bind="i18n: '[placeholder]key', i18n-options: {var: input}" />
    

    JS

    define(['knockout', 'i18next'], function (ko, i18n) {
        ko.bindingHandlers.i18n = {
            update: function (element, valueAccessor, allBindings) {
                var key = ko.unwrap(valueAccessor()),
                    options = ko.toJS(allBindings.get('i18n-options') || {}),
                    translation,
                    parts,
                    attr;
    
                // Check whether we are dealing with attributes
                if (key.indexOf('[') === 0) {
                    parts = key.split(']');
                    key = parts[1];
                    attr = parts[0].substr(1, parts[0].length - 1);
                }
    
                translation = i18n.t(key, options);
    
                if (attr === undefined) {
                    // Check whether the translation contains markup
                    if (translation.match(/<(\w+)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/)) {
                        //noinspection InnerHTMLJS
                        element.innerHTML = translation;
                    } else {
                        // Check whether the translation contains HTML entities
                        if (translation.match(/&(?:[a-z]+|#x?\d+);/gi)) {
                            //noinspection InnerHTMLJS
                            element.innerHTML = translation;
                        } else {
                            // Treat translation as plain text
                            element.innerText = translation;
                        }
                    }
                } else {
                    // Add translation to given attribute
                    element.setAttribute(attr, translation);
                }
            }
        };
    });
    
    0 讨论(0)
  • 2021-01-20 00:28

    Thanks for a great example, @robert.westerlund!

    I slightly modified your example to better fit my needs:

    ko.bindingHandlers['i18n'] = {
            update: function (element, valueAccessor, allBindings) {
                var key = ko.unwrap(valueAccessor()),
                    options = ko.toJS(allBindings.get('i18n-options') || {}),
                    translation = i18next.t(key, options);
    
                // Check whether the translation contains markup
                if (translation.match(/<(\w+)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/)) {
                    element.innerHTML = translation;
                } else {
                    // Check whether the translation contains HTML entities
                    if (translation.match(/&(?:[a-z]+|#x?\d+);/gi)) {
                        element.innerHTML = translation;
                    } else {
                        // Treat translation as plain text
                        element.innerText = translation;
                    }
                }
            }
        };
    
    0 讨论(0)
提交回复
热议问题