Лучший способ интернационализации простого сайта PHP - PullRequest
14 голосов
/ 05 августа 2011

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

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

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

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

hello: "Hello world!"

=> fr.yaml

hello: "Bonjour tout le monde !"

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

Ответы [ 4 ]

19 голосов
/ 05 августа 2011

Хотя 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!');
13 голосов
/ 02 июля 2015

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

Подготовительный шаг 1:Установите gettext и локали на сервере

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

sudo apt-get install gettext
sudo dpkg-reconfigure locales

Редактировать : Я предполагал, что 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 просто выполните:

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 необходимо повторно загрузить.

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

3 голосов
/ 05 августа 2011

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

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

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

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

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

1 голос
/ 05 августа 2011

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

...