Лучший способ интернационализации простого PHP-сайта

Я должен разработать довольно простой php-сайт, поэтому мне не нужна инфраструктура. Но он должен поддерживать несколько языков (EN / FR / CHINESE). Я искал PHP, встроенный в систему, и нашел два способа:

  • intl от php5.3 ( http://php.net/manual/fr/book.intl.php )
  • gettext ( http://php.net/manual/fr/book.gettext.php )

У меня нет опыта работы в i18n без рамки, поэтому любые советы о том, что является самым простым способом поддержки нескольких языков?

В конце мне просто нужна функция, которая ищет перевод в файл (один файл по языку). EQ: trans('hello');

=> en.yaml (yaml или нет, это пример)

 hello: "Hello world!" 

=> fr.yaml

 hello: "Bonjour tout le monde !" 

И, если возможно, я предпочитаю реализацию Pure PHP

Solutions Collecting From Web of "Лучший способ интернационализации простого PHP-сайта"

Хотя ext/gettext и ext/intl связаны с i18 (интернационализация), gettext имеет дело с переводом, в то время как intl занимается интернационализацией таких вещей, как отображение количества и даты, порядок сортировки и транслитерация. Таким образом, вам действительно понадобится как полное i18-решение. В зависимости от ваших потребностей вы можете придумать решение для домашнего приготовления, основанное на упомянутых выше расширениях или на ваших используемых компонентах, которые предоставляются в некоторых рамках:

  • Перевод
  • интернационализация
    • Zend Framework Zend_Locale

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

Самое простое решение, о котором я могу думать, это:

 $translation = array( 'Hello world!' => array( 'fr' => 'Bonjour tout le monde!', 'de' => 'Hallo Welt!' ) ); if (!function_exists('gettext')) { function _($token, $lang = null) { global $translation; if ( empty($lang) || !array_key_exists($token, $translation) || !array_key_exists($lang, $translation[$token]) ) { return $token; } else { return $translation[$token][$lang]; } } } echo _('Hello World!'); 

Я знаю, что это старый вопрос, но я чувствую, что ответы не имеют более практического подхода от начала до конца. Это то, что я сделал, чтобы получить перевод с использованием библиотеки gettext PHP и Poedit без использования каких-либо дополнительных библиотек PHP на сервере Debian:

Шаг 1 подготовки: установите gettext и локали на сервере

Я не уверен, как это делается с другими операционными системами, но для Debian вы делаете:

 sudo apt-get install gettext sudo dpkg-reconfigure locales 

Edit : Я предположил, что Ubuntu будет таким же, как Debian, но, по-видимому, он немного отличается. Инструкции по установке локалей на Ubuntu см. На этой странице .

Убедитесь, что вы выбрали все локали, которые хотите использовать. Затем вы должны увидеть что-то вроде:

 Generating locales (this might take a while)... en_US.UTF-8... done es_MX.UTF-8... done fr_FR.UTF-8... done zh_CN.UTF-8... done Generation complete. 

Примечание. Убедитесь, что вы выбрали правильные варианты и кодировки символов (скорее всего, UTF-8) для каждого языка. Если вы установите es_MX.UTF-8 и попытаетесь использовать es_ES.UTF-8 или es_MX.ISO-8859-1 это не сработает.

Шаг подготовки 2: Установите Poedit на компьютеры переводчиков

Poedit доступен из репозитория программного обеспечения для большинства операционных систем Linux. Для Debian-based просто выполните:

 sudo apt-get install poedit 

Для Windows и Mac перейдите по адресу : https://poedit.net/download


Начало кодирования:

Хорошо, теперь вы готовы начать кодирование. Я написал следующую функцию gettext() для перевода как сингулярных, так и множественных чисел:

 function __($text, $plural=null, $number=null) { if (!isset($plural)) { return _($text); } return ngettext($text, $plural, $number); } 

Пример использования:

 // Singular echo __('Hello world'); // Plural $exp = 3; printf( __( 'Your account will expire in %d day', 'Your account will expire in %d days', $exp ), $exp ); 

Это будет работать на всех языках, а не только на языках, где множественное число есть где-нибудь, где n != 1 – это языки с несколькими множественными типами.

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

 /** NOTE: The name Coconut Hotel is a brand name and shouldn't be translated. */ echo __('Welcome to Coconut Hotel'); в /** NOTE: The name Coconut Hotel is a brand name and shouldn't be translated. */ echo __('Welcome to Coconut Hotel'); 

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

 // Warning! THIS WILL NOT WORK! /* NOTE: This translator's note will not be picked up because it is not immediately preceding the __() function. */ printf( __( 'Your account will expire in %d day', 'Your account will expire in %d days', $exp ), $exp ); // Warning! THIS WILL NOT WORK! 

После того, как вы готовы отправить строки переводчикам, сохраните следующий сценарий оболочки (например, update.sh) в корневом каталоге приложения:

 #!/bin/sh find . -iname "*.php" | xargs xgettext --add-comments=NOTE --keyword=__:1,2 --keyword=__ --from-code=UTF-8 -o i18n.pot find . -name '*.po' | xargs -I{} msgmerge -U {} i18n.pot 

Чтобы выполнить его, просто выполните:

 cd /path/to/script && sh update.sh 

Это будет рекурсивно сканировать все файлы PHP в этом каталоге и создать файл i18n.pot (я назвал его i18n.pot , но не стесняйтесь называть его как угодно) и обновлять любые существующие файлы .po которые он находит с новыми строками.

Затем нам нужно создать каталоги, в которых будут храниться все файлы локали, по одному для каждого языкового стандарта. Они должны быть формата ./locale/{locale}/LC_MESSAGES . Например:

 cd /path/to/your/project mkdir -p ./locale/en_US.UTF-8/LC_MESSAGES mkdir -p ./locale/es_MX.UTF-8/LC_MESSAGES # ...etc. 

Вам нужно выбрать текстовый домен для использования. Это может быть все, что вы хотите, но сценарий будет искать файл с именем {yourTextDomain}.mo в папке LC_MESSAGES для этого языка. Добавьте в свой PHP-скрипт следующее:

 define('TEXT_DOMAIN', 'yourdomain'); bindtextdomain(TEXT_DOMAIN, __DIR__.'/locale'); textdomain(TEXT_DOMAIN); bind_textdomain_codeset(TEXT_DOMAIN, 'UTF-8'); 

Затем, чтобы перейти на другой язык, выполните следующие действия:

 $lang = 'es_MX.UTF-8'; // Change this to the language you want to use if (setlocale(LC_ALL, $lang) === false) { throw new Exception("Server error: The $lang locale is not installed"); } putenv('LC_ALL='.$lang)); 

Первоначально вы отправляете файл .pot сгенерированный сценарием выше, переводчикам. Затем они открывают Poedit и нажимают на File > New from POT/PO file . Когда они сохраняют его, они должны сохранять его как {yourTextDomain}.po . {yourTextDomain} должен быть точно таким же, как текстовый домен, который у вас есть в вашем PHP-скрипте. Когда они сохранят его, он автоматически создаст файл .po файл .mo . Оба они должны быть сохранены в каталоге LC_MESSAGES этого языка, когда они будут переведены.

Теперь, когда вы обновляете строки в своем PHP-файле, просто заново запустите сценарий оболочки и отправьте обновленные файлы .po переводчикам. Затем они переводят строки, и файлы .po и .mo необходимо повторно загрузить.

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

Gettext кажется тем, что вам нужно. Существует файл langage (кроме оригинального), и он очень прост в использовании:

 echo _('Bonjour, ça va ?'); 

будет печатать Привет, как дела? на английском.

Есть несколько инструментов с gettext, которые могут сканировать ваш php-файл и искать переводимую строку (на самом деле все строки в _ () или gettext ()). Благодаря этому вам не нужно беспокоиться о разных файлах langage. Вы просто кодируете свой сайт в оригинальном langage, и файл langage будет автоматически создан позже.

Тем не менее gettext – это больше инструменты перевода, тогда как intl действительно является i18n (например, для форматирования чисел)

Хотя вам не нужна фреймворк, вы можете использовать фреймворк. Функции интернационализации в Zend Framework довольно хороши, и вы можете просто использовать эту часть, а не использовать все части (включая MVC)