<a href="https://github.com/winsnow/spring-message">source code</a>
十一假期被通知出现大bug,然后发现是多语言翻译问题。法语中有很多单引号,单引号在format的时候出现无法匹配问题。这个问题是由spring resource bundle 并调用MessageFormat引起的,根本原因是MessageFormat会转义单引号。
这里没有指定localeResolver, 默认会使用AcceptHeaderLocaleResolver,也就是说从request的header中获取<code>Accept-Language</code>来解析语言。
ResourceBundleMessageSource是多语言翻译的逻辑处理。<code>source.setBasenames("msg")</code>绑定一个多语言的集合。这里我创建一个叫做msg的集合:
.
在main下右键创建一个文件夹i18n,然后将其设置为resources类型。在gradle中,可以在build.gradle里添加:
然后-New-Resource Bundle. 起一个集合的名字,比如msg, 添加需要的语言包。
在里面添加内容
java中通过MessageSource来获取配置语言包中内容
在controller的参数中添加Locale会自动注入LocaleResolver解析后的Locale, 当前是采用默认的AcceptHeaderLocaleResolver。当然也可以自己添加locale拦截器来自定义locale, 这个后面再去设置。
本例中获取name和age。其中name需要插入参数,而age不需要参数,原样输出即可。
如果在jsp中可以使用spring标签:
通过postman来访问get请求:

可以看到age的单引号会原样输出,但name的单引号没了,不仅如此,参数也并没有传入
这是因为messageSource在getMessage的时候采用了两种策略,一种是原样输出,一种是采用MessageFormat来处理参数。
因此,主要原因就是MessageFormat的问题了。
通过测试用例可以发现,MessageFormat会转义(escape)单引号(quote)。因此,如果想要输出一个单引号就需要针对的用两个单引号来替换。
所以,解决上述问题的关键就是在语言包中涉及单引号的地方都做一下转义,即两个单引号。然而,这个步骤会比较繁琐,而且会使得语言包的内容和显示的内容不一致。因此,最好可以通过一个工具来将单引号自动转义。
既然已经知道问题原因所在了,那么只要在Format之前做一下转义就可以了。
追踪getMessage方法到AbstractMessageSource可以发现有参数和无参数的不同处理:
那么,按道理,我们只要处理有参数的情况下就好了。接下来就应该是重写resolveCode方法,将取出来的结果中的单引号替换。
要重写的就是ResourceBundleMessageSource类, 但是发现这些方法都是私有的。这是因为我当前spring的版本是4.1.1。 意外升级成4.3.2之后发现这些方法已经变成protected。
接着发现由于私有成员变量能重写的是getStringOrNull方法,但重写后也会影响无参数的获取。所以,设置ResourceBundleMessageSource
将所有的语言包获取都走传参路线,即都会经过MessageFormat处理,即单引号都要转义。如此,便可以重写getStringOrNull了。
创建ResourceFormat
然后修改配置类:
这样,再次访问:
这样就正常了,单引号可以显示,并且参数可以传进去。
关于locale resolver有多个实现类,通常使用<code>SessionLocaleResolver</code>, 这时候需要添加一个拦截器,来将locale注入进去。注入locale的方法有很多,比如header,比如url直接传参,比如cookie。通过各种手段获取浏览器的语言之后,设置到locale里就可以了。
spring自带了一个<code>LocaleChangeInterceptor</code>,可以将参数locale拦截并注入。
因此,只要自己在拦截器里设置:
localeString就是语言代码,比如en-US, zh-CN
<a href="http://www.cnblogs.com/woshimrf/p/5030642.html">http://www.cnblogs.com/woshimrf/p/5030642.html</a>
<a href="https://www.mkyong.com/spring-mvc/spring-mvc-internationalization-example/">https://www.mkyong.com/spring-mvc/spring-mvc-internationalization-example/</a>
唯有不断学习方能改变!
-- <b>Ryan Miao</b>