Лучший способ интернационализации простого 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 без фреймворка, поэтому любые советы о том, какой Самый простой способ поддерживать мультиязычность ?
В конце мне просто нужна функция, которая ищет перевод в файл (один файл по языку).
ЭКВИВАЛЕНТ :
trans('hello');
= > ru.ямл (ямл или нет, это пример)
hello: "Hello world!"
= > фр.ямл
hello: "Bonjour tout le monde !"
И если возможно, я предпочитаю чистые реализации PHP
4 ответа:
Хотя
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!');
Я знаю, что это старый вопрос, но я чувствую, что ответы не имеют более практического подхода от начала до конца. Вот что я сделал, чтобы заставить перевод работать с помощью библиотеки PHP
gettext
и Poedit без использования каких-либо дополнительных библиотек PHP на сервере Debian:Шаг подготовки 1: Установите
gettext
и локали на сервереЯ не уверен, как это делается с другими операционными системами, но для Debian, вы do:
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
на любой другой, но вам придется изменить его в приведенном ниже скрипте оболочки. важно : примечание переводчика должно быть частью прокомментируйте строку , непосредственно предшествующую функции__()
, иначе она не будет обнаружена при сканировании 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 в этом каталоге и создаст файл
Затем нам нужно создать каталоги, в которых будут храниться все файлы локали, по одному для каждой локали. Они должны иметь формат.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-это то, что вам нужно. Существует файл по языку (кроме оригинального), и он очень прост в использовании:
echo _('Bonjour, ça va ?');
Напечатает Привет, как дела ? по-английски.
Есть некоторые инструменты с gettext, которые могут сканировать ваш php-файл и искать переводимую строку (фактически всю строку в _() или gettext()). Благодаря этому Вам не придется беспокоиться о другом файле langage. Вы просто код свой сайт в исходном языке и языке файл будет автоматически создан позже.
Тем не менее gettext-это скорее инструмент перевода, тогда как intl-это действительно i18n (например, форматирование чисел)