最近一直在做整个页面的国际化,相信很多小伙伴们都做过,前端主要采用的是Angularjs,后端使用的是Spring来做国际化,那么他们的优点,缺点现在一起来总结一下。其实无论用哪种语言做国际化,感觉都是千篇一律,只不过实现的方式不同而已。
1.定义国际化配置(什么CN啊EN啊之类的)
2.读取国际化配置
3.定义自己的国际化方式(是通过切面也好,工具类也好)
AngularJs国际化
1.定义国际化配置;
在自己指定的目录下定义国家化配置文件吧,大部分只要求实现中文和英文,所以定义两套,以key和value的形式。
en.json 文件内容如下:
cn.json 文件内容如下:
2.读取国际化配置AngularJs读取国际化配置的时候要引入Angularjs的相关Js。
接下来通过注入依赖来读取配置文件:
分解的看下上面的代码:
var app = angular.module('myApp', ['pascalprecht.translate']);
这一句就是告诉我们已经把 angular-translate 模块以一个依赖项加载进来.
.config(['$translateProvider',function($translateProvider)
config 函数用 $translateProvider 服务配置 $translate 服务实现.
我们上面使用了 localStorage.lang 来存储用户上一次选择的语言,如果用户是第一次范围,默认显示中文(及 加载 cn.json 文件来翻译)
$translateProvider.preferredLanguage(lang)
这一句告诉 angular.js 哪种语言是默认已注册的语言.
上面的语句告诉我们 angular.js 应该加载本地那些国际化语言配置文件.
prefix : 指定文件前缀.
suffix: 指定文件后缀.
定义自己的国际化实现方式: 现在我们先准备在html页面里做国际化,首先想到做一个过滤器,在html页面使用起来是最方便的. /filters/ 目录下创建 T.js 过滤器
假如登录的控制器 LoginCtrl.js 有一个登录标签需要做国际化:
那么这意味着,页面的元素也需要绑定一个ng-model。
那么使用另外一种,就直接在页面进行过滤了。
Spring国际化
在网上找到了一篇写的不错的文章,这里转载一下,就懒得自己写了,这里说明一下为什么要做后台国际化,主要是对业务异常的信息提示,来做国际化的,这一块也会用到。
原文地址:http://a123159521.iteye.com/blog/1323317
覆写ResourceBundleMessage.
Spring留接口,其设计给力啊,很容易扩展。
- package org.frame.base.message;
- import java.io.UnsupportedEncodingException;
- import java.text.MessageFormat;
- import java.util.Locale;
- import java.util.Map;
- import java.util.concurrent.ConcurrentHashMap;
- import org.springframework.context.support.ResourceBundleMessageSource;
- /**
- *
- * 扩展Spring的resourceBundleMessageSource
- * 使其支持中文,因为properties文件天生不支持中文,如果要其支持,需要转码,麻烦!
- *
- * 于是扩展一下,实现自动转码
- */
- public class ResourceBundleMessageSourceExtend extends
- ResourceBundleMessageSource {
- private static final String ENCODING = "GBK";// 注意属性文件使用GBK编码
- private static final String NULL = "null";
- /** cache the encoding key value * */
- Map<String, String> encodingCache = new ConcurrentHashMap<String, String>(
- 20);
- /**
- * resolve no argus
- */
- protected String resolveCodeWithoutArguments(String code, Locale locale) {
- String message = super.resolveCodeWithoutArguments(code, locale);
- return decodeString(message, ENCODING);
- }
- /**
- * resolve args
- * @see resolveCode(String code, Locale locale)
- */
- protected MessageFormat createMessageFormat(String msg, Locale locale) {
- if (logger.isDebugEnabled()) {
- logger.debug("Creating MessageFormat for pattern [" + msg
- + "] and locale '" + locale + "'");
- }
- msg = decodeString(msg, ENCODING);
- return new MessageFormat((msg != null ? msg : ""), locale);
- }
- /**
- * 转码
- * @param msg
- * @param encode
- * @return
- */
- private String decodeString(String message, String encode) {
- String encodMessage = encodingCache.get(message);
- if (encodMessage == null) {
- try {
- encodMessage = new String(message.getBytes("ISO8859-1"), encode);
- if (message != null) {
- encodingCache.put(message, encodMessage);
- } else {
- encodingCache.put(message, NULL);
- // log the code is not exist in properties
- }
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- }
- }
- return encodMessage;
- }
- }
配置文件如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" " http://www.springframework.org/dtd/spring-beans.dtd ">
- <beans default-autowire="byName">
- <!-- 国际化资源文件 -->
- <bean id="messageSource" class="org.frame.base.message.ResourceBundleMessageSourceExtend">
- <property name="basenames">
- <list>
- <value>message/message</value>
- <value>message/error</value>
- </list>
- </property>
- </bean>
- </beans>
配置文件内容
- message.user.username = 用户名 !
- message.user.password = 密码 !
- message.user.context = 内容{0}真好 !
- message.user.username = user name !
- message.user.password = password !
- package org.frame.base.message;
- import java.util.Locale;
- import org.springframework.context.MessageSource;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- public class MessageSourceTest {
- public static void main(String[] args) {
- MessageSource messageSource = new ClassPathXmlApplicationContext("message/testMessage.xml");
- String message1 = messageSource.getMessage("message.user.username", null, Locale.CHINESE);
- //String message3 = messageSource.getMessage("message.user.username", null, Locale.CHINESE);
- String message4 = messageSource.getMessage("message.user.context", new Object[]{"ycl"}, Locale.CHINESE);
- String message2 = messageSource.getMessage("error.user.validName", null, Locale.CHINESE);
- System.out.println(message1);
- System.out.println(message2);
- System.out.println(message4);
- }
- }
配置文件使用GBK编码,不需要转码,就能够自动转码了
国际化其实很简单,调用语言自带的功能,实现起来还是很快的,就是每个地方都需要使用国际化,都要去定义模板,感觉好麻烦,很繁琐。
这里说说国际化的缺点;
1.定位错误不方便。使用了国际化之后我们的页面都是一个一个的KEY,你能保证你会记住每个key的含义吗,如果页面中某个字段报错了。我们肯定是根据这个字段查询到这个属性,然后再排查错误,现在页面都是key了,你要先去配置文件里面,找到这个字段,然后再根据配置文件里面的key,去找到页面的key。
2.耦合度太高,页面国际化在我看来应该是无关编程语言的,而我们无论是使用spring还是angularjs,还是jquery的i18N。都需要去引入相应的文件,然后在去定义响应的配置文件,响应的国际化方式。像angularjs这种,一旦哪一天像换个什么前端框架,这套国际化直接报废。
3.兼容性太差,我这里不是指浏览器的兼容,而是指各个JS框架之间的兼容,因为前端没有完全统一的关系。
4.效率低,先解析配置文件,然后再去匹配配置文件,从一堆JSON里面找出自己的那一个,效率确实会有影响,虽然很低。
其实无论使用上面的哪种方法都是把页面上的静态字段,定义成一个变量,然后在后台进行比对匹配,最后在预先定义的模板里面进行匹配,找出到那个显示给用户的字段。
我们都知道在HTML里面一个静态字段从来都不会很突兀的放在那里,它必然会跟有这样的标签;
我们来看下W3C对于这个标签的解释
浏览器支持
所有主流浏览器都支持 <span> 标签。
标签定义及使用说明
<span> 用于对文档中的行内元素进行组合。
<span> 标签没有固定的格式表现。当对它应用样式时,它才会产生视觉上的变化。如果不对 <span> 应用样式,那么 <span> 元素中的文本与其他文本不会任何视觉上的差异。
<span> 标签提供了一种将文本的一部分或者文档的一部分独立出来的方式。
提示和注释
提示:被 <span> 元素包含的文本,您可以使用 CSS 对它定义样式,或者使用 JavaScript 对它进行操作。
来了,重点来了,我现在要说一个极端的前端国际化方法。
首先假设我们所有的文本都被<span>标签所包裹着,当然还有更极端的就是自己去定义一个国际化标签,这个等会在讲。
然后我们的页面就这样去定义。注意span里面的内容。
这个"|",我把它当成是国际化标签分隔符,我认为我左边的是中文,右边的是英文,如果还要加韩语怎么办,我可以在添加一个"|",然后写上韩语。
接着写我们的JS方法,首先要记住一点,那就是在登陆的时候,肯定会去选择使用哪种语言。选择好了之后,记得保存起来,存到哪都可以,我这里是存到window里面去了,以后肯定是要读出来的。
来,是不是很简单,首先找到我们的国际化下标,这里通过window.localStorage.lang找到用户选择的语言,然后给它指定国际化下标,如果是中文的话,我们默认在第一个"|"前面,如果是英文的话,那就是在第一个"|"后面,以后在添加什么语言,只要改一行代码。然后在页面上加上我们的"|"属性就好了。来看看效果。
中文效果:
切换成英文的效果:
决定在加个韩语试试
基本不需要配置啊,只需要大家去遵循这个语法就可以了,而且加载速度也是很快,根本不怎么影响。感兴趣的,可以在自己的项目里面试一试。