Проверка наличия локали клиента в списке поддерживаемых языков

Я хочу представить веб-сайт пользователям на предпочитаемом ими языке, если веб-сайт поддерживает этот язык.

В Spring Boot я использую следующий bean-компонент для установки языка по умолчанию для клиента:

@Bean
public LocaleResolver localeResolver() {
    SessionLocaleResolver localeResolver = new SessionLocaleResolver();
    localeResolver.setLocaleAttributeName("user_locale"); // Not strictly needed
    localeResolver.setDefaultLocale(Locale.ENGLISH);
    return localeResolver;
}

Как я могу изменить его, чтобы взять язык клиента и проверить, есть ли он в списке поддерживаемых языков, например.

private List<Locale> LOCALES = Arrays.asList(new Locale("en"), new Locale("de"), new Locale("fr"), new Locale("sp"), new Locale("it"));

а затем установите локаль, используя что-то вроде

return locales.contains(locale) ? locale : Locale.ENGLISH;

Обратите внимание, что это должно происходить каждый раз при запуске сеанса.

Как вы передаете локаль в бэкэнд? Делает ли это fronted, или вы имеете в виду HTTP-заголовок Accept-Language

Maksim Eliseev 05.08.2023 09:53

Я имею в виду HTTP-заголовок, способ Spring Boot по умолчанию для обработки локали.

qarabala 05.08.2023 10:28
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
2
50
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете получить текущую сохраненную локаль следующим образом:

Locale locale = LocaleContextHolder.getLocale();
localeResolver.setDefaultLocale(locale);

Хорошим способом, если файлы cookie разрешены, было бы реализовать это следующим образом:

@Bean
public LocaleResolver localeResolver() {

    CookieLocaleResolver localeResolver = new CookieLocaleResolver("BALLROOM_LANGUAGE");

    Locale locale = LocaleContextHolder.getLocale();
    localeResolver.setDefaultLocale(locale);

    return localeResolver;
}

Нет необходимости проверять, есть ли автоматически запрошенный язык клиента в вашем списке, так как он всегда будет возвращаться к вашей реализации сообщения по умолчанию (которая в вашем случае будет английской).

Один из способов позволить пользователю изменить локаль вручную (что всегда должно быть возможно) — это собственный LocaleController:

@Controller
@RequestMapping("/locale")
public class LocaleController {

    @PostMapping(path = {"", "/"}, consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
    public String locale(@RequestParam("locale") String locale,
                         HttpServletRequest request,
                         HttpServletResponse response) {

        if (locale != null && !locale.isBlank()) {
            LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
            if (localeResolver == null)
                throw new IllegalStateException("No LocaleResolver found");

            try {
                localeResolver.setLocale(request, response, StringUtils.parseLocale(locale));
            } catch (IllegalArgumentException e) {
                logger.debug("Ignoring invalid locale value [{}]: {}", locale, e.getMessage());
            }
        }

        String referer = request.getHeader("referer");
        return referer != null && !referer.isBlank() ? "redirect:" + referer : "redirect:/";
    }
}

Вы просто отправляете почтовый запрос, содержащий желаемую локаль в виде строки, например, в виде en_US.

Большое спасибо за ваш подробный ответ. Я не совсем понимаю, как в этом ответе достигается механизм по умолчанию, основанный на списке поддерживаемых языков. Если язык поддерживается (например, испанский), то он НЕ должен использоваться по умолчанию (английский). И это должно происходить каждый раз, когда кто-то открывает сеанс. Это была моя основная проблема с localeResolver.setDefaultLocale(locale); в Bean. `.

qarabala 05.08.2023 08:47

Если, например, браузер отправляет es_ES в качестве предпочтительного языкового стандарта, то Spring Boot устанавливает этот языковой стандарт в LocaleContextHolder. Что вам теперь нужно сделать, так это убедиться, что везде, где вы хотите установить свое приложение, у вас есть испанские опции. Spring Boot (соответственно Java) автоматически попытается получить испанские версии чего угодно. Это можно использовать для форматирования даты и времени или отображения текстового содержимого, которое вы сохранили внутри messages.properties: тогда у вас есть база messages.properties и поддерживаемые языки messages_en.properties и messages_es.properties.

Slevin 05.08.2023 17:04

Если вы устанавливаете локаль вручную с помощью localeResolver.setDefaultLocale(locale), то это локаль, которую Spring Boot использует при попытке разрешить локаль, например. сообщения проверки. Вы все еще должны обеспечить поддержку локали (языка), например. сообщения проверки на испанском языке, в противном случае Spring использует резервные варианты. Одной настройки локали недостаточно, вы также должны предоставить поддержку. Затем Spring знает, чего вы хотите, и автоматически попытается найти нужные сообщения.

Slevin 05.08.2023 17:14
Ответ принят как подходящий

Если вы хотите изменить локаль в зависимости от заголовка HTTP Accept-Language, вам нужно использовать AcceptHeaderLocaleResolver, например:

@Bean
public LocaleResolver localeResolver() {
    var resolver = new AcceptHeaderLocaleResolver();
    resolver.setDefaultLocale(Locale.ENGLISH);
    resolver.setSupportedLocales(
            List.of(Locale.ENGLISH,
                    Locale.FRENCH,
                    Locale.of("es"))
    );

    return resolver;
}

Его легко настроить, и я думаю, это именно то, что вам нужно.

Следующий шаг — получить точно локаль, определенную с помощью AcceptHeaderLocaleResolver, и использовать ее, например, для получения сообщения из источников сообщений. Для этого вы можете использовать LocaleContextHolder следующим образом:

@Autowired
private MessageSourceAccessor messageSourceAccessor;

@GetMapping(produces = MediaType.TEXT_PLAIN_VALUE)
public ResponseEntity<String> getGreeting() {
    String msg = messageSourceAccessor.getMessage("msg", LocaleContextHolder.getLocale());
    return ResponseEntity.ok(msg);
}

}

Вы можете посетить мой github , где я создал рабочий пример. Для проверки локали я использовал расширение Locale Switcher Chrome Extension.

Другие вопросы по теме