简体   繁体   English

无法获得特定国家/地区的本地化响应

[英]Failed to get country specific Localized response

I have a spring boot application and we are trying to support multiple languages and countries. 我有一个spring boot应用程序,我们正在尝试支持多种语言和国家/地区。

These are the codes we are planning to support for now. 这些是我们现在计划支持的代码。 en, es, fr, en-gb, es-mx, zh, ja. en,es,fr,en-gb,es-mx,zh,ja。

I'm working on getting some fields in response to be localized. 我正在努力获取一些字段以响应本地化。 When I run the application in my local(eclipse) and check the response from postman I can see that it is picking up country specific files and giving the response correctly, but when I push my changes to AWS server it is not, it is only picking up language specific files and ignoring country codes. 当我在本地(eclipse)中运行应用程序并检查邮递员的响应时,我可以看到它正在拾取特定于国家/地区的文件并正确地给出响应,但是当我将更改推送到AWS服务器时它不是,它只是获取特定于语言的文件并忽略国家/地区代码。

For example, if I give the Accept-Language as da,es-MX;q=0.8 I expect the response in es-MX(we do not support da) but it is just giving the response in es(I have both es and es-MX files) and ignoring the country code MX. 例如,如果我将Accept-Language设置为da,es-MX; q = 0.8我期望es-MX中的响应(我们不支持da)但它只是在es中给出响应(我有es和es-MX文件)并忽略国家代码MX。

But if i have Accept-Language as fr,es-MX;q=0.8 it is picking up messages_fr.properties file and gives the response in French which is what I expect. 但是,如果我将Accept-Language作为fr,es-MX; q = 0.8,它将获取messages_fr.properties文件,并以法语给出响应,这是我所期望的。

Below are my classes. 以下是我的课程。

@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;
    }

}

This class parses Accept-Language header and sets Locale. 此类解析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();
        }
    }

I have the below constant in my ApplicationConstants class 我的ApplicationConstants类中有以下常量

public static final List<String> LOCALE              = Collections
            .unmodifiableList(Arrays.asList("en", "es", "fr", "es-mx", "zh", "ja"));

Here is the MessageHandler class 这是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);
    }

}

Any thoughts on this? 有什么想法吗?

It seems you're just reimplementing the lookup() method of Locale: 看来你只是重新实现了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

There are few ways to implement the correct locale lookup method (by the way congratulation on following i18n best practices). 有几种方法可以实现正确的区域设置查找方法(顺便提一下,遵循i18n最佳实践)。
One way is to parse the header "manually", as you attempted. 一种方法是在您尝试时“手动”解析标题。
However, please note that HttpServletRequest derives one fancy method from its superclass, that is ServletRequest#getLocales() . 但请注意, HttpServletRequest从其超类派生出一个奇特的方法,即ServletRequest#getLocales()
My point is, you'll receive already parsed prioritized Enumeration of Locales. 我的观点是,您将收到已经解析的优先级枚举区域设置。 By the way, I would definitely use the HashSet to compare locales against (for performance reasons). 顺便说一句,我肯定会使用HashSet来比较区域设置(出于性能原因)。

Enough of talking: 足够说话:

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);
    }
}

In this case the ApplicationConstants class needs to be modified: 在这种情况下,需要修改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?

A word on Chinese. 关于中文的一个词。 There are two flavors of Chinese language - Chinese Simplified (zh-Hans) and Chinese Traditional (zh-Hant). 有两种中文口味 - 简体中文(zh-Hans)和繁体中文(zh-Hant)。 It is best not to mix them. 最好不要混合它们。 I am not sure if it is good idea to serve Chinese Simplified as default Chinese version. 我不确定将简体中文版本作为默认中文版本服务是否是个好主意。 Well, maybe it is, but I have doubts. 好吧,也许是,但我怀疑。 I would use zh-Hans and zh-CN specifically (even if that means I would copy over the same file during CI build). 我会特别使用zh-Hans和zh-CN(即使这意味着我会在CI构建期间复制同一个文件)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM