我们现在的应用已经有一部分功能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
