Google foo подвел меня. Я хочу выяснить, существует ли стандартный «по книге» способ преобразования входных локалей из заголовка Accept-Language в правильный ResourceBundle.
ResourceBundle::getBundle()
метод (ы) принимает одну локаль, но Accept-Language может иметь несколько локалей, взвешенных по индексу, например: de;q=1.0, sl;q=0.9
.
Текущий код:
@Context
private HttpServletRequest request;
public String getString(String key) {
ResourceBundle i18n = ResourceBundle.getBundle("locale/strings", this.request.getLocale());
return i18n.getString(key);
}
Проблема в том, что getLocale()
возвращает предпочтительный языковой стандарт, в данном случае de
. Если доступных комплектов ресурсов равны sl
и en
, будет предпринята попытка найти de
и затем выполнить откат к en
, но фактический ожидаемый клиентом результат будет sl
!
Мой вопрос в основном, должен ли я реализовать собственный резервный код, который повторяется по HttpServletRequest.getLocales()
(я не хочу изобретать колесо ...), или есть более стандартный и простой способ сделать это? Я также согласился бы на какую-нибудь стороннюю библиотеку, которая восполняет этот пробел.
Пользовательское решение до сих пор:
@RequestScoped
public class Localization {
@Context
private HttpServletRequest request;
private ResourceBundle i18n;
@PostConstruct
void postConstruct() {
//List of locales from Accept-Language header
List<Locale> locales = Collections.list(request.getLocales());
if (locales.isEmpty()) {
//Fall back to default locale
locales.add(request.getLocale());
}
for (Locale locale : locales) {
try {
i18n = ResourceBundle.getBundle("bundles/translations", locale);
if (!languageEquals(i18n.getLocale(), locale)) {
//Default fallback detected
//The resource bundle that was returned has different language than the one requested, continue
//Only language tag is checked, no support for detecting different regions in this sample
continue;
}
break;
}
catch (MissingResourceException ignore) {
}
}
}
private boolean languageEquals(Locale first, Locale second) {
return getISO2Language(first).equalsIgnoreCase(getISO2Language(second));
}
private String languageGetISO2(Locale locale) {
String[] localeStrings = (locale.getLanguage().split("[-_]+"));
return localeStrings[0];
}
public ResourceBundle i18n() {
return this.i18n;
}
}