Веб-приложение Java i18n - PullRequest
       1

Веб-приложение Java i18n

8 голосов
/ 23 июня 2011

Мне дали (довольно устрашающую) задачу ввести i18n в веб-приложение J2EE с использованием спецификации сервлета 2.3. Приложение очень большое и находится в активной разработке более 8 лет.

Поэтому я хочу, чтобы все было правильно с первого раза, чтобы я мог ограничить время, необходимое для просмотра JSP, файлов JavaScript, сервлетов и т. Д., Заменяя жестко запрограммированные строки значениями из пакетов сообщений.

Здесь не используется фреймворк. Как мне подойти к поддержке i18n. Обратите внимание, что я хочу иметь один JSP для каждого представления, который загружает текст из файла (ов) свойств, а не разные JSP для каждой поддерживаемой локали.

Я предполагаю, что мой главный вопрос заключается в том, могу ли я установить локаль где-нибудь в «бэкэнде» (то есть прочитать локаль из профиля пользователя при входе в систему и сохранить значение в сеансе), а затем ожидать, что страницы JSP смогут правильно загрузить указанная строка из правильного файла свойств (т. е. из messages_fr.properties, когда языковой стандарт является французским), в отличие от добавления логики для поиска правильного языкового стандарта в каждой JSP.

Есть идеи, как мне к этому подойти?

Ответы [ 3 ]

19 голосов
/ 23 июня 2011

Есть много вещей, о которых нужно позаботиться при интернационализации приложения:

Определение локали

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

  1. Как вы наверняка знаете, веб-браузеры, как правило, отправляют предпочтительный язык конечного пользователя через заголовок HTTP Accept-Language.Доступ к этой информации в сервлете может быть таким же простым, как вызов request.getLocale().Если вы не планируете поддерживать какой-либо изящный рабочий процесс Locale Detection , вы можете просто придерживаться этого метода.
  2. Если у вас есть пользовательские профили в вашем приложении, вы можете добавить предпочитаемый язык иПредпочтительный язык форматирования к нему.В таком случае вам потребуется переключить Locale после входа пользователя в систему.
  3. Возможно, вы захотите поддержать переключение языка на основе URL (например: http://deutsch.example.com/ или http://example.com? Lang =де ).Вам может потребоваться установить действительный языковой стандарт на основе информации URL-адреса - это можно сделать различными способами (например, URL-фильтр).
  4. Возможно, вы захотите поддержать переключение языка (выберите его в раскрывающемся меню или что-то еще)Однако я бы не рекомендовал его (если только он не объединен с пунктом 3).

JSTL может быть достаточным, если вы просто хотите сначала поддержатьили если вы не планируете добавлять какие-либо дополнительные зависимости (например, Spring Framework).

Пока мы находимся на Spring Framework , у него есть довольно много приятных функций, которыеВы можете использовать оба для обнаружения Locale (например, CookieLocaleResolver , AcceptHeaderLocaleResolver , SessionLocaleResolver и LocaleChangeInterceptor ) и экранирование строк и сообщений форматирования (см.1045 * spring: вкладка сообщения ).
Spring Framework позволит вам довольно легко реализовать все вышеописанные сценарии, поэтому я предпочитаю его.

Экстернализация строки

Это должно быть легко, верно?Ну, в основном это так и есть - просто используйте соответствующий тег.Единственная проблема, с которой вы можете столкнуться, - это когда речь идет об экстернализации клиентских (JavaScript) текстов.Есть несколько возможных подходов, но позвольте мне упомянуть эти два:

  1. Каждый JSP записывает массив переведенных строк (с тегом сообщения) и просто обращается к этому массиву в коде клиента.Это более простой подход, но менее обслуживаемый - вам нужно будет на самом деле написать действительные строки из допустимых страниц (те, которые фактически ссылаются на ваши клиентские скрипты).Я делал это раньше и, поверьте мне, это не то, что вы хотите делать в больших приложениях (но, вероятно, это лучшее решение для небольших приложений).
  2. Другой подход может показаться сложным в принципе, но на самом делелегче справиться в будущем.Идея состоит в том, чтобы централизовать строки на стороне клиента (переместить их в какой-нибудь общий файл JavaScript).После этого вам нужно будет реализовать свой собственный сервлет, который будет возвращать этот скрипт по запросу - содержимое должно быть переведено.Вы не сможете использовать JSTL здесь, вам нужно будет напрямую получать строки из Resource Bundles.
    Гораздо проще поддерживать, потому что у вас будет одна центральная точка для добавления переводимых строк.

Конкатенации

Мне неприятно это говорить, но конкатенации действительно болезненны с точки зрения локализуемости.Они очень распространены, и большинство людей не осознают этого.

Так что же такое конкатенация?

По принципу каждое английское предложение должно быть переведено на целевой язык.Проблема в том, что часто бывает, что правильно переведенное сообщение использует другой порядок слов, чем его английский аналог (поэтому английский «Политика безопасности» переводится на польский «Polityka bezpieczeństwa» - «policy» - это «polityka» - порядок другой).

ОК, но как это связано с программным обеспечением?

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

String securityPolicy = "Security " + "policy";

или как это:

<p><span style="font-weight:bold">Security</span> policy</p>

И то, и другое было бы проблематично. В первом случае вам нужно будет использовать метод MessageFormat.format() и экстернализировать строки как (например) "Security {0}" и "policy", во втором случае вы будете выводить содержимое всего абзаца (тег p), , включая тег span. Я знаю, что это болезненно для переводчиков, но лучшего пути нет.
Иногда вам нужно использовать динамический контент в вашем абзаце - вам также поможет тег JSTL fmt: format (он работает на MessageFormat со стороны сервера).

Макеты

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

  1. Исправляйте проблемы, когда они возникают, корректируя общие стили (и молитесь, чтобы это не нарушало другие языки). Это очень больно поддерживать.
  2. Реализация механизма локализации CSS. Механизм, о котором я говорю, должен обслуживать стандартные, независимые от языка CSS-файлы и переопределения для каждого языка. Идея состоит в том, чтобы переопределить CSS-файл для каждого языка, чтобы вы могли настроить макеты по требованию (только для одного языка). Для этого файл CSS по умолчанию, а также страницы JSP не должны содержать ключевое слово !important рядом с определениями стилей. Если вам действительно нужно его использовать, переместите их в языковой en.css - это позволит другим языкам изменять их.

Вопросы культуры

Избегайте использования графики, цветов и звуков, которые могут быть специфическими для западной культуры. Если вам это действительно нужно, предоставьте средства локализации. Избегайте чувствительной к направлению графики (так как это будет проблемой при локализации, скажем, на арабском или иврите). Кроме того, не думайте, что весь мир использует одни и те же цифры (т. Е. Это не относится к арабскому языку).

Даты и часовые пояса

Обработка дат во времени в Java, мягко говоря, непростая. Если вы не собираетесь поддерживать ничего, кроме григорианского календаря, вы можете придерживаться встроенных классов Date и Calendar. Вы можете использовать JSTL fmt: timeZone, fmt: formatDate и fmt: parseDate для правильной установки часового пояса, формата и даты разбора в JSP.

Я настоятельно рекомендую использовать fmt: formatDate следующим образом:

<fmt:formatDate value="${someController.somedate}" 
    timeZone="${someController.detectedTimeZone}"
    dateStyle="default" 
    timeStyle="default" />

Важно перевести дату и время в действительный (конечный пользователь) часовой пояс. Также очень важно преобразовать его в легко понятный формат - вот почему я рекомендую стиль форматирования по умолчанию.
КСТАТИ. Обнаружение часового пояса не так-то просто, так как веб-браузеры не так хороши, чтобы отправлять что-либо Вместо этого вы можете либо добавить поле предпочтительного часового пояса в настройки пользователя (если оно у вас есть), либо получить смещение текущего часового пояса из веб-браузера через скрипт на стороне клиента (см. Методы объекта Date )

Числа и валюты

Числа, а также валюты должны быть переведены в местный формат. Это делается аналогично форматированию дат (разбор также выполняется аналогично):

<fmt:formatNumber value="1.21" type="currency"/> 

Составные сообщения

Вас уже предупредили не объединять строки. Вместо этого вы, вероятно, будете использовать MessgageFormat. Однако я должен заявить, что вы должны минимизировать использование составных сообщений. Это просто потому, что целевые грамматические правила довольно часто отличаются, поэтому переводчикам может потребоваться не только переупорядочить предложение (это можно решить с помощью заполнителей и MessageFormat.format()), но и перевести все предложение по-разному в зависимости от того, что будет быть замененным. Позвольте привести несколько примеров:

// Multiple plural forms
English: 4 viruses found.
Polish: Znaleziono 4 wirusy. **OR** Znaleziono 5 wirusów.

// Conjugation
English: Program encountered incorrect character | Application encountered incorrect character.
Polish: Program napotkał nieznaną literę | Aplikacja napotkała nieznaną literę.

Кодировка символов

Если вы планируете локализацию на языки, которые не поддерживают кодовую страницу ISO 8859-1, вам нужно будет поддерживать Unicode - лучший способ - установить кодировку страницы в UTF-8. Я видел людей, делающих это так:

<%@ page contentType="text/html; charset=UTF-8" %>

Я должен предупредить вас: это недостаточно . Вам действительно нужно это объявление:

<%@page pageEncoding="UTF-8" %>

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

<META http-equiv="Content-Type" content="text/html;charset=UTF-8"> 

Список, который я вам дал, не является исчерпывающим, но это хорошая отправная точка. Удачи :)

1 голос
/ 23 июня 2011

Вам не нужно (и не нужно) иметь отдельный файл JSP для каждой локали.Сложная задача - выяснить ключи, которые не помечены как i18n-ed, и переместить их в файл для каждой локали, скажем, messages_en.properties, messages_fr.properties и т. Д.

Расчет локали может происходить в нескольких местах в зависимости отпо твоей логике.Мы поддерживаем локали пользователей, хранящиеся в базе данных, а также локали браузера.Каждый запрос, поступающий в ваше приложение, будет иметь заголовок «Accept-Language», который указывает, на каких языках настроен ваш браузер, с настройками, т.е. сначала японский, а затем английский.Если это так, приложение должно прочитать messages_ja.properties, а для ключей, которых нет в этом файле, вернуться к messages_en.properties.То же самое можно сказать и о пользовательских локалях, которые хранятся в базе данных.Обратите внимание, что стандарт состоит в том, чтобы просто переключать язык в браузере и ожидать, что контент будет i18n-ed.(Сначала мы начали с сохранения локали в базе данных, а затем перешли на поддержку локали из браузера).Кроме того, вам все равно понадобится значение по умолчанию, поскольку переводчики пропускают копирование ключей и значений с английского (файл основного языка) на другие языки, поэтому вам нужно будет установить значение по умолчанию на английском для значений, которых нет в других файлах.

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

1 голос
/ 23 июня 2011

Вы можете сделать это, используя стандартную библиотеку тегов JSTL с тегом.Возьмите копию спецификации JSTL, прочитайте главы i8N, в которых обсуждается общий текст + дата, время, валюта.Очень четко написано и показывает, как вы можете сделать все это с помощью тегов.Вы также можете установить такие вещи, как Locale программно

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...