Knockout.js — это библиотека для построения динамических пользовательских интерфейсов с применением паттерна MVVM. Одним из важных аспектов современных веб-приложений является возможность поддержки нескольких языков (i18n). В Knockout.js это достигается за счёт сочетания observables и сторонних библиотек для локализации.
В традиционном подходе статические строки хранятся в отдельных ресурсных файлах в формате JSON или JavaScript-объектов. Для Knockout.js структура может выглядеть следующим образом:
const resources = {
en: {
greeting: "Hello",
farewell: "Goodbye",
dateFormat: "MM/DD/YYYY"
},
ru: {
greeting: "Привет",
farewell: "До свидания",
dateFormat: "DD.MM.YYYY"
}
};
Главная идея — сделать текущий язык observable, чтобы все привязанные элементы автоматически обновлялись при смене языка:
function ViewModel() {
this.currentLang = ko.observable('en');
this.t = (key) => {
return resources[this.currentLang()][key] || key;
};
}
Текстовые значения можно привязывать к HTML-элементам с
использованием стандартного text binding:
<div data-bind="text: t('greeting')"></div>
<button data-bind="click: () => currentLang('ru')">RU</button>
<button data-bind="click: () => currentLang('en')">EN</button>
Когда currentLang изменяется, функция t
автоматически возвращает строку на выбранном языке, и все элементы с
привязкой обновляются.
Для локализации placeholder, title и других атрибутов используется
binding attr:
<input type="text" data-bind="attr: { placeholder: t('greeting') }" />
Это позволяет менять язык интерфейса без перезагрузки страницы.
Для более сложных сценариев удобно использовать
ko.computed:
this.localizedGreeting = ko.computed(() => {
return this.t('greeting');
});
В этом случае привязка может быть упрощена:
<div data-bind="text: localizedGreeting"></div>
Computed автоматически пересчитывается при изменении
currentLang, обеспечивая реактивность интерфейса.
Для массивов объектов, отображаемых через foreach,
локализация также возможна:
this.items = ko.observableArray([
{ nameKey: 'greeting' },
{ nameKey: 'farewell' }
]);
this.localizedItems = ko.computed(() => {
return this.items().map(item => ({ name: this.t(item.nameKey) }));
});
<ul data-bind="foreach: localizedItems">
<li data-bind="text: name"></li>
</ul>
Knockout.js легко интегрируется с библиотеками вроде i18next или Globalize.js для расширенных возможностей: форматирование дат, чисел, валюты. Пример с i18next:
i18next.init({
lng: 'en',
resources: {
en: { translation: { greeting: "Hello" } },
ru: { translation: { greeting: "Привет" } }
}
});
function ViewModel() {
this.currentLang = ko.observable('en');
this.t = ko.computed(() => i18next.t('greeting'));
this.currentLang.subscribe(lang => i18next.changeLanguage(lang));
}
Для собственных Knockout-компонентов можно передавать функцию
локализации через params:
ko.components.register('greeting-component', {
viewModel: function(params) {
this.text = params.t;
},
template: '<span data-bind="text: text()"></span>'
});
<greeting-component params="t: t"></greeting-component>
Таким образом, компоненты остаются независимыми от конкретного языка,
а реактивность обеспечивается через observable.
observable для текущего языка обеспечивает
автоматическое обновление интерфейса.computed удобен для динамических строк и списков.