(轉載)ASP.NET MVC多語言切換
流程圖
1.建立語言檔案
建立App_GlobalResources資料夾
建立Language資料夾
建立資原始檔
這些操作做完後,目錄結構應該是以下這樣的
我們開啟每個資原始檔,在裡面新增一條TiTle資料
我推薦使用ResX Manager來管理語言檔案
比如我已經建立了中文、英語、日語這三個語言檔案,我如果要做修改的話就需要每個檔案輪流修改,使用ResX Manager就能直接同時修改這三個語言檔案,它還提供語言翻譯功能。具體使用方法與此文無關,就不再贅述了。
2.建立一個過濾器
namespace MvcEdu.Filters { public class LocalizationAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { bool isSkipLocalization = filterContext.ActionDescriptor.IsDefined(typeof(WithoutLocalizationAttribute), inherit: true) || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(WithoutLocalizationAttribute), inherit: true); if (!isSkipLocalization) { if (filterContext.RouteData.Values["lang"] != null && !string.IsNullOrWhiteSpace(filterContext.RouteData.Values["lang"].ToString())) { ///從路由資料(url)裡設定語言 var lang = filterContext.RouteData.Values["lang"].ToString(); Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(lang); } else { ///從cookie裡讀取語言設定 var cookie = filterContext.HttpContext.Request.Cookies["Localization.CurrentUICulture"]; var langHeader = string.Empty; if (cookie != null && cookie.Value != "") { ///根據cookie設定語言 langHeader = cookie.Value; Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(langHeader); } else { ///如果讀取cookie失敗則設定預設語言 langHeader = filterContext.HttpContext.Request.UserLanguages[0]; Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(langHeader); } ///把語言值設定到路由值裡 filterContext.RouteData.Values["lang"] = langHeader; //如果url中不包含語言設定則重定向到包含語言值設定的url裡 string ReturnUrl = $"/{filterContext.RouteData.Values["lang"]}/{filterContext.RouteData.Values["controller"]}/{filterContext.RouteData.Values["action"]}"; filterContext.Result = new RedirectResult(ReturnUrl); } /// 把設定儲存進cookie HttpCookie _cookie = new HttpCookie("Localization.CurrentUICulture", Thread.CurrentThread.CurrentUICulture.Name); _cookie.Expires = DateTime.Now.AddYears(1); filterContext.HttpContext.Response.SetCookie(_cookie); base.OnActionExecuting(filterContext); } } } public class WithoutLocalizationAttribute : Attribute { } }
3.配置路由檔案
我這邊因為只有三個語言檔案,所以我對於語言項的輸入做了限制。
namespace MvcEdu { public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Localization", // 路由名稱 url: "{lang}/{controller}/{action}/{id}", // 帶有引數的 URL\ constraints: new { lang = "zh-CN|en-US|ja-JP" }, //限制可輸入的語言項 defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }//引數預設值 ); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } } }
4.修改HomeController.cs檔案,新增修改語言函式
namespace MvcEdu.Controllers
{
[Localization] //HomeController裡的函式都要走Localization過濾器
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Title = Resources.Language.Title;//頁面中的Title值取語言檔案裡的Title值
return View();
}
public ActionResult About()
{
ViewBag.Title = Resources.Language.Title;//頁面中的Title值取語言檔案裡的Title值
ViewBag.Message = "Your application description page.";
return View();
}
public ActionResult Contact()
{
ViewBag.Title = Resources.Language.Title;//頁面中的Title值取語言檔案裡的Title值
ViewBag.Message = "Your contact page.";
return View();
}
[WithoutLocalization]//這個函式不走Localization過濾器
public ActionResult ChangeLanguage(String NewLang, String ReturnUrl)
{
if (!ReturnUrl.EndsWith("/"))
{
ReturnUrl += "/";
}
//use NewLang replace old lang,include input judgment
if (!string.IsNullOrEmpty(ReturnUrl) && ReturnUrl.Length > 3 && ReturnUrl.StartsWith("/") && ReturnUrl.IndexOf("/", 1) > 0 && new string[] { "zh-CN", "en-US","ja-JP" }.Contains(ReturnUrl.Substring(1, ReturnUrl.IndexOf("/", 1) - 1)))
{
ReturnUrl = $"/{NewLang}{ReturnUrl.Substring(ReturnUrl.IndexOf("/", 1))}";
}
else
{
ReturnUrl = $"/{NewLang}{ReturnUrl}";
}
return Redirect(ReturnUrl);//redirect to new url
}
}
}
注意:我在使用vs2015 express for web時,出現了使用Resources.Language時智慧提示沒出現Title的情況,此時去找一下Language.designer.cs裡有無以下程式碼,如果沒有的話則以後新增鍵值對的時候你們都要在此手動新增,或者把Language資料夾建在Controllers的同級目錄下然後再新建資原始檔等操作也能解決該問題。
/// <summary>
/// 查詢類似 標題 的本地化字串。
/// </summary>
internal static string Title {
get {
return ResourceManager.GetString("Title", resourceCulture);
}
}
5.修改母版頁,添加了修改語言的link
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li>@Html.ActionLink("主頁", "Index", "Home")</li>
<li>@Html.ActionLink("關於", "About", "Home")</li>
<li>@Html.ActionLink("聯絡方式", "Contact", "Home")</li>
@*以下是新增的內容*@
<li>@Html.ActionLink("en-US", "ChangeLanguage", "Home",new { NewLang = "en-US",ReturnUrl=Request.RawUrl},new { @class="testclass"})</li>
<li>@Html.ActionLink("zh-CN", "ChangeLanguage", "Home", new { NewLang = "zh-CN", ReturnUrl = Request.RawUrl }, new { @class = "testclass" })</li>
<li>@Html.ActionLink("ja-JP", "ChangeLanguage", "Home", new { NewLang = "ja-JP", ReturnUrl = Request.RawUrl }, new { @class = "testclass" })</li>
</ul>
</div>
6.Views/Home的三個頁面我都加了顯示ViewBag.Title值的程式碼
<h2>@ViewBag.Title.</h2>
7.現在我們來執行,看一下效果
首次登入的時候因為url是localhost:50062/,沒有語言項,所以讀取瀏覽器預設語言“zh-CN”,然後重定向。
以下是點選導航欄的en-US和ja-JP時的情況
8.如果使用者直接輸入http://localhost:50062/Home/Index/
程式會重定向到http://localhost:50062/cookie裡儲存的語言項OR瀏覽器預設語言/Home/Index/
基本做到了和MSDN效果一樣。
---------------------
作者:Cooldiok
來源:CSDN
原文:https://blog.csdn.net/cooldiok/article/details/78313513
版權宣告:本文為博主原創文章,轉載請附上博文連結!
這個博文非常詳細,適合像我這樣的小白使用,我沒有用resx resource manage來管理,使用的是simple resx editor,對於注意中提到的問題也出現了,我是在對resx檔案再進行下儲存就可以正常顯示出最新資料了
resx resourc manager的使用方法
程式碼網址:https://github.com/stefanlenselink/ResXResourceManager
下載網址:https://marketplace.visualstudio.com/items?itemName=TomEnglert.ResXManager
去裡面下載resxmanager擴充套件包,然後雙擊下載下來的ResXManager.VSIX.vsix,應用到vs中,然後開啟vs,在工具中就能看到了。
特別需要注意的問題:ASP.NET MVC多語言處理中請求丟失或引數丟失
網址:https://blog.csdn.net/Cooldiok/article/details/78429294
在專案中碰到了一個問題是:POST請求一個非多語言處理的[WithoutLocalization]函式A,而該函式在執行時又會呼叫其他需要多語言的函式B,這就會導致函式B裡面和多語言有關的值都是預設值,並非是使用者設定的值。
如果去掉[WithoutLocalization]屬性後,則函式A在初次呼叫,經Localization處理後,請求就丟失了。這是因為函式A只接受POST請求,而Localization重定向的請求是GET的,所以定位不到函式A就丟失了。
如果去掉[WithoutLocalization]和[POST]屬性,則重定向後還能找到函式A,但是原本傳入的引數丟失了。
解決辦法:
去掉函式A的[WithoutLocalization]和[POST]屬性,在呼叫函式A的地方使用GET方法,並在URL中加入語言設定,使得Localization不做重定向的步驟。只做圖中紅圈部分的內容,這樣函式B也能正確的進行多語言處理。