Самый эффективный подход для многоязычного веб-сайта PHP

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

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

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

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

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

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

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

Теперь это выглядит просто прекрасно и понятно для всех, кому нужно перевести это. Но что происходит, когда вы используете ключевые слова, как предлагает Майк, вместо полных предложений? Если кому-то нужно перевести msgid, называемую «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 может использоваться таким образом. Кроме того, если вам нужно добавлять комментарии с каждым текстом, который вы хотите отобразить, вы, возможно, сделаете ошибку в какой-то момент, b) весь скрипт будет заполнен текстами в любом случае, только в форме комментария, c) комментарии должны быть помещены непосредственно над функцией Gettext, что не всегда удобно, в зависимости от положения функции в вашем коде.

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


Другой вариант: объедините свою вторую и третью альтернативу:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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