Наиболее эффективный подход для многоязычного сайта PHP - PullRequest
25 голосов
/ 11 мая 2010

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

  1. Gettext работает с генерацией .po файлов
  2. Одна таблица MySQL с переводами и уникальным идентификатором строки для каждого текста
  3. PHP-файлы с массивами, содержащими разные переводы с уникальными строковыми идентификаторами

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

Какое наименее ресурсоемкое решение?
Требует ли использование функций Gettext или PHP-файлов с массивами более или менее равные ресурсы?
Любые другие предложения для более эффективных решений?

Ответы [ 3 ]

26 голосов
/ 11 мая 2010

Несколько соображений:

1. Переводы
Кто будет делать переводы? Люди, которые тоже подключены к сайту? Бюро переводов? При использовании Gettext вы будете работать с файлами '.po'. Эти файлы содержат идентификатор сообщения и строку сообщения (перевод). Пример:

msgid "A string to be translated would go here"  
msgstr ""

Теперь это выглядит прекрасно и понятно для всех, кому нужно перевести это. Но что происходит, когда вы используете ключевые слова, как предлагает Майк, вместо полных предложений? Если кому-то нужно перевести сообщение с именем «address_home», он или она не имеет понятия, должен ли это быть заголовок «Домашний адрес» или что это полное предложение. В этом случае обязательно добавьте комментарии к файлу непосредственно перед вызовом функции gettext, например:

/// This is a comment that will be included in the pot file for the translators
gettext("ready_for_lost_episode");

Использование xgettext --add-comments=/// при создании файлов .po добавит эти комментарии. Тем не менее, я не думаю, что Gettext может быть использован таким образом. Кроме того, если вам нужно добавить комментарии с каждым текстом, который вы хотите отобразить, вы а) возможно, допустите ошибку в какой-то момент, б) ваш сценарий будет заполнен текстами в любом случае, только в форме комментария, в) комментарии должны быть размещены непосредственно над функцией Gettext, что не всегда удобно, в зависимости от положения функции в вашем коде.

2. Техническое обслуживание
Как только ваш сайт вырастет (даже дальше) и ваши языковые файлы вместе с ним, может быть довольно сложно поддерживать все различные переводы таким образом. Каждый раз, когда вы добавляете текст, вам нужно создать новые файлы, отправить файлы переводчикам, получить файлы обратно, убедиться, что структура все еще не повреждена (нетерпеливые переводчики всегда рады перевести и синтаксис, создавая весь файл). непригодный для использования :)), и закончите с импортированием новых переводов. Конечно, это выполнимо, но имейте в виду возможные проблемы на этом уровне с большими сайтами и множеством разных языков.

<ч /> Другой вариант: объедините ваш второй и третий вариант:

Лично я считаю более полезным управлять переводом с помощью (простой) CMS, хранить переменные и переводы в базе данных и самостоятельно экспортировать соответствующие тексты в языковые файлы:

  1. добавить переменные в базу данных (например, id, page, variable);
  2. добавить переводы к этим переменным (например, id, varId, language, translation);
  3. выбрать соответствующие переменные и переводы, записать их в файл;
  4. включить соответствующий языковой файл на вашем сайте;
  5. создайте свою собственную функцию для отображения текста переменных:

text('var'); или, может быть, что-то вроде __('faq','register','lost_password_text');

Точка 3 может быть такой же простой, как выбор всех соответствующих переменных и переводов из базы данных, помещение их в массив и запись сериализованного массива в файл.

Преимущества:

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

  2. Транслейтинг. Вы можете отобразить переменную со всеми переводами всех разных языков на одной странице. Это может быть полезно для людей, которые могут переводить тексты на несколько языков одновременно. И было бы полезно увидеть другие переводы, чтобы понять контекст, чтобы перевод был как можно лучше. Вы также можете запросить базу данных, чтобы узнать, что было переведено, а что нет. Возможно, добавьте метки времени, чтобы отслеживать возможные устаревшие переводы.

  3. Доступ. Это зависит от того, кто будет переводить. Вы можете обернуть CMS простым логином, чтобы предоставить доступ к людям из бюро переводов, если это необходимо, и разрешить им изменять только определенные языки или даже определенные части сайта. Если это не вариант, вы все равно можете вывести данные в файл, который можно перевести вручную и импортировать позже (хотя это может привести к тем же проблемам, что и упомянутые ранее). Вы можете добавить один из уже переведенных переводов (английский или другой основной язык) в качестве контекста для переводчика.

В целом, я думаю, вы обнаружите, что таким образом у вас будет намного больше контроля над переводами, особенно в долгосрочной перспективе. Я не могу вам ничего сказать о скорости или эффективности этого подхода по сравнению с нативной функцией gettext. Но, в зависимости от размера языковых файлов, я не думаю, что это будет большой разницей. Если вы группируете переменные по странице или разделу, вы всегда можете включить только необходимые части.

13 голосов
/ 17 мая 2010

После некоторого тестирования я, наконец, решил более или менее использовать линии комбинации Алекса для второго и третьего варианта.

Проблема Gettext
Сначала я попытался настроить всю систему gettext, но она оказалась намного сложнее, чем я думал. Проблема в том, что Windows и системы Unix используют разные языковые сокращения для setlocale () . На данный момент я использую свой dev-сервер в Windows с Wamp , а последний сайт будет работать под Linux. После того, как я прошел через несколько дюжин руководств , форумов , вопросов и т. Д. И перезапускал сервер после каждой модификации. Я не мог настроить его так просто, как мне казалось. Кроме того, gettext не является потокобезопасным: для обновления языкового файла необходимо перезапустить сервер или использовать хак , нет простого способа обработки различных версий языковых файлов или обработки исходного текста на английском языке без изменение источника или использование предложения Майка, которое, как указал Алек, не является оптимальным.

Решение
Таким образом, я нашел лучшее решение, основанное на ответе Алекса:

  • Сохранить все переводы в БД с полями; language, page, var_key, version, revision и last_modified_time - где версия соответствует версии исходного перевода (на английском языке), а revision позволяет переводчику изменять / исправлять окончательные переводы в пределах версии.
  • Используйте для перевода своего рода CMS, который подключен к БД и обрабатывает разные версии и позволяет легко просматривать, какие языки переведены, в какую версию и насколько завершены переводы.
  • Когда доработка версии завершена, создаются файлы кэша - каждый файл содержит массив только с ключом var_key и text-translation для одного языка и одной страницы и именуется ISO 639-1 названия языков и имя страницы, такие как: lang / en_index.php. Эти языковые файлы затем просто включаются и оборачиваются в функцию t ($ var_key), которая позволяет использовать БД во время разработки, а затем изменяется только на использование кеш файлов.

Производительность
Я никогда не удосужился протестировать gettext, но согласно ссылке, которую Майк опубликовал , разница в производительности между использованием массива и gettext полностью приемлема для меня, поскольку преимущества пользовательской системы дают, как описано выше. Однако я сравнил использование массива с 20 переведенными текстовыми строками в массиве по сравнению с извлечением тех же 20 текстовых строк из MySQL DB . Оказалось, что использование массива, включенного в файл, было в 6 раз быстрее , чем одновременное извлечение всех 20 строк из БД MySQL. Это не был действительно научный эталон, и результаты, безусловно, могут отличаться в разных системах и настройках, но он четко показывает, что я ожидал - что использование БД будет намного медленнее, чем использование массива напрямую, поэтому я решил сгенерировать кэш -файлы для массива вместо использования БД.

В качестве сравнения я также проверил, насколько быстро было выводить только простые эхо-сигналы с тем же текстом. Оказалось, что это примерно в 20 раз быстрее, чем использование массивов из включенного файла, но хорошо - тогда невозможно выполнить перевод, не имея разных версий страницы для разных языков, что не соответствует назначению динамических страниц. Тогда лучше также использовать хорошую кэшированную систему .

Исходные файлы теста производительности:
PHP: http://pastie.org/964082
Таблица MySQL: http://pastie.org/964115
Это, конечно, не идеально, но по крайней мере создает представление о различиях в производительности.

3 голосов
/ 11 мая 2010

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

ключ gettext - «привет»

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

...