Gettext всегда будет использовать язык системы по умолчанию

мне нужно локализовать веб-приложение PHP только для Windows, и я оцениваю расширение gettext версии но у меня самое трудное время, пытаясь заставить его работать в моем окне разработки Windows 7. Я использовал метод проб и ошибок вместе с Контролировать Процесс чтобы преодолеть плохую и неточную документацию, и мне удалось сделать _() отображение строк из *.каталог po, соответствующий языковому стандарту компьютера по умолчанию (современный испанский в моем случае). все мои попытки установить другую локаль молча игнорируются.

Я написал тестовый сценарий с большим количеством избыточных вещей:

<dl><?php

define('DIR_LOCALE', __DIR__ . DIRECTORY_SEPARATOR . 'locale');
bindtextdomain('general', DIR_LOCALE);
bind_textdomain_codeset('general', 'UTF-8');
textdomain('general');

if(!defined('LC_MESSAGES')){
    define('LC_MESSAGES', 5);
}

$pruebas = array(
    'enu',
    'es_ES',
    'en_GB',
    'english-uk',
    'Spanish_Spain.1252',
    'esn',
    'spanish',
    'spanish-modern',
);
foreach($pruebas as $locale){
    putenv("LC_ALL=$locale");
    setlocale(LC_ALL, $locale);

    putenv("LC_MESSAGES=$locale");
    setlocale(LC_MESSAGES, $locale);

    putenv("LANGUAGE=$locale");
    putenv("LANG=$locale");
?>
    <dt><?=htmlspecialchars($locale)?></dt>
    <dd><?=_('codigo_idioma')?></dd>
<?php } ?>
</dl>

в моем случае, <?=_('codigo_idioma')?> всегда печатает es_ES@modern.

у меня есть PHP / 5.4.5, но я ожидаю, что он будет работать на любом достаточно современном сервере, которым владеют наши клиенты.

Я прочитал много неопределенных ссылок о необходимости установки локали даже на Windows, но никаких точных деталей. что может ли быть проблема?

(я знаю, что общий совет-сбросить gettext и использовать любую другую библиотеку.)


дальнейшие испытания:

мой код работает безупречно, как на двух других компьютерах: 32-разрядная Windows Vista и 32-разрядная Windows 7 32-разрядная. Он терпит неудачу на моем компьютере (64-разрядная Windows 7) и еще один (32-разрядная Windows Server 2003)

  • версия Apache кажется не имеет значения (это также происходит с интерпретатором командной строки).
  • версия PHP кажется нерелевантной (также пробовал последний 32-битный PHP/5.5.5 на моем ПК).
  • мой [HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlNls] дерево реестра идентично другим семи окнам.

Edit: во время тестирования в командной строке я обнаружил, что установка LANG переменная окружения перед запуском скрипта PHP окончательно меняет язык:

C:>set LANG=en_GB
C:>php C:testgettext.php

это окончательно доказывает, что мой компьютер имеет правильные активы, но также заставляет меня задаться вопросом, почему PHP не утверждает, что putenv() работает, а затем игнорирует его:

var_dump( getenv('LANG'), putenv('LANG=en_GB'), getenv('LANG') );
bool(false)
bool(true)
string(5) "en_GB"

даже это не имеет никакого эффекта:

$_ENV['LANG'] = 'en_GB';
$_SERVER['LANG'] = 'en_GB';

6 ответов


Это вопрос это было признано и частично исправлено командой PHP.

Это довольно техническая вещь, по-видимому, связанная с тем, как переменные среды (от которых сильно зависит gettext) обрабатываются базовой платформой. Кроме того, что-то изменилось в библиотеках среды выполнения Visual C от VC9 до VC11, что влияет на все это.

подведем итоги:

  • не потокобезопасные сборки были исправлены в исходное дерево на 21st ноября. 2014.
  • Потокобезопасные сборки (например, модуль Apache) не имеют и нет четкого решения в поле зрения.

ключ используйте не потокобезопасную (=NTS) версию PHP.

к сожалению, Windows и PHP плохо обрабатывают среды для потоковых процессов, поэтому putenv ('LC_ALL='.$locale); команда не работает.

наконец, я заканчиваю Apache 2.4 + FCGID + PHP 7.1 NTS, который хорошо работает теперь в Windows 7, и это не потокобезопасная установка.

пошаговая инструкция по установке такой системы находится здесь: https://www.youtube.com/watch?v=UXrJPrGaPB0

Я использовал версии VC14 и x64 для всех компонентов (VC является аббревиатурой для "Microsoft Visual C++ Redistributable"). Для этого я сначала установил VC14, скачал отсюда:https://www.microsoft.com/en-us/download/details.aspx?id=48145


У меня была такая же проблема с PHP 5.6.30 VC11 Theard Safe на Windows 10. Обходной путь найден и исправить эту проблему здесь по sirio3mil.

по-видимому, PHP с TS может получить доступ только к папке языка локали. Поэтому, когда функция setlocale и putenv вызывает другой язык, чем системный, папка С. МО и .по не может быть прочитан.

обходной путь должен иметь только одну языковую папку с системным языком и несколькими парами .МО/.po-файлы для каждого переведенного языки. Домен будет установлен с требуемым языком.

пример со швейцарским французским, немецким и итальянским:

структура папок

\Locale\fr_CH\LC_MESSAGES

  • fr_CH.mo + fr_CH.po / / язык системы
  • de_CH.mo + de_CH.по!--18-->
  • it_CH.mo + it_CH.по!--18-->

код

$lang = 'fr_CH' or 'de_CH' or 'it_CH'

bindtextdomain($lang, '.\Locale');
textdomain($lang);
bind_textdomain_codeset($lang, 'UTF-8');
setlocale (LC_ALL, $lang);
putenv('LC_ALL=' . $lang);

первая проблема: setlocale ()

чтобы сделать эту работу, вам нужно установить допустимый язык. В windows setlocale () не будет работать должным образом. Вам нужно установить переменную среды, например:

// putenv("LANG=$lang");  <- WRONG!
putenv('LC_ALL='.$locale);

вторая проблема: имена локалей.

имена языковых стандартов Windows отличаются от Linux. Попробуйте с "Ита", "eng", "deu", "ger", "esp". Вы можете получить полный список здесь: http://www.microsoft.com/resources/msdn/goglobal/default.mspx

пример:

//putenv("LANG=esp");  <- WRONG!
putenv('LC_ALL=esp');

третья проблема, большая: расширение gettext в windows не является потокобезопасным. Каждый раз, когда вы меняете язык, изменение процесса. Если вы запускаете php как fast-cgi, вы в порядке. Если вы запускаете php как модуль apache (например), это полный беспорядок, потому что язык меняется для каждого экземпляра php. Проблема в том, что gettext() зависит от настройки локали. Эта настройка процесс широкий на Windows PHP. Вы не можете изменить локаль для потока PHP, но только для процесса PHP.

сказал это, вот какой рабочий код:

// $MAINPATH is your document root

$locales=array(
  'it'=>'ita',
  'en'=>'eng',
  'de'=>'deu',
  'fr'=>'fra',
  'es'=>'esp',
  'ru'=>'rus'
);

$locale = $locales[$lang];
$res=putenv('LC_ALL='.$locale);
$rres=bindtextdomain('default', $MAINPATH.'locale');
$dres=textdomain('default');

структура каталогов локали должна быть следующей:

deu
  LC_MESSAGES
    default.mo
esp
  LC_MESSAGES
    default.mo
fra
  LC_MESSAGES
    default.mo
ita
  LC_MESSAGES
    default.mo
rus
  LC_MESSAGES
    default.mo

на Ubuntu он работает, если вы установите lc_all по умолчанию и оставьте язык и язык пустыми, например:

LANG=
LANGUAGE=
LC_ALL= "en_US.utf8"

вы должны перейти на PHP 5.6.6 для Windows, он работает!