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

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

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

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

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

3 ответов


несколько вопросов:

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

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


другой вариант: объединить 2-й и 3-й вариант:

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

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

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

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

плюсы:

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

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

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

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


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

проблема Gettext
Я попытался сначала настроить всю gettext-систему, чтобы опробовать ее, но она оказалась намного сложнее, чем я думал. Проблема в том, что Windows и системы Unix используют разные языковые сокращения для setlocale (). На данный момент я запускаю свой dev-сервер Окна с ПУВР, в то время как окончательный сайт будет работать на Linux. После того, как я прошел через пару десятков справочники, форумы, вопросы etc. и перезапуск сервера после каждой модификации. Я не мог правильно настроить его каким-либо простым способом. Кроме того, gettext не является threadsafe, для обновления языкового файла необходимо перезапустить сервер или взлом необходимо использовать, нет простого способа обработка различных версий языковых файлов или обработка оригинального текста на английском языке без изменения источника или использования предложения Mikes, что, как отметил Алек, не является оптимальным.

решение
Поэтому я закончил тем, что я считаю лучшим решением, основанным на ответе Alecs:

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

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

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

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


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

gettext ключ "привет"

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