读书人

一个i18n的草案请人拍砖

发布时间: 2012-11-07 09:56:10 作者: rapoo

一个i18n的方案请人拍砖
长久以前做18n一直靠Strurts的resource bundler的方法,从properties里读取一个个key的值来对应显示正确的语言文字,对于大部分场景这都是满足的。

但是对于有些情况,Resource bundler就不一定适合,比说产品的名称,一个很简单的例子,我的产品中文叫“钢笔,铅笔”,英文叫“pen,pencil",在搜索场景中,国内客户输入的就是“笔”--他想要钢笔铅笔的报价,国外用户可能输入“pen"--他只要钢笔的价格。那么resource bundler在这种情景下就有点力不从心。---可能方案,parser对应的properties,对应line的key读出来,然后读数据库,取信息....(也许luncene有更好的方案,不过偶不知道)。

因此我的初步解决方法是,将各国语言都存储到数据库中去,利用java 5.0的annotation标注其适用的field,例子如下。

//POJO 在hibernate mapping 是field不是propertiespublic class Major implements Serializable {@DocumentIdprivate int id = 0;@SuppressWarnings("unused")@Field(name="subject",index = Index.TOKENIZED, store = Store.NO)@Localization(language = "en", country = "US", acquiescence = true)private String subject_english = StringUtils.EMPTY;@SuppressWarnings("unused")@Field(name="subject",index = Index.TOKENIZED, store = Store.NO)@Localization(language = "zh", country = "CN")private String subject_chinese = StringUtils.EMPTY;                // get/set Id 从略          public String getSubject(){            return Translator.translate(this, CurrentUser.getLocale());        }        public void setSubject(String subject){        }         }


Localization是个简单的annotation标签,它有四个参数,前面三个分别是langauge,country和variant,于java.util.Locale的构造参数是一样的,用于构造一个可比较的locale变量,第四个参数acquiescence用于指定某个field是否为默认显示。(default被java给占用了)。

无论我们指定了多少种语言的field,默认暴露出来的就只有subject一个属性,在getSubject中,我写了一个简单的Translator来parser匹配当前locale的field. CurrentUser是个辅助类,从ServletContext中读当前locale,如果用Spring的话,可以直接wrap
LocaleContextHolder.getLocale();


接下来是Translator的内容,并未做什么太多事情
import java.util.Locale;import java.lang.reflect.Field;import org.apache.commons.lang.StringUtils;public class Translator {public static String translate(Object object, Locale locale)throws IllegalAccessException {String result = StringUtils.EMPTY;for (Field field : object.getClass().getFields()) {field.setAccessible(true);Localization i18n = (Localization) field.getAnnotation(Localization.class);// construct a local for compareif (locale.equals(new Locale(i18n.language(), i18n.country(), i18n.variant()))) {result = field.get(object).toString();break;}// set a default value if no foundif (i18n.acquiescence() && StringUtils.isEmpty(result))result = field.get(object).toString();}return result;}}


利用了反射读每一个field的标签,找到适合的值返回而已。

这个方案好处是,对搜索是透明的,无须干预后台生成索引,也无须干预hibernate search的搜索过程,理论上可以满足前面提出的应用场景,请大家拍砖。
比如 中文资料有"国光苹果","红富士苹果","香蕉苹果","象牙芒果" 等等, 我可以通过搜索苹果,得到前三者的产地/价格/品种吗?

public class Fruit{  public long id=0;  public String name=null;  public double price=0.0;  public String description=null;}


又及,Descritpion可能为TEXT类型的i18n文档, 要Search出description中带有某些字眼的POJO出来,不知道用resouce builder怎么实现?public class helloWorld{}<p>你厉害</p> 28 楼 ray_linn 2009-08-31 呵呵,居然想起这个帖子了, 先把应用场景说清楚,这样比较好讨论:

比如我的站点是电器公司的,客户关心冰箱,除了品牌,价格外,最注重的就是它的功能,有许多条款确实不需要做i18n,比如电耗、容积、这些是每台冰箱都有的东西,可以用一个个field来表示,但是以后的产品可能有新的功能,这个就没办法通过增加field来是实现了,因此留了个descript来容纳这些东西:

比如 冰箱A: WLAN 下载 菜谱 光合 保鲜
比如 冰箱B: 臭氧 异味清除 光合 保鲜
冰箱C: 真空保存 臭氧杀菌

这里这些关键词是我人为抽取出来的,这个设计是为了 对这些description做一个i18n的搜索用的:

比如输入“臭氧", 冰箱B和C应该被显示出来,而英国人输入ozone,得到是一致的结果,这里利用了hibernate search,来自动为description分词,索引。


简单一句话,这个方案是针对输入无法预测的string字段的一个解决办法。

读书人网 >软件架构设计

热点推荐