2014-01-14 76 views
1

我正在開發與杜蘭達SPA。我依賴於ASP.NET Web API和ASP.NET MVC。 對於本地化的需求,我已經在durandal v2 doc中設置了i18n模塊,即使我一直想要管理服務器端的大部分全球化,這也可以正常工作:我的意思是在ASP中。淨mvc(* .cshtml)的意見。durandal本地化(服務器視圖)

但是,隨着視圖按需加載,我怎樣才能以某種方式自定義視圖(html/cshtml)異步加載調用,以便請求視圖的特定語言(如給出url參數以指定實例視圖語言)。

我已經開始尋找視圖(html/cshtml)加載的位置,但到目前爲止還沒有找到位置)。你能給我任何解釋/訣竅嗎? (這是由杜蘭達完成,由ko,要求..?)

謝謝!

編輯:我開始探索杜蘭代碼。我只是明白,即使通過text.js插件加載views/html文件,它仍然使用require.js。所以現在我的目標是鉤住這個過程,以便將所請求的頁面文化添加到調用中(url請求參數或http標頭)。 有關如何做到這一點的最簡單方法的任何想法? (通過剛剛在viewEngine.js黑客convertViewIdToRequirePath寫text.js相當於或可能?)

回答

1

簡單的解決方案

正如我真的不喜歡它,有檢測語言i18next可能性來自url參數。 在i18next選擇您需要添加下面的條目:

detectLngQS: 'lang' 

多虧了它,您可以設置使用?lang=en-US URL參數頁面的語言。

更好的(恕我直言)解決方案

在我的應用我用來創建處理本地化功能的迪朗達爾本地化服務模塊。在App/services我確實創造localization.ts文件(打字稿抱歉,但我真的很喜歡它在JS)與follwing代碼:

/// <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()回調:

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引用),所以它很棒。我通常在自舉導航欄中創建本地化按鈕,這使得我在任何時候都可以隨時更改語言動態

編輯

據我知道,你仍然可以使用i18next MVC的意見 - 剛剛成立i18next綁定。如果你想基於身份驗證設置語言,最好的選擇可能是使用18下一個cookie。在您的登錄MVC動作你需要類似的東西添加到:

var languageCode = GetLanguageCode(username) 
var userCookie = new HttpCookie("i18next", languageCode); 
userCookie.Expires.AddDays(365); 
HttpContext.Response.Cookies.Add(userCookie); 

只要確保在i18next選項默認設置爲英語 - 這種語言會被選擇爲匿名用戶。在語言登錄後,將事先設定你的邏輯和選擇將瀏覽器來保留

編輯2

應該只在text.js文件小的變化 - 也許你應該補充一點,兩個或三個行號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); 
+0

謝謝基耶斯洛夫,但我已經有一個相當的國際化設置。我的問題不是關於國際化。我希望通過MVC視圖找到一種通過durandal按需提供本地化的方法。基本上,我關於本地化的應用場景很簡單:以前你是匿名的時候使用英文,並且一旦登錄就選擇語言。 – Christophe

+0

@Christophe,隨時再次 –

+0

感謝檢查我的編輯爲試圖解決我的問題,但我的登錄過程通過,Ajax調用管理,而不是由表單提交... – Christophe

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的幫助!

0

一個原因,爲什麼我不能導入i18next是因爲i18next.d.ts文件沒有

declare module "i18next" { 
    export = i18next; 
} 

末。 它只有

declare var i18next: I18nextStatic; 

所以,當我試圖使用import i18next = require('i18next');我的打字稿要導入的文件將BARF:

無法加載外部模塊 模塊不能別名非模塊式

我不知道爲什麼Definitely Typed項目以這種方式組成d.ts文件。 我不知道申報模塊是否是一個好的解決方案。

有人請幫助,我也貼一個問題在這裏:

Cannot load external module when trying to import i18next in TypeScript