Проблемы PHP / Gettext - PullRequest
       44

Проблемы PHP / Gettext

18 голосов
/ 03 августа 2010

Я помню, как запускал несколько тестов несколько месяцев назад с 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() не возвращает 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Надежно перевести Adapter ) в различные операционные системы (возможно, с custom locales вроде 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 ]

18 голосов
/ 21 августа 2010

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 (да, очень старое образование), и вместо этого просто использует функцию __ (). Близко. И еще надежнее.

6 голосов
/ 17 августа 2010

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

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

Существует множество ошибок с setlocale,это просто ненадежно.Смотрите комментарии @ http://php.net/manual/en/function.setlocale.php

...