我们会看到很多支持多语言的网站,有些早期的网站在首页会有一个链接,让用户自己来选希望看到中文,还是英文,现在的网站则不需要了,这些网站可以根据用户使用的语言来显示不同语言的版本。比如,你在使用简体中文,打开网页,会看到一个简体中文的网页,你在使用英文,输入同一个地址,就会看到一个英文的页面。
服务器是如何知道用户希望看到何种语言版本的页面呢?
浏览器端
对于网站来说,一个网站要服务海量的用户,使用服务器来记住用户的语言是很麻烦的,这个工作还是从浏览器开始,如果浏览器自己告诉服务器希望使用的语言,服务器不就简单了吗?
各种浏览器都可以设置希望使用的语言,在 IE 中,选择设置,弹出对话框之后,可以设置语言首选项。
点击语言,弹出语言首选项对话框。
在控制面板中进行设置。
对于 Chrome 来说,在高级设置中。
点击语言和输入设置。
当浏览器向服务器发出请求的时候,浏览器会在请求头中添加一个特殊的请求头 Accept-Language 来说明浏览器端设置的语言类型,如果你刚才注意的话,会发现我们可以设置多个语言,而且可以调整顺序,在 Accept-Language 头中,它们按着你设置的顺序依次出现。每种语言使用逗号 (,) 进行分隔。
各种浏览器的 Accept-Language 如下所示。
IE 的语言
Accept-Language en-US,en;q=0.8,zh-Hans-CN;q=0.5,zh-Hans;q=0.3
Chrome 的语言
Accept-Language:zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4
FireFox 的语言
Accept-Language: en-us,zh-cn;q=0.8,en;q=0.5,zh;q=0.3
慢着,q 又是什么呢?在 HTTP 协议中有一个详细的说明,点击这里的链接可以查看详细说明: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html。简单来说,语言可以携带一个“q”值,来表示用户对该语言的喜好程度,这个值在 0 - 1 之间,默认为 1。
服务器端
在我们服务器端代码中,可以直接获取到浏览器在请求中携带的语言设置,在 .NET 中,HttpRequest 表示浏览器发出的请求,属性 UserLanguages就表示 Accept-Language 中传递的语言,已经根据优先级进行了排序,而且已经根据逗号 (,) 进行了拆分。这个属性是一个字符串数组。
代码中
string[] languages = Request.UserLanguages;
比如,我们希望取出第一个语言,就可以通过 Request.UserLanguages[0] 来获取到了。
获取的语言从程序的角度来说仅仅是一个表示语言的字符串,从面向对象的角度来说,我们需要一个对象来表示语言,这个类就是 CurtureInfo 类,它定义在命名空间 System.Globalization 中。可以通过 MSDN 来查看它的定义。
通常,我们将表示语言的字符串通过构造函数传递给 CultureInfo。
CultureInfo info = new CultureInfo(culture);
中文问题
如果你刚才仔细查看的话,会发现 IE 发送的语言代码与 Chrome 是不一样的。你会发现表示简体中文实际上有四种写法:
- zh
- zh-cn
- zh-Hans
- zh-Hans-CN
这些写法是从哪里来的呢,在 MSDN 中有详细的说明
CultureInfo 类将根据 RFC 4646为每个区域性指定一个唯一的名称。 名称是语言关联的 ISO 639小写双字母区域性代码和国家/地区关联的 ISO 3166大写双字母子区域性代码的组合。
比如 zh 就表示中文,Han: 汉字 ,S: Simplified 简体字,T: Tranditional 繁体字,而 cn 表示中国地区代码。
区域性名称的格式为 两个小写字符的语言代码>-两个大写字符的国家地区码。 例如 “zh-CN” 代表“中文(简体中文)”,“en-US”代表“英语(美国)”。 在双字母语言代码不可用的情况中,将使用从 ISO 639-2 派生的三字母代码。
请注意,某些区域性名称还指定 ISO 15924书写符号。 例如,中文有简体和繁体之分,这种名称可以使用 两字符的语言码-书写标记-两字符的国家地区码形式。 例如“zh-Hans-CN”代表“简体中文(中国)”。 对于 Windows Vista 之前的操作系统,包含书写符号的区域性名称使用languagecode2-country/regioncode2-scripttag 的模式,例如“uz-UZ-Cyrl”代表“乌兹别克语(乌兹别克斯坦,西里尔语)”。
非特定区域性只能由双字母小写语言代码指定。 例如,fr指定“法语”的非特定区域性,de指定“德语”的非特定区域性。
那么,zh 就表示非特定区域的中文,en 就表示非特定区域的英文。
但是,需要注意的是,CultureInfo 不支持 zh-Hans-CN 写法,如果你使用了,会收到这样一个异常。
zh-Hans-CN 是无效的区域性标识符。
你可以使用 zh, zh-cn, zh-Hans, 但是,不能使用 zh-Hans-CN 来构建 CultureInfo 对象。
网站如何知道浏览器的用户在使用什么语言?