我有一个春季启动应用程序,我们正在尝试支持多种语言和国家/地区。
这些是我们现在计划支持的代码。 en,es,fr,en-gb,es-mx,zh,ja。
我正在努力获取一些字段以响应本地化。 当我在本地(eclipse)中运行应用程序并检查邮递员的响应时,我可以看到它正在拾取特定于国家/地区的文件并正确地给出响应,但是当我将更改推送到AWS服务器时它不是,它只是获取特定于语言的文件并忽略国家/地区代码。
例如,如果我将Accept-Language设置为da,es-MX; q = 0.8我期望es-MX中的响应(我们不支持da)但它只是在es中给出响应(我有es和es-MX文件)并忽略国家代码MX。
但是,如果我将Accept-Language作为fr,es-MX; q = 0.8,它将获取messages_fr.properties文件,并以法语给出我期望的响应。
以下是我的课程。
@Configuration
@ComponentScan("com.hsf")
@EnableWebMvc
public class ApplicationConfig extends WebMvcConfigurerAdapter {
@Value("${spring.application.name}")
String appName;
@Bean
public LocaleResolver localeResolver() {
return new SmartLocaleResolver();
}
@Bean
public DispatcherServlet dispatcherServlet() {
final DispatcherServlet servlet = new DispatcherServlet();
servlet.setDispatchOptionsRequest(true);
return servlet;
}
@Bean
public ReloadableResourceBundleMessageSource messageSource() {
final ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:i18n/messages");
// If true, the key of the message will be displayed if the key is not
// found, instead of throwing an exception
messageSource.setUseCodeAsDefaultMessage(true);
messageSource.setDefaultEncoding("UTF-8");
// The value 0 means always reload the messages to be developer friendly
messageSource.setCacheSeconds(10);
return messageSource;
}
}
此类解析Accept-Language标头并设置Locale。
public class SmartLocaleResolver extends AcceptHeaderLocaleResolver {
@Override
public Locale resolveLocale(HttpServletRequest request) {
try {
List<LanguageRange> list = Locale.LanguageRange.parse(request.getHeader("Accept-Language"));
if (!list.isEmpty()) {
for (LanguageRange s : list) {
if (ApplicationConstants.LOCALE.contains(s.getRange())) {
return Locale.forLanguageTag(s.getRange());
}
}
}
} catch (IllegalArgumentException e) {
throw e;
}
return request.getLocale();
}
}
我的ApplicationConstants类中有以下常量
public static final List<String> LOCALE = Collections
.unmodifiableList(Arrays.asList("en", "es", "fr", "es-mx", "zh", "ja"));
这是MessageHandler类
@Component
public class MessageHandler {
@Autowired
private MessageSource messageSource;
public String localizeMessage(String errorCode, Object args[]) {
Locale locale = LocaleContextHolder.getLocale();
String message = messageSource.getMessage(errorCode, args, locale);
return message;
}
public String localizeMessage(String errorCode) {
return localizeMessage(errorCode, null);
}
}
对此有何想法?
答案 0 :(得分:2)
您似乎只是重新实现了Locale的lookup()方法:
List<Locale> locales = Arrays.asList(new Locale("en"),
new Locale("es"),
new Locale("fr"),
new Locale("es", "MX"),
new Locale("zh"),
new Locale("ja"));
List<Locale.LanguageRange> ranges = Locale.LanguageRange.parse("da,es-MX;q=0.8");
Locale best = Locale.lookup(ranges, locales);
System.out.println("best = " + best); // prints best = es_MX
ranges = Locale.LanguageRange.parse("fr,es-MX;q=0.8");
best = Locale.lookup(ranges, locales);
System.out.println("best = " + best); // prints best = fr
答案 1 :(得分:1)
有几种方法可以实现正确的区域设置查找方法(顺便说一下i18n最佳实践的祝贺方式)。
一种方法是在您尝试时“手动”解析标题
但请注意,HttpServletRequest从其超类中派生出一种奇特的方法,即ServletRequest#getLocales()。
我的观点是,您将收到已经解析的Locales优先级Enumeration。顺便说一句,我肯定会使用HashSet来比较区域设置(出于性能原因)。
足够说话:
public class SmartLocaleResolver extends AcceptHeaderLocaleResolver {
@Override
public Locale resolveLocale(HttpServletRequest request) {
List<Locale> locales = Collections.list(request.getLocales());
return getBestMatchingOrDefault(locales);
}
private Locale getBestMatchingOrDefault(List<Locale> locales) {
Optional<Locale> maybeLocale = locales.stream()
.filter(locale -> ApplicationConstants.LOCALE.contains(locale))
.findFirst();
return maybeLocale.orElse(ApplicationConstants.DEFAULT_LOCALE);
}
}
在这种情况下,需要修改ApplicationConstants
类:
public static final Set<Locale> LOCALE = Collections.unmodifiableSet(
new HashSet<Locale>(
Arrays.asList(Locale.ENGLISH,
Locale.forLanguageTag("es"),
Locale.FRENCH,
Locale.forLanguageTag("es-MX"),
Locale.JAPANESE,
Locale.forLanguageTag("zh-Hans"),
Locale.PRC,
Locale.CHINESE)));
public static final Locale DEFAULT_LOCALE = Locale.ENGLISH; // or something else?
关于中文的一句话。有两种中文口味 - 简体中文(zh-Hans)和繁体中文(zh-Hant)。最好不要混合它们。我不确定将简体中文版本作为默认中文版本服务是否是个好主意。好吧,也许是,但我怀疑。我会特别使用zh-Hans和zh-CN(即使这意味着我会在CI构建期间复制相同的文件)。