我们现在的应用已经有一部分功能Hybrid化了,之前也说过,有客户需要国际版的,我这边需要支持到多语言切换。
当时写了一点代码(http://www.voidcn.com/article/p-hnwxiota-da.html),把中文的东西抓出来,给翻译,所以原生部分在哪个时候已经基本解决了。从中文版切换到英文版,只需要到系统设置里面切换下语言就行。虽然还有一点细节,但是这里就不摊开了。
之前翻译一直没出来,所以,web这边的国际化也就一直挂着。
web这边的国际化有几种方案的,原理都是把文字等东西资源化。
第一种:
就像msdn上的做法一样
原理应该是通过路由来定位给到对应的网页
Global.asax.cs public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "Globalization", // 路由名称 "{lang}/{controller}/{action}/{id}", // 带有参数的 URL new { lang = "zh", controller = "Home", action = "Index", id = UrlParameter.Optional }, // 参数默认值 new { lang = "^[a-zA-Z]{2}(-[a-zA-Z]{2})?$" } //参数约束 ); routes.MapRoute( "Default", // 路由名称 "{controller}/{action}/{id}", // 带有参数的 URL new { controller = "Home", action = "Index", id = UrlParameter.Optional } // 参数默认值 ); }
(代码来自:http://www.tuicool.com/articles/bmIbe2)
这种的好处是,可以有针对性的给页面,官方也是这样用的。不过问题可能就是出在会改变链接上,加了一个前缀,所以之前代码中写了不少绝对路径,例如(/Order/Index)都要改一轮,原生那边也要跟着改一轮,切换语言时也要手动改一轮。
第二种:
通过Accept-Language的第一个语言来确定系统当前优先使用的语言
private string innerGetFirstAcceptLanguageInRequest() { string language = "zh-CN"; if (enbaleAutoSwitchLanguage && Request.UserLanguages != null) { string[] array = Request.UserLanguages;//eg : Accept-Language:zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4 if (array.Length > 0) { string firstLanguage = array[0]; if (!string.IsNullOrWhiteSpace(firstLanguage)) { if (!firstLanguage.StartsWith("zh")) { //firstLanguage : zh zh-cn zh-Hans zh-Hans-CN zh-tw //only support "zh-CN" and "en-US" currently language = "en-US"; } } } } return language; }
(参考资料:http://www.cnblogs.com/haogj/p/3921756.html)
Accept-Language第一个值 在Chrome中可以这样设置
在手机中就是系统语言了。
private void innerUpdateCulture(string language) { //cache lang in cookie,we may use it in js if (Request.Cookies != null) { if (Request.Cookies[cacheCookieName] != null) { HttpCookie lanCookie = Request.Cookies[cacheCookieName]; lanCookie[cacheCookieKey] = language; } else { HttpCookie lanCookie = new HttpCookie(cacheCookieName); lanCookie[cacheCookieKey] = language; Response.Cookies.Add(lanCookie); } } //update culture in C# if (!string.IsNullOrEmpty(language)) { Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(language); Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture(language); } }
(参考资料:http://www.huhailong.cn/article_10.html)
然后C#上的资源就自动转过去了,js上如果需要国际化的信息,就可以从cookie中拿
Tools.isChinese = function() { var arr,reg=new RegExp("(^| )"+"LdLang"+"=([^;]*)(;|$)"); if(arr=document.cookie.match(reg)){ var str = unescape(arr[2]); var array = str.split("; "); for(var i=0;i<array.length;i++){ var arr=array[i].split("="); if("lan"==arr[0]){ return arr[1] == "zh-CN"; } } } return true; };
会写得这么细致,是因为我用的是第二种。
好处就是原生系统切换语言的时候,web上的东西不用做什么处理(基本不用),就能把语言切换过去。地址也不用动(之前有写会跨几个不同版本的那些集团版也不用再来回搞一波)。当然原生那边也不是什么都不用做,它要确保Accept-Language中的值是对的。
接下来就是适配页面了,基本上都是体力活了。
代码都弄进系统了,所以不打算给demo了。这里给下step by step吧 :)
step1、选中项目右键-->“添加”-->“添加ASP.NET文件夹”-->“App_GlobalResources” 选中“App_GlobalResources”右键添加一个资源文件Global.resx
在新建中文和英文的资源:
例如:
这里的命名格式要保持,就是**.en-US.resx **.zh-CN.resx
可以这样使用,举这个例子是为了说明,字符串中的东西,不要用拼接的方式去做,C#中提供了很方便的string.Format。
以前拼接了怎么办?这是债,要还 : )
step2、在controller中新建一个BaseController
using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.Web; using System.Web.Mvc; using System.Threading; namespace MobileWeb.Controllers { /// <summary> /// Refer to: /// http://www.huhailong.cn/article_10.html /// http://www.cnblogs.com/haogj/p/3921756.html /// /// by Yeshen /// 2016.12.13 /// </summary> public class BaseController : Controller { //config.js "Tools.isChinese()" quto this two key private const string cacheCookieName = "LdLang"; private const string cacheCookieKey = "lan"; //enbaleAutoSwitchLanguage default value is "true" //if disable , set this value to "false"; private const bool enbaleAutoSwitchLanguage = true; /* * if any need? protected void OnlyEnglish() { this.innerUpdateLanguage("en-US"); } */ protected void Internationalization() { string language = innerGetFirstAcceptLanguageInRequest(); this.innerUpdateCulture(language); } /////////////inner//////////////////////// private string innerGetFirstAcceptLanguageInRequest() { string language = "zh-CN"; if (enbaleAutoSwitchLanguage && Request.UserLanguages != null) { string[] array = Request.UserLanguages;//eg : Accept-Language:zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4 if (array.Length > 0) { string firstLanguage = array[0]; if (!string.IsNullOrWhiteSpace(firstLanguage)) { if (!firstLanguage.StartsWith("zh")) { //firstLanguage : zh zh-cn zh-Hans zh-Hans-CN zh-tw //only support "zh-CN" and "en-US" currently language = "en-US"; } } } } return language; } private void innerUpdateCulture(string language) { //cache lang in cookie,we may use it in js if (Request.Cookies != null) { if (Request.Cookies[cacheCookieName] != null) { HttpCookie lanCookie = Request.Cookies[cacheCookieName]; lanCookie[cacheCookieKey] = language; } else { HttpCookie lanCookie = new HttpCookie(cacheCookieName); lanCookie[cacheCookieKey] = language; Response.Cookies.Add(lanCookie); } } //update culture in C# if (!string.IsNullOrEmpty(language)) { Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(language); Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture(language); } } } }
然后全部的controller都要继承它,每个方法都要调用Internationalization,例如
step3、找出项目中的全部中文字符,资源化它。
厚脸皮的说,我年初开始写web的时候,虽然web是新手,但是原生那边有一些经验,所以一开始上来都是直接用资源、用string.format去写,所以这一步反而没什么工作量。
如果需要找出来,可以参考我这篇博客(http://www.voidcn.com/article/p-hnwxiota-da.html)
step4、页面细节调整。
替换过后,每个页面都要看看,真会页面错乱,文字溢出的。
中午吃饭的时候,我们几个小伙伴的讨论这个,PC端的小伙伴有个意见:这里应该保留一个配置,如果一定要指定中文版或者英文版,要给指定到。
我虽然是拒绝的,因为现在产品SAAS化,不可能在针对某个酒店给配置了。然而考虑到我就要离职了,不要给接手的小伙伴造成困扰,我还是留了配置。
在BaseController中,关掉 enbaleAutoSwitchLanguage 选项,或者
/* * if any need? protected void OnlyEnglish() { this.innerUpdateLanguage("en-US"); } */
然后今天的大部分时间都在弄step3、step4,东西不少,翻译那边也要协助搞,必然是耗时的。
转载请保留地址:http://blog.csdn.net/yeshennet/article/details/53614156
by Yeshen 2016.12.13