锁定老帖子 主题:一个i18n的方案请人拍砖
精华帖 (0) :: 良好帖 (2) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-10-31
最后修改:2009-08-31
但是对于有些情况,Resource bundler就不一定适合,比说产品的名称,一个很简单的例子,我的产品中文叫“钢笔,铅笔”,英文叫“pen,pencil",在搜索场景中,国内客户输入的就是“笔”--他想要钢笔铅笔的报价,国外用户可能输入“pen"--他只要钢笔的价格。那么resource bundler在这种情景下就有点力不从心。---可能方案,parser对应的properties,对应line的key读出来,然后读数据库,取信息....(也许luncene有更好的方案,不过偶不知道)。 因此我的初步解决方法是,将各国语言都存储到数据库中去,利用java 5.0的annotation标注其适用的field,例子如下。 //POJO 在hibernate mapping 是field不是properties public class Major implements Serializable { @DocumentId private 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 compare if (locale.equals(new Locale(i18n.language(), i18n.country(), i18n .variant()))) { result = field.get(object).toString(); break; } // set a default value if no found if (i18n.acquiescence() && StringUtils.isEmpty(result)) result = field.get(object).toString(); } return result; } } 利用了反射读每一个field的标签,找到适合的值返回而已。 这个方案好处是,对搜索是透明的,无须干预后台生成索引,也无须干预hibernate search的搜索过程,理论上可以满足前面提出的应用场景,请大家拍砖。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-10-31
在一个pojo中定义多个相同name的@Field,没见过这种用法,不知道是否可行?这样如何存储到Document中?存储进去才能被搜索得到。
就这个简单的例子来讲,你的方案复杂了,直接就是定义一个@Field(name="keyword"),把所有语种的关键词都存储起来即可。 # public String getSubject(){ # return Translator.translate(this, CurrentUser.getLocale()); # } 索引的时候,没法构造CurrentUser.getLocale()这个环境了。这个只能用于特定用户显示结果用。 |
|
返回顶楼 | |
发表时间:2008-10-31
sorphi 写道 在一个pojo中定义多个相同name的@Field,没见过这种用法,不知道是否可行?这样如何存储到Document中?存储进去才能被搜索得到。
就这个简单的例子来讲,你的方案复杂了,直接就是定义一个@Field(name="keyword"),把所有语种的关键词都存储起来即可。 # public String getSubject(){ # return Translator.translate(this, CurrentUser.getLocale()); # } 索引的时候,没法构造CurrentUser.getLocale()这个环境了。这个只能用于特定用户显示结果用。 1。 同name的field应该是可实现的,详细我可以做个试验看看。因为我是利用hibernate Search,存储是的时候会直到被POJO持久化。 2. 我分成不同的field,是为了配合不同的分词器.hibernate search 3.1似乎可以支持不同分词器,目前似乎还没有万国分词器啊。 3. 我只写了getSubject,setSubject的locale变量不来自于CurrentUser,而是来自于某个Setting,一般场景是后台输入人员选择了语言的种类,因此详细我就没在写出来。 |
|
返回顶楼 | |
发表时间:2008-10-31
Hibernate Search倒是支持一个property映射到不同Field,在文档中也没有你那种例子,我想了一下好像也不可行。
分词的问题我倒是没有考虑,只想到中文分词器一般可以用于按空格隔开单词的语种中。 |
|
返回顶楼 | |
发表时间:2008-10-31
java在支持国际化时,除了属性文件化,还可用list;
你还不如直接把数据库的资料,读到list中。 汗!!!!!!!!!! 这是部份代码,仅供抛砖引玉用 //获取系统的区域与语言默认设置 Locale locale = Locale.getDefault(); String ret; ListResourceBundle aa=new ListResourceBundle () { Object[][] contents ={{"key","hello"},{"key1","你好"}}; @Override protected Object[][] getContents() {return contents; } }; ret= aa.getString("key1"); ============================ |
|
返回顶楼 | |
发表时间:2008-10-31
yunhaifeiwu 写道 java在支持国际化时,除了属性文件化,还可用list;
你还不如直接把数据库的资料,读到list中。 汗!!!!!!!!!! 这是部份代码,仅供抛砖引玉用 //获取系统的区域与语言默认设置 Locale locale = Locale.getDefault(); String ret; ListResourceBundle aa=new ListResourceBundle () { Object[][] contents ={{"key","hello"},{"key1","你好"}}; @Override protected Object[][] getContents() {return contents; } }; ret= aa.getString("key1"); ============================ 你这不是又回到了我最早的问题吗? 我输入"hello"和"你好",如何得到同一个POJO,因为他们就是同一个POJO啊。 这就好比“苹果”和apple都可以返回产品清单中的" id =2". |
|
返回顶楼 | |
发表时间:2008-10-31
ray_linn 写道 yunhaifeiwu 写道 java在支持国际化时,除了属性文件化,还可用list;
你还不如直接把数据库的资料,读到list中。 汗!!!!!!!!!! 这是部份代码,仅供抛砖引玉用 //获取系统的区域与语言默认设置 Locale locale = Locale.getDefault(); String ret; ListResourceBundle aa=new ListResourceBundle () { Object[][] contents ={{"key","hello"},{"key1","你好"}}; @Override protected Object[][] getContents() {return contents; } }; ret= aa.getString("key1"); ============================ 你这不是又回到了我最早的问题吗? 我输入"hello"和"你好",如何得到同一个POJO,因为他们就是同一个POJO啊。 这就好比“苹果”和apple都可以返回产品清单中的" id =2". ListResourceBundle 与struts2属性文件一样,自动根所设定地区代号,选择是哪一类别的资料。 如果你是中国,就会得到 苹果! 如果你是英国,就会得到 apple! 但Pojo却是同一个. 注意:java对国际化支持, 一是属性文件(struts就是利用这个) 二是list性,相关处理类是 ListResourceBundle. list一样会成相同的键,而对应的语言不同存放资料,然后自动根据地区选择语言。 如何使用ListResourceBundle 请查阅相关资料! |
|
返回顶楼 | |
发表时间:2008-10-31
public class ProgramResources_de extends ListResourceBundle{ public Object [][] getContents() {return contents; } private static final Object[][] contents { {"button", "Rechnen"}, {"backColor", Color.black}, {"defaultSie", double[] {210, 297}} } } public class ProgramResources_en_US extends ListResourceBundle{ public Object [][] getContents() {return contents; } private static final Object[][] contents { {"button", "Compute"}, {"backColor", Color.blue}, {"defaultSie", double[] {216, 279}} } } ------------------------------------- 这是大体一个ListResourceBundle。没有测试,自已查阅相关资料吧! 回到你的苹果问题上: 如果要显示中国的文字,要把汉字资料“苹果“读入到 ProgramResources_ch_ZH 中, 如果要显示美国的文字,要把英文资料”apple",读到 ProgramResources_en_US 中。 (至于你的文字资料,要放在哪个数据库,随你!只要你按要求读入到相应的类对象中就行了。 一种合理的方式时,在加载资料时,要先得例用者的地区信息,然后只加载该地区的资料!) 同时你的Pojo 的属性,要引用ListResourceBundle的key (估计不错的法, java允许注释方式引用。 )。 这样,java会自动根据用户所在的地区,给你的POJO注入相应地区的数据。 即: 中国,你的pojo 的id="苹果" 在美国,你的pojo 的id="apple" 但你的 pojo却是同一个! |
|
返回顶楼 | |
发表时间:2008-10-31
http://cache.baidu.com/c?m=9d78d513d99d1aee1eadc33f505197374e04c73f6a8987027fa5cb1bd7374c41367195be30511013a2b66b1677bb0e1cb4ff6c34714137b6e8d5951a83e6c73f2fff71692c4bc30005d36efe9619389262c304b4f34cfae9b063c9f59684c25451c85418788aed8b5d1d13ca6bf0103af4a6ee1b541d5a&p=882a9642919c16fd0be2932a5747&user=baidu
这是一个简单介绍! |
|
返回顶楼 | |
发表时间:2008-10-31
谢谢你的分享,让我开了眼界.
不过我想你可能有点误会我要东西,我的要求是--- 知道某个产品的某个i18n的名字,比如中文"苹果",英文"apple",能够回溯回它在数据库中的id,从而拿到他在数据库中的i18n资料,比如产地/价格/品种. 我不知道你的方案如何实现第一步,即从"苹果" "apple" 回溯回 id. 比如 中文资料有"国光苹果","红富士苹果","香蕉苹果","象牙芒果" 等等, 我可以通过搜索苹果,得到前三者的产地/价格/品种吗? 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怎么实现? |
|
返回顶楼 | |