2016-05-04 5 views
3

Ich habe eine Springboot-Anwendung und wir versuchen, mehrere Sprachen und Länder zu unterstützen.Fehler beim Abrufen der landesspezifischen lokalisierten Antwort

Dies sind die Codes, die wir vorerst unterstützen möchten. de, es, fr, en-de, es-mx, zh, ja.

Ich arbeite daran, einige Felder als Antwort zu lokalisieren. Wenn ich die Anwendung in meinem lokalen (Eclipse) ausführen und überprüfen Sie die Antwort von Briefträger kann ich sehen, dass es länderspezifische Dateien abholen und die Antwort richtig geben, aber wenn ich meine Änderungen an AWS-Server pushen ist es nicht, es ist nur sprachspezifische Dateien abholen und Ländercodes ignorieren.

Zum Beispiel, wenn ich die Accept-Language als da gebe, es-MX; q = 0.8 erwarte ich die Antwort in es-MX (wir unterstützen da nicht), aber es gibt nur die Antwort in es (I habe es sowohl es als auch es-MX-Dateien) und ignoriere den Ländercode MX.

Aber wenn ich Accept-Language als fr, es-MX; q = 0.8 habe, nimmt es die Datei messages_fr.properties auf und gibt die Antwort auf Französisch, was ich erwarte.

Unten sind meine Klassen.

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

} 

Diese Klasse analysiert Accept-Language-Header und legt Locale fest.

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

Ich habe die unten Konstante in meinem ApplicationConstants Klasse

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

ist die Message Klasse

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

} 

Irgendwelche Gedanken dazu?

Antwort

2

Es scheint, Sie sind nur die Lookup() -Methode von Locale Neuimplementierung:

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 
+0

Das sieht besser aus, aber aus irgendeinem Grund nimmt es immer noch die Datei messages_es.properties auf und nicht messages_es_mx.properties. Aber wie ich bereits erwähnt habe funktioniert in meinem lokalen (wenn ich vor der Sonnenfinsternis laufe). Dies ist meine Kopfzeile in der Anfrage da, es-MX; q = 0.8 – Arun

+1

Ihre Datei sollte den Namen messages_es_MX.properties haben, nicht messages_es_mx.properties –

+0

Es hat funktioniert. Vielen Dank. wenn ich das Gebietsschema drucke, das mit dem Code zurückgegeben wurde, den ich es bekannt gab, druckte es als mx anstelle von MX. Deshalb habe ich den Dateinamen mit MX anstelle von MX beibehalten. Von Ihrem Code sehe ich, dass es als es_MX gedruckt wird, ich habe es in messages_es_MX.properties umbenannt und es hat funktioniert. Danke noch einmal. – Arun

1

Es gibt nur wenige Möglichkeiten, um die korrekte locale-Lookup-Methode (übrigens seine Glückwünsche an folgende i18n Best Practices) zu implementieren.
Eine Möglichkeit besteht darin, die Kopfzeile "manuell" zu analysieren, wie Sie es versucht haben.
Bitte beachten Sie jedoch, dass HttpServletRequest eine ausgefallene Methode aus ihrer Oberklasse ableitet, nämlich ServletRequest#getLocales().
Mein Punkt ist, Sie erhalten bereits geparseten priorisierten Enumeration von Locales. Übrigens würde ich definitiv das HashSet verwenden, um Locales zu vergleichen (aus Performance-Gründen).

Genug sprechen:

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 diesem Fall wird die ApplicationConstants Klasse geändert werden muss:

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? 

Ein Wort auf Chinesisch. Es gibt zwei Geschmacksrichtungen der chinesischen Sprache - Chinesisch vereinfacht (zh-Hans) und Chinesisch traditionell (zh-Hant). Es ist am besten, sie nicht zu mischen. Ich bin mir nicht sicher, ob es eine gute Idee ist, Chinesisch als Chinesische Standardversion zu bedienen. Nun, vielleicht ist es das, aber ich habe Zweifel. Ich würde speziell zh-Hans und zh-CN verwenden (auch wenn das bedeutet, dass ich während des CI-Builds dieselbe Datei kopieren würde).

+0

Danke für die Erklärung. – Arun