我正在开发一个带durandal的SPA。我依赖ASP.NET Web API和ASP.NET MVC。 对于本地化的需求,我已经在durandal v2 doc中设置了i18n模块,即使我总是考虑在服务器端管理大部分全球化,这也很好用:我的意思是在ASP.Net中mvc(* .cshtml)视图。
但是,由于视图是按需加载的,我怎么能以某种方式自定义视图(html / cshtml)异步加载调用以请求视图的特定语言(比如给出一个url参数来指定查看语言)。
我已经开始寻找加载视图(html / cshtml)的地方,但到目前为止找不到位置。你能给我任何解释/伎俩吗? (是由durandal完成的,由ko,要求..?)
谢谢!
编辑:我开始探索durandal代码。我只是理解它正在使用require.js甚至是通过text.js插件加载的views / html文件。所以现在我的目标是挂钩该进程,以便将所请求的页面文化添加到调用(url request param或http header)。 有关如何做到这一点的最简单方法吗? (通过写一个text.js等价,或者只是通过在viewEngine.js中黑客攻击convertViewIdToRequirePath?)
答案 0 :(得分:1)
简单解决方案
由于我真的不喜欢它,因此有可能从url参数中检测i18next的语言。 在i18next选项中您需要添加以下条目:
detectLngQS: 'lang'
由此感谢您可以使用?lang=en-US
url参数设置页面语言。
更好(恕我直言)解决方案
在我的应用程序中,我曾经创建了本地化服务模块,用于处理Durandal的本地化功能。在App/services
中,我创建了localization.ts
文件(对于TypeScript感到遗憾,但我真的更喜欢它而不是JS)以及以下代码:
/// <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
在main.js
回调中的app.start()
文件中调用Init函数:
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');
});
});
值得注意的是,Init函数是进行复杂本地化初始化的好地方(例如从数据库中获取本地化选项)。
对你来说最重要的是SetLng
。根据你的架构和想法,它可以在很多地方调用,但由于它在模块中,它可以在任何其他模块中调用(只需要require.js引用),所以它很棒。我通常在bootstrap导航栏中创建本地化按钮,这样可以随时随地改变动态语言。
修改强>
据我所知,您仍然可以将i18next用于MVC视图 - 只需设置i18next绑定即可。如果您想基于身份验证设置语言可能最好的选择是使用18next cookie。在您的登录MVC操作中您需要添加类似于:
的内容var languageCode = GetLanguageCode(username)
var userCookie = new HttpCookie("i18next", languageCode );
userCookie.Expires.AddDays(365);
HttpContext.Response.Cookies.Add(userCookie);
只需确保i18next选项中的默认值设置为英语 - 将为匿名用户选择此语言。登录语言将根据您的逻辑设置,选择将保留在cookie
中修改2
它应该只是text.js文件中的小变化 - 可能你应该在273. line of text.js(以及一个辅助函数)之前添加两行或三行
首先我们需要帮助函数来获取给定cookie的值(document.cookie返回所有连接的cookie名称和值,所以我们需要以某种方式解析它)
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 "";
}
现在您需要修改text.js文件以设置i18next cookie。 在273.代码行之前:
var cookie = getCookie('i18next');
if ( cookie != '') xhr.setRequestHeader("Cookie", "i18next=" + cookie);
答案 1 :(得分:0)
好的,这就是我的表现! (目前我刚刚为所请求的文化添加了一个url参数。)
因此,在客户端,在main.js中(在app.start之前),我重写了viewEngine的“convertViewIdToRequirePath”方法来添加参数:
//overriding the default viewEngine viewId conversion rule to add language parameter
viewEngine.convertViewIdToRequirePath = function (viewId) {
return this.viewPlugin + '!' + viewId + this.viewExtension + '?lang=' + i18n.lng();
};
然后在服务器端,我添加了一个Application_AcquireRequestState方法来管理参数检测,然后设置线程的当前文化。
PS:感谢@Krzysztof的帮助!
答案 2 :(得分:0)
我无法导入i18next的一个原因是因为i18next.d.ts文件没有
declare module "i18next" {
export = i18next;
}
最后。 它只有
declare var i18next: I18nextStatic;
因此,当我尝试使用import i18next = require('i18next');
导入我的TypeScript文件时,它会barf:
无法加载外部模块 模块不能别名为非模块类型
我不知道为什么Definitely Typed项目会以这种方式组成d.ts文件。 而且我不知道声明模块是否是一个好的解决方案。
有人请帮忙,我也在这里发了一个问题:
Cannot load external module when trying to import i18next in TypeScript