Knockout.js — это легковесный JavaScript-фреймворк, ориентированный на реализацию паттерна MVVM (Model-View-ViewModel), обеспечивающий двустороннюю привязку данных между моделью и интерфейсом. Одной из ключевых задач при разработке многоязычных веб-приложений является динамическая смена локализации без перезагрузки страницы. В Knockout.js это реализуется с помощью реактивных observable и computed свойств.
Для начала необходимо создать observable, который будет хранить текущую локализацию:
function LocalizationViewModel() {
var self = this;
self.currentLang = ko.observable('en'); // по умолчанию английский
}
Observable currentLang позволяет автоматически обновлять
все зависимости при изменении языка. Это основа для динамической
локализации.
Тексты приложения удобно хранить в виде объекта, где ключи — языковые коды, а значения — словари текстов:
var translations = {
en: {
greeting: "Hello",
farewell: "Goodbye",
welcomeMessage: "Welcome to our website!"
},
ru: {
greeting: "Привет",
farewell: "До свидания",
welcomeMessage: "Добро пожаловать на наш сайт!"
},
es: {
greeting: "Hola",
farewell: "Adiós",
welcomeMessage: "¡Bienvenido a nuestro sitio web!"
}
};
Для удобства добавляется функция получения перевода с проверкой существования ключа:
function getTranslation(lang, key) {
return translations[lang] && translations[lang][key] ? translations[lang][key] : key;
}
Knockout позволяет создавать computed свойства, которые
автоматически пересчитываются при изменении зависимостей. Это идеально
подходит для динамических текстов:
LocalizationViewModel.prototype.greeting = ko.pureComputed(function() {
return getTranslation(this.currentLang(), 'greeting');
}, LocalizationViewModel.prototype);
LocalizationViewModel.prototype.farewell = ko.pureComputed(function() {
return getTranslation(this.currentLang(), 'farewell');
}, LocalizationViewModel.prototype);
LocalizationViewModel.prototype.welcomeMessage = ko.pureComputed(function() {
return getTranslation(this.currentLang(), 'welcomeMessage');
}, LocalizationViewModel.prototype);
При изменении currentLang() все computed
свойства пересчитаются автоматически, обеспечивая мгновенное обновление
интерфейса.
В шаблоне используется стандартная привязка Knockout.js через
data-bind:
<div>
<h1 data-bind="text: greeting"></h1>
<p data-bind="text: welcomeMessage"></p>
<button data-bind="click: function() { currentLang('en') }">English</button>
<button data-bind="click: function() { currentLang('ru') }">Русский</button>
<button data-bind="click: function() { currentLang('es') }">Español</button>
</div>
Каждая кнопка меняет значение currentLang, что
автоматически обновляет тексты на странице.
Для больших проектов полезно использовать вложенные словари и
динамическую генерацию текстов. Можно создавать функцию-обертку для
computed, которая автоматически возвращает нужный текст по
ключу:
LocalizationViewModel.prototype.t = function(key) {
return ko.pureComputed(() => getTranslation(this.currentLang(), key));
};
Применение в HTML:
<p data-bind="text: t('farewell')"></p>
Такой подход снижает дублирование кода и упрощает добавление новых текстов.
Если интерфейс состоит из нескольких компонентов, рекомендуется
хранить currentLang в глобальном объекте ViewModel или
использовать отдельный глобальный observable:
var AppViewModel = {
currentLang: ko.observable('en'),
headerVM: new HeaderViewModel(),
footerVM: new FooterViewModel()
};
В каждом компоненте computed свойства привязываются к
AppViewModel.currentLang, обеспечивая синхронную смену
языка для всех частей интерфейса.
Для динамических приложений можно загружать переводы через AJAX:
function loadTranslations(lang) {
return fetch(`/locales/${lang}.json`)
.then(response => response.json())
.then(data => {
translations[lang] = data;
});
}
После загрузки словаря можно менять currentLang, что
автоматически обновит интерфейс.
loadTranslations('de').then(() => {
viewModel.currentLang('de');
});
ko.pureComputed вместо обычного
computed, чтобы избежать лишних пересчетов.computed свойств, объединяя
несколько ключей в один объект, если тексты часто обновляются
одновременно.function LocalizationViewModel() {
var self = this;
self.currentLang = ko.observable('en');
self.t = function(key) {
return ko.pureComputed(() => getTranslation(self.currentLang(), key));
};
}
var viewModel = new LocalizationViewModel();
ko.applyBindings(viewModel);
Такой подход обеспечивает гибкую, масштабируемую и полностью реактивную систему локализации для веб-приложений на Knockout.js.