14

How do you handle localization using knockout.js?

It seems like knockback.js has a nice looking utilities to handle localization, and I'm wondering if there are any third party libraries which can be used with knockout.js to handle localization without having to actually switch to knocback.js to get those features (since I don't really need the backbone models or routing for this simple app). Something as simple to use as the Mapping plugin would be ideal.

Thanks!!

Bob Smith
  • 791
  • 2
  • 9
  • 19
  • If you are getting your localized strings from the server, then all you have to do is use the `text` binding to set all the strings up. What specific problem are you having? – Kyeotic Jul 11 '12 at 16:46
  • @Tyrsius, Well, I'm not getting localized strings from the server so that could be one solution. I'll have to think about a good way to set that up. What I'm specifically looking for in regards to this question though is a way to handle toggling localized strings in knockout.js similar to how they are handled by knockback.js (for example, [see](http://kmalakoff.github.com/knockback/tutorial_locale_manager.html).) so that I wouldn't have to modify the server side API. Thanks for your suggestion! – Bob Smith Jul 11 '12 at 18:07
  • Man you just linked to a tutorial that answers your own question. Knockback *uses* knockout. *read the link*. – Kyeotic Jul 11 '12 at 22:38
  • While Knockback.js uses knockout.js (and backbone.js) my reading of the link was that the localization features of knockback.js, both the localization manager and the localized observables, are additions and not a part of knockout.js, correct? – Bob Smith Jul 12 '12 at 16:39
  • well yes. Sort of. I'm not too familiar with knockback, but it looks like a thin wrapper around knockout's binding to make the localization step easier. But really, knockout is easily capable of this, as my answer demonstrates. – Kyeotic Jul 12 '12 at 17:33

3 Answers3

12

Here is a simple fiddle demonstrating Knockout switching between two languages. Its very rudimentary, but your question lacks any specifics to give you any more complex.

HTML

<div data-bind="with: selectedLanguage">
    <h1 data-bind="text: header"></h1>
    <h2 data-bind="text: subHeader"></h2>
    <p data-bind="text: body"></p>
</div>
<select data-bind="options: languages, optionsText: 'name', value: selectedLanguage"></select>​

ViewModels

var Language = function(language) {
    this.name = ko.observable(language.name);
    this.header = ko.observable(language.header);
    this.subHeader = ko.observable(language.subHeader);
    this.body = ko.observable(language.body);
};

var ViewModel = function(data) {
    var self = this;
    self.languages = ko.observableArray(
    ko.utils.arrayMap(data, function(i) {
        return new Language(i);
    }));
    self.selectedLanguage = ko.observable();
};
Kyeotic
  • 19,697
  • 10
  • 71
  • 128
  • 6
    There is no need to make each property of Language an observable! If you have many labels it will slow down the page. I edited your fine fiddle: http://jsfiddle.net/runjep/KRS2A/63/ – Rune Jeppesen Sep 23 '13 at 11:38
  • But if they are observable, then you could change the language and the page would update, no? – Neil Barnwell Sep 01 '15 at 09:32
  • @NeilBarnwell please look at the fiddle. Changing the language *does* update the page. – Kyeotic Sep 01 '15 at 16:08
  • In the Language function, just create a loop instead: `for (var key in language) { this[key] = language[key]; }` – Sintyche Apr 01 '16 at 19:17
  • @Sintyche Actually, it would need to be `this[key] = ko.observable(langauage[key])`, but I still don't recommend doing that. First, I often rename properties in constructors, because their source might have different conventions. Second, I may not want all of the properties that the source gave me. – Kyeotic Apr 01 '16 at 19:48
6

I don't think it's necessary to do the mapping, nor use observables for each label.

var ViewModel = function () {  
    this.l = ko.observable(spanish);
    this.chooseenglish = function () {
        this.l(english);
    };
  this.choosespanish = function () {
        this.l(spanish);
    };
};
var spanish = {
    header: "Bienvenidos",    
    body: "Esta es la demostración de idioma"
};
var english = {
    header: "Welcome",
     body: "This is the language demo"
}
    ko.applyBindings(new ViewModel());

In the html code you just need to call the observable and the label name:

<h1 data-bind='text: l().header'></h1> 
<button data-bind='click: chooseenglish'>English</button>
<button data-bind='click:choosespanish'>Spanish</button>
<p data-bind='text: l().body'></p> 

http://jsfiddle.net/runjep/3Lqsx/2094/

Rune Jeppesen
  • 1,121
  • 13
  • 22
3

There is amazing i18next-ko project, which uses i18next under the hood.

Define you translations:

var resourceStore = {
    en: {
      translation: {
        'testTranslation': 'Test translation',
        'testTranslation2': 'Test translation __param__'
      }
    },

    de: {
      translation: {
        'testTranslation': 'Test-Übersetzung',
        'testTranslation2': 'Test-Übersetzung __param__'
      }
    }
  }

Initialize i18next-ko:

i18nextko.init(resourceStore, 'en', ko);

Switch languages at will:

i18nextko.setLanguage('de');

And bind:

data-bind="i18n: 'testTranslation'"

Or:

data-bind="i18n: { key: 'testTranslation2', options: { param: paramObservable } }"
vlp
  • 7,811
  • 2
  • 23
  • 51