Knockback.js uses a convention of storing your custom Locale Manager in 'kb.locale_manager' so that it can be globally used to localize aspects of your application (please see the Custom Locale Manager tutorial for usage examples).
The kb.LocalizedObservable watches the 'kb.locale_manager' instance for changes and updates itself accordingly.
warning This is one of the few cases where you are likely to derive from a Knockback class and where you need to know about observable returned. Basically, when you derive your own type of kb.LocalizedObservable, you need to return the wrapped observable rather than the instance itself from the constructor usingkb.utils.wrappedObservable
We'll use the following Locale Manager for these examples:
class LocaleManager constructor: (locale_identifier, @translations_by_locale) -> @current_locale = ko.observable(locale_identifier) get: (string_id) -> return '(no translation)' unless @translations_by_locale[@current_locale()] return '(no translation)' unless @translations_by_locale[@current_locale()].hasOwnProperty(string_id) return @translations_by_locale[@current_locale()][string_id] getLocale: -> return @current_locale() setLocale: (locale_identifier) -> @current_locale(locale_identifier) @trigger('change', @) _.extend(LocaleManager.prototype, Backbone.Events) kb.locale_manager = new LocaleManager('en-GB', { 'en-GB': body: 'I ought to localize this sentence.' 'fr-FR': body: 'J\'ai besoin de localiser cette phrase.' })
var LocaleManager = function(locale_identifier, translations_by_locale) { this.translations_by_locale = translations_by_locale; this.current_locale = ko.observable(locale_identifier); this.get = function(string_id) { if (!this.translations_by_locale[this.current_locale()]) { return '(no translation)'; } if (!this.translations_by_locale[this.current_locale()].hasOwnProperty(string_id)) { return '(no translation)'; } return this.translations_by_locale[this.current_locale()][string_id]; }; this.getLocale = function() { return this.current_locale(); }; this.setLocale = function(locale_identifier) { this.current_locale(locale_identifier); return this.trigger('change', this); }; }; _.extend(LocaleManager.prototype, Backbone.Events); kb.locale_manager = new LocaleManager('en-GB', { 'en-GB': { body: 'I ought to localize this sentence.' }, 'fr-FR': { body: 'J\'ai besoin de localiser cette phrase.' } });
If you want to simply localize some read-only text based on a nested string id, you typically use a ko.Observable to access the attribute with the string id and use a localizer that simply looks up the string in the kb.locale_manager.
LocalizedStringLocalizer = kb.LocalizedObservable.extend({ constructor: (value, options, view_model) -> kb.LocalizedObservable.prototype.constructor.apply(this, arguments) return kb.utils.wrappedObservable(@) read: (string_id) -> return if (string_id) then kb.locale_manager.get(string_id) else '' })
// Generated by CoffeeScript 1.3.3 var LocalizedStringLocalizer; LocalizedStringLocalizer = kb.LocalizedObservable.extend({ constructor: function(value, options, view_model) { kb.LocalizedObservable.prototype.constructor.apply(this, arguments); return kb.utils.wrappedObservable(this); }, read: function(string_id) { if (string_id) { return kb.locale_manager.get(string_id); } else { return ''; } } });
<div id='kblo_read_only'> <p data-bind="text: main_text"></p> <p> <span>Current Locale: <span> <span data-bind="text: kb.locale_manager.getLocale()"><span> </p> <button data-bind="click: toggleLocale">Toggle Locale</button> </div>
texts = new Backbone.Model({main_text_id: 'body'}) view_model = main_text: kb.observable(texts, {key: 'main_text_id', localizer: LocalizedStringLocalizer}) toggleLocale: -> if (kb.locale_manager.getLocale() == 'en-GB') kb.locale_manager.setLocale('fr-FR') else kb.locale_manager.setLocale('en-GB') ko.applyBindings(view_model, $('#kblo_read_only')[0])
// Generated by CoffeeScript 1.3.3 var texts, view_model; texts = new Backbone.Model({ main_text_id: 'body' }); view_model = { main_text: kb.observable(texts, { key: 'main_text_id', localizer: LocalizedStringLocalizer }), toggleLocale: function() { if (kb.locale_manager.getLocale() === 'en-GB') { return kb.locale_manager.setLocale('fr-FR'); } else { return kb.locale_manager.setLocale('en-GB'); } } }; ko.applyBindings(view_model, $('#kblo_read_only')[0]);
Current Locale:
If you want to simply label an input field, you can use a read-only localized observable that only looks up the string in the kb.locale_manager.
LongDateLocalizer = kb.LocalizedObservable.extend({ constructor: (value, options, view_model) -> kb.LocalizedObservable.prototype.constructor.apply(this, arguments) return kb.utils.wrappedObservable(@) read: (value) -> return Globalize.format(value, 'dd MMMM yyyy', kb.locale_manager.getLocale()) write: (localized_string, value) -> new_value = Globalize.parseDate(localized_string, 'dd MMMM yyyy', kb.locale_manager.getLocale()) # reset if invalid if not (new_value and _.isDate(new_value)) return kb.utils.wrappedObservable(this).resetToCurrent() value.setTime(new_value.valueOf()) })
// Generated by CoffeeScript 1.3.3 var LongDateLocalizer; LongDateLocalizer = kb.LocalizedObservable.extend({ constructor: function(value, options, view_model) { kb.LocalizedObservable.prototype.constructor.apply(this, arguments); return kb.utils.wrappedObservable(this); }, read: function(value) { return Globalize.format(value, 'dd MMMM yyyy', kb.locale_manager.getLocale()); }, write: function(localized_string, value) { var new_value; new_value = Globalize.parseDate(localized_string, 'dd MMMM yyyy', kb.locale_manager.getLocale()); if (!(new_value && _.isDate(new_value))) { return kb.utils.wrappedObservable(this).resetToCurrent(); } return value.setTime(new_value.valueOf()); } });
<div id='kblo_read_write'> <input data-bind="value: date"/> <p> <span>Current Locale: <span> <span data-bind="text: kb.locale_manager.getLocale()"><span> </p> <button data-bind="click: toggleLocale">Toggle Locale</button> </div>
model = new Backbone.Model({date: new Date()}) view_model = date: kb.observable(model, {key: 'date', localizer: LongDateLocalizer}) toggleLocale: -> if (kb.locale_manager.getLocale() == 'en-GB') kb.locale_manager.setLocale('fr-FR') else kb.locale_manager.setLocale('en-GB') ko.applyBindings(view_model, $('#kblo_read_write')[0])
// Generated by CoffeeScript 1.3.3 var model, view_model; model = new Backbone.Model({ date: new Date() }); view_model = { date: kb.observable(model, { key: 'date', localizer: LongDateLocalizer }), toggleLocale: function() { if (kb.locale_manager.getLocale() === 'en-GB') { return kb.locale_manager.setLocale('fr-FR'); } else { return kb.locale_manager.setLocale('en-GB'); } } }; ko.applyBindings(view_model, $('#kblo_read_write')[0]);
Current Locale: