Simple solution
As I really don't like it there is possibility of detecting language for i18next from url parameter.
In i18next options You need to add following entry:
detectLngQS: 'lang'
Thanks to it You can set page language using ?lang=en-US
url parameter.
Better (IMHO) Solution
In my applications I used to create localization service module which handles localization features for Durandal. In App/services
I do create localization.ts
file (sorry for TypeScript but I really prefer it over JS) with follwing code:
/// <reference path='../../Scripts/typings/durandal/durandal.d.ts' />
/// <reference path='../../Scripts/typings/i18next/i18next.d.ts' />
//#region Imports
import app = require('durandal/app');
//#endregion
//#region Public Members
export var Languages: KnockoutObservableArray<ILanguage> = ko.observableArray();
export var Init = (callback: (t: (key: string, options?: any) => string) => void) =>
{
var pl: ILanguage =
{
Id: ko.observable('pl'),
Name: ko.observable('Polski'),
Icon: ko.observable('Content/images/pl_flag.png'),
IsActive: ko.observable(true)
};
var en: ILanguage =
{
Id: ko.observable('en'),
Name: ko.observable('English'),
Icon: ko.observable('Content/images/en_flag.png'),
IsActive: ko.observable(false)
};
var de: ILanguage =
{
Id: ko.observable('de'),
Name: ko.observable('German'),
Icon: ko.observable('Content/images/de_flag.png'),
IsActive: ko.observable(false)
};
Languages.push(pl);
Languages.push(en);
Languages.push(de);
var option: I18nextOptions =
{
preload: ['pl', 'en', 'de'],
lng: 'pl',
fallbackLng: 'pl',
ns: 'app',
debug: true
};
$.i18n.init(option, callback);
app.trigger('Localization:Init');
};
export var T = (key: string) =>
{
return $.i18n.t(key);
};
export var Lng = () =>
{
return $.i18n.lng();
};
export var SetLng = (lng: ILanguage) =>
{
for (var l in Languages())
{
var value = Languages()[l];
if (value.Id != lng.Id)
{
value.IsActive(false);
}
else
{
value.IsActive(true);
}
}
$.i18n.setLng(lng.Id());
$('*').i18n();
app.trigger('Localization:SetLng');
};
//#endregion
//#region Local Interfaces
export interface ILanguage
{
Id: KnockoutObservable<string>;
Name: KnockoutObservable<string>;
Icon: KnockoutObservable<string>;
IsActive: KnockoutObservable<boolean>;
}
//#endregion
Init function is called in main.js
file in app.start()
callback :
app.start().then(function () {
toastr.options.positionClass = 'toast-bottom-right';
toastr.options.backgroundpositionClass = 'toast-bottom-right';
viewLocator.useConvention();
localization.Init(function () {
binder.binding = function (obj, view) {
$(view).i18n();
};
app.setRoot('viewmodels/shell', 'entrance');
});
});
It's worth noticing that Init function is good place for some complex localization initialization ( for example getting localization options from database).
The most important for You is SetLng
. Depending on Your architecture and idea it can be invoked in many places but since it's in the module it can be invoked in any other module (just reference by require.js) so it's great. I usually create localization buttons in bootstrap navbar what gives me dynamic language change whenever i want.
Edit
As far I know You can still use i18next for MVC views - just set up i18next bindings. If You want to set language based on authentication probably best option would be to use 18next cookie. In Your login MVC action You need to add something similar to:
var languageCode = GetLanguageCode(username)
var userCookie = new HttpCookie("i18next", languageCode );
userCookie.Expires.AddDays(365);
HttpContext.Response.Cookies.Add(userCookie);
Just make sure that defaults in i18next options are set to English - this language will be selected for anonymous user. After logging in language will be set based on Your logic and choice will be persisted in cookie
Edit 2
It should be only small change in text.js file - probably You should add just two or three lines before 273. line of text.js ( and one helper function)
First we need helper function to get value of given cookie ( document.cookie returns all cookies names and values concatenated so we need to parse it somehow)
function getCookie(cname)
{
var name = cname + "=";
var ca = document.cookie.split(';');
for(var i=0; i<ca.length; i++)
{
var c = ca[i].trim();
if (c.indexOf(name)==0) return c.substring(name.length,c.length);
}
return "";
}
Now You need to modify Your text.js file to set up i18next cookie.
Before 273. line of code:
var cookie = getCookie('i18next');
if ( cookie != '') xhr.setRequestHeader("Cookie", "i18next=" + cookie);