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

Мне нужно локализовать только веб-приложение PHP для Windows, и я оцениваю расширение gettext, но мне тяжело, пытаясь заставить его работать в моем окне разработки Windows 7. Я использовал пробную версию и ошибку вместе с Process Monitor для преодоления плохой и неточной документации, и мне удалось сделать строки _() отображаемые в каталоге * .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_MACHINE\SYSTEM\CurrentControlSet\Control\Nls] идентично дереву 7.

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

 C:\>set LANG=en_GB C:\>php C:\test\gettext.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'; 

Solutions Collecting From Web of "Gettext всегда будет использовать системный стандарт по умолчанию"

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

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

Подводить итоги:

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

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

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

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

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

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

Пример:

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

Третья проблема, большая: расширение gettext на окнах не является потокобезопасным. Каждый раз, когда вы меняете язык, изменение происходит в процессе. Если вы запустите 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 

Ключ состоит в использовании версии PHP (Non Nest Safe) (= NTS) .

К сожалению, 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 вызывается с другим языком, кроме системного, папка с .mo и .po не может быть прочитана.

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

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

Структура папок

\ Locale \ fr_CH \ LC_MESSAGES

  • fr_CH.mo + fr_CH.po // системный язык
  • de_CH.mo + de_CH.po
  • it_CH.mo + it_CH.po

Код

 $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); 

В Ubuntu он работает, если вы установили свой LC_ALL по умолчанию и оставите LANG и LANGUAGE пустым, например:

 LANG= LANGUAGE= LC_ALL= "en_US.utf8" 

Вы должны обновиться до PHP 5.6.6 для Windows, он работает!

goto php.ini и расширение uncomment = php_intl.dll