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


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

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

В конце мне просто нужна функция, которая ищет перевод в файл (один файл по языку). ЭКВИВАЛЕНТ : trans('hello');

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

hello: "Hello world!"

= > фр.ямл

hello: "Bonjour tout le monde !"

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

4 11

4 ответа:

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

Если вам нужен только перевод и сайт достаточно прост, возможно, ваше простое решение (чтение файла конфигурации перевода в 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 (например, форматирование чисел)

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