Уже давно считается хорошим тоном отдавать контент сайта на языке, предпочитаемым пользователем. Некоторые сервера определяют язык по месту нахождения пользователя с помощью модулей геолокации, остальные берут настройки браузера. Языковые предпочтения пользователя часто сохраняются в cookie, и затем используются при повторном визите.
Какой метод определения языка пользователя подходит лучше – вопрос достаточно спорный. Мой личный ранг значимости языковой информации (в порядке убывания): cookie, настройки браузера, регион.
Для поисковых систем, социальных сетей и прочих агрегаторов информации важно знать, на каком языке должна быть проиндексирована или загружена страница, например в качестве миниатюры в хронику фейсбука. Это значит, что ссылка должна однозначно указывать на язык.
Распространенные варианты кодирования языковой информации о ресурсе следующие:
- каждая языковая версия на отдельном субдомене, например
en.example.com
,ru.example.com
- язык ресурса указывается в префиксе URI, например
example.com/en/
,example.com/ru
- язык ресурса указывается в GET параметре, например
example.com?lang=en
,example.com?lang=ru
Первый вариант наиболее радикальный, каждая языковая версия сайта рассматривается как отдельный ресурс. Могут возникнуть сложности с SSL сертификатом, необходимо заранее предусмотреть все возможные варианты в SAN DNS Host Name, или заказать сертификат с маской, например *.example.com.
Второй вариант наиболее практичный, выбор языка входит в URI, значит, не будет проблем с индексацией и копированием ссылки.
Третий вариант выглядит менее привычно, требует дополнительной логики при добавлении остальных GET параметров и может смутить пользователя при копировании ссылки. Не самый лучший вариант для публичных ссылок.
Я расскажу о реализации второго варианта на базе сервера NGINX. При минимальных изменениях можно применить описанные настройки и для первого варианта.
Настройка состоит из нескольких этапов.
Сначала проверяется языковая настройка браузера. Если у пользователя установлены cookie, то это значение переписывает настройку браузера. Итоговое значение передается в переменную $lang
.
На первом этапе надо настроить back-end на получение GET параметра с информацией о языке. То есть реализуем третий вариант из списка, но внутри нашей системы. Для примера будем рассматривать GET параметр locale=<код локали>
, используем двухбуквенный код ISO 639-1.
Надо удостовериться, что при переходе на ссылку типа http://<адрес_back-end_сервера>?locale=ru
мы получает ответ на русском языке.
После этого можно настраивать NGINX на фронтенде.
Второй этап – получение языковых настроек от пользователя. Подразумевается, что при посещении сервер устанавливает cookie в браузере клиента с предпочтительным языком. Cookie называется $lang.
В конфигурации сайта пишем
map $http_accept_language $browser_lang {
default en;
~ru ru;
}
map $cookie_lang $lang {
default $browser_lang;
~en en;
~ru ru;
}
Сначала надо выделить запрос типа
/NN/*
в отдельный локейшен. Применяем регулярные выражения с выделением переменных.location ~ '^/(?<lang_code>[\D-]{2})/(?<rest_uri>.*)'
Сохраняем двухсимвольный код в переменную
$lang_code
, все остальное в переменную $rest_uri
Так же можно перенаправлять близкие языки на один существующий, например для украинской или белорусской локали лучше показать сайт на русском, чем на английском.
if ($lang_code ~* (uk|be)) {
return 301 http://$host/ru/$rest_uri$is_args$args;
}
Если код неизвестен, то используется английский вариант сайта.
if ($lang_code !~* (en|ru)) {
return 301 http://$host/en/$rest_uri$is_args$args;
}
Для if-конструкций порядок расположения имеет значение. Поэтому сначала надо ставить блок на проверку соответствия, и только в конце – на проверку несоответствия.
Далее надо очистить пользовательскую ссылку от возможного использования параметра locale в GET запросе. Неизвестно, как поведет себя back-end, если на него послать дублирующие аргументы, типа ?locale=en&locale=ru
. Поэтому если пользователь пришел со ссылкой example.com/en/?locale=ru
, то locale=ru
на back-end лучше не посылать.
if ($args ~ (.*)locale=[^&]*(.*)) {
set $args $1$2;
}
Убираем повторяющиеся амперсанды
if ($args ~ (.*)&&+(.*)) {
set $args $1&$2;
}
Убираем амперсанд в начале
if ($args ~ ^&(.*)) {
set $args $1;
}
Убираем амперсанд в конце
if ($args ~ (.*)&$) {
set $args $1;
}
Все, осталось только передать необходимые параметры на back-end. У меня в примере все идет на группу серверов, прописанных как back-end в разделе конфигурации
upstream
.proxy_pass http://back-end/$rest_uri?locale=$lang_code&$args;
Итоговая конфигурация выглядит примерно так
## get locale
map $http_accept_language $browser_lang {
default en;
~ru ru;
}
map $cookie_lang $lang {
default $browser_lang;
~en en;
~ru ru;
}
upstream back-end {
ip_hash;
server 172.21.71.15:8080; # vm-deb-osl-scala-1
server 172.21.71.16:8080; # vm-deb-osl-scala-2
server 172.21.71.17:8080; # vm-deb-osl-scala-3
server 172.21.71.18:8080; # vm-deb-osl-scala-4
keepalive 32;
}
server {
listen 109.233.59.100:80;
server_name ruvpn.net;
location / {
# Redirect to locale
return 301 http://$host/$lang$uri$is_args$args;
}
# Handle URL with locale
location ~ '^/(?<lang_code>[\w-]{2})/(?<rest_uri>.*)' {
# Redirect to Russian for some CIS countries
if ($lang_code ~* (uk|be|kk)) {
return 301 http://$host/ru/$rest_uri$is_args$args;
}
# Redirect to English for unknown languages
if ($lang_code !~* (en|ru)) {
return 301 http://$host/en/$rest_uri$is_args$args;
}
if ($args ~ (.*)locale=[^&]*(.*)) {
set $args $1$2;
}
# Cleanup any repeated & introduced
if ($args ~ (.*)&&+(.*)) {
set $args $1&$2;
}
# Cleanup leading &
if ($args ~ ^&(.*)) {
set $args $1;
}
# Cleanup ending &
if ($args ~ (.*)&$) {
set $args $1;
}
proxy_pass http://back-end/$rest_uri?locale=$lang_code&$args;
include /etc/nginx/proxy.conf;
}
Можно проверить, как это работает на реальном сайте. Как вы уже заметили из примера конфигурации, по такой схеме настроен ресурс http://ruvpn.net. Все запросы типа ruvpn.net/ru/product/details/4/ будут отображать страницу на русском, в то время как запрос ruvpn.net/sv/product/details/4/ будет переадресован на ruvpn.net/en/product/details/4/, так как шведского варианта сайта не существует. При переходе на корневую ссылку ruvpn.net, произойдет автоматическая переадресация на ruvpn.net/ru/ или ruvpn.net/en/, в зависимости от ваших языковых настроек.
Единственным недостатком описанного метода является то, что нельзя использовать ссылки с двумя символами в начале URI для чего-то отличного от выбора языка. Но это вопрос архитектуры сайта и легко решается при проектировании.
This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends: 'You Say What You Like, Because They Like What You Say' - http://www.medialens.org/index.php/alerts/alert-archive/alerts-2013/731-you-say-what-you-like-because-they-like-what-you-say.html
Комментариев нет:
Отправить комментарий