Проблемы с PHP/Gettext

Я помню, как несколько месяцев назад запускал несколько тестов с gettext, и следующий код работал отлично:

putenv('LANG=l33t');
putenv('LANGUAGE=l33t');
putenv('LC_MESSAGES=l33t');

if (defined('LC_MESSAGES')) // available if PHP was compiled with libintl
{
    setlocale(LC_MESSAGES, 'l33t');
}

else
{
    setlocale(LC_ALL, 'l33t');
}

bindtextdomain('default', './locale'); // ./locale/l33t/LC_MESSAGES/default.mo
bind_textdomain_codeset('default', 'UTF-8');
textdomain('default');

echo _('Hello World!'); // h3110 w0r1d!

Это работало отлично (под Windows XP и CentOS, если я правильно помню), что было хорошо, потому что я мог использовать произвольные "локали", не беспокоясь, установлены ли они в системе или нет. Тем не менее, кажется, это больше не работает, интересно, почему...


Red Hat + PHP 5.2.11:

Я могу переключаться между различными локалями, и переводы показывают корректность до тех пор, пока setlocale() call не возвращает false (если локаль доступна / установлена ​​в системе).

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

Windows 7 + PHP 5.3.1 (XAMPP):

setlocale() всегда возвращает false (даже при использовании LC_ALL вместо LC_MESSAGES), если я не использую какой-либо действительный языковой стандарт Windows, такой как eng, deu или же ptg - в этом случае локаль, кажется, установлена ​​правильно, но переводы по-прежнему не отображаются. Я не могу сейчас проверить, потому что у меня открыты сотни вкладок, но я думаю, что самый первый вызов этого скрипта дает правильный перевод (перезапуск Apache не сработает).

Я не уверен, связано ли это с ошибкой PHP # 49349. Я проверю это пару часов.


Есть ли способ надежно использовать расширение gettext (а не чистые реализации PHP, такие как php-gettext или Zend Translate Adapter) в разных операционных системах (возможно, с пользовательскими локалями, такими как l33t)?

Кроме того, это абсолютно необходимо использовать setlocale(LC_ALL, ...)? Я предпочел бы оставить TIME, NUMERIC а также MONETARY (специально) настройки локали нетронуты (по умолчанию POSIX локали).


У меня была идея... Можно ли позвонить setlocale() с очень распространенным языком (например, C, POSIX или же en_US) и указать язык через домен? Что-то вроде этого:

/lang/C/LC_MESSAGES/domain.pt.mo
/lang/C/LC_MESSAGES/domain.de.mo
/lang/C/LC_MESSAGES/domain.en.mo
/lang/C/LC_MESSAGES/domain2.pt.mo
/lang/C/LC_MESSAGES/domain2.de.mo
/lang/C/LC_MESSAGES/domain2.en.mo

Будет ли это работать на платформах *nix и Windows без проблем?

2 ответа

Решение

Gettext не слишком практичен для веб-приложений.

  • Например, он сам по себе не учитывает / не использует настройки стиля Accept-Language.
  • Обычно возникают некоторые проблемы с кэшированием на общих веб-хостах (mod_php SAPI).

Так что иногда я бы хотел, чтобы модуль PHP не существовал, а удобный _() ярлык имени функции был доступен для пользовательских реализаций.
(Был мой собственный gettext.php, который работал более надежно.)

Ваши варианты:

  1. Тем не менее, согласно нескольким сообщениям об ошибках, порт Windows gettext имел некоторые недостатки с UTF-8. Возможно, на вашу версию снова повлияло. Так что постарайтесь bind_textdomain_codeset('default', 'ISO-8859-1'); для начинающих. Кроме того, кажется, что он предпочитает переменные среды в Windows IIRC, поэтому putenv("LC_ALL", "fr_FR"); может работать лучше, чем setlocale(), Особенно выполнимо, если вы позже (gettext.dll).

    Также дайте ему шанс с включением кодировки прямо там LANG=en_GB.ISO-8859-1, (Так как ваш исходный текст в любом случае английский, забота о кодировке здесь не очень актуальна; но, вероятно, распространенный случай, когда gettext срабатывает сам по себе.) О, а иногда это UTF8, а не UTF-8; также попробуйте ASCII.

  2. Альтернативно обойти gettext. Идея вашего домена близка, но я бы просто использовал предопределенный./locale/ subdir для языков:

    ./lang/en/locale/C/LC_MESSAGES/domain.mo
    

    Тогда просто вызовите bindtextdomain("default", "./lang/{$APP_LANG}/locale") не давая gettext возможности интерпретировать многое. Он всегда будет искать /C/, но правильный каталог локали уже введен. Но все равно попробуйте использовать символическую ссылку из $LANG в / C /.

  3. Укус в гну. Откажись от gettext. "PhpWiki" имел собственный скрипт конвертации в awk. Он преобразует файлы.po в сценарии массива.php (да, очень старое образование) и просто использует вместо него функцию __(). Близко. И более надежный.

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

Если вам нужна согласованность, вам нужно использовать что-то вроде Zend_Translate, которое, если вы установите Zend в каждой системе (одну и ту же версию), все они будут согласованы друг с другом, потому что они используют одни и те же данные локализации, имена локалей и кодовую базу.

Есть многочисленные ошибки с setlocaleПросто это не надежно. Смотрите комментарии @ http://php.net/manual/en/function.setlocale.php

Другие вопросы по тегам