What I do in my projects is to use a base viewmodel class to handle text data retrieval from the server.
Each viewmodel has its own Id that matches the resource id used on the server.
Fetched texts are kept in the base viewmodel class in a structure like this:
public texts: KnockoutObservableArray<ITextItem> = ko.observableArray<ITextItem>();
.. where the ITextItem is a structure like this:
interface ITextItem {
id: string;
value: KnockoutObservable<string>;
}
.. fetched with a function like this:
public updateTexts(cultId: string): Q.Promise<any> {
if (this.textsName === '')
this.textsName = this.modelId;
if (this.lastCultureIdFetched != cultId) {
this.lastCultureIdFetched = cultId;
return mm_cspData.cspCtx.getTexts(this.textsName, this.texts);
}
else
return Q.resolve(true);
}
.. specific text fetched from within the viewmodel like this:
public tx(id: string): string {
var match: ITextItem = ko.utils.arrayFirst(this.texts(), item=> item.id === id);
if (!match)
return '';
else
return match.value();
}
So each time a viewmodel is activated or application language is change the updateText method is triggered.
To display the text in my html view I use knockout binding handler to fetch the correct text from the viewmodel. As a rule each viewmodel is exported to a variable named vm so I get away with doing it like this:
ko.getVmTx = (label: any, bindingContext: any) : string => {
if (label === null)
return '';
var vm: any;
var labelId;
if (typeof label === 'object' && typeof label.vm === 'object' && typeof label.vm.tx !== 'function') {
vm = label.vm;
labelId = label.tx;
} else {
vm = bindingContext.$root.vm;
labelId = ko.unwrap(label);
}
if (vm === null || typeof vm === 'undefined' || typeof vm.tx !== 'function') {
console.log('tx binding: unable to find vm for ' + label);
return '';
}
else
return vm.tx(labelId);
}
ko.bindingHandlers.tx = {
update: (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) => {
$(element).text(ko.getVmTx(valueAccessor(),bindingContext));
}
};
ko.bindingHandlers.txVal = {
update: (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) => {
$(element).val(ko.getVmTx(valueAccessor(), bindingContext));
}
};
Finally in my views I use the binding handlers like this:
<span class="app-badge-label-bg" data-bind="tx: 'FinInvAmount'"></span>
This is a massive setup, but once in place, the text handling is taken care of by the base viewmodel class and the only thing you need to do for each viewmodel is to set-up the resource files on the server side and data-bind your labels and values with simple knockout binding.