Gettext将始终使用系统默认的语言环境

我需要本地化一个仅限于Windows的PHP Web应用程序,并且正在评估gettext扩展,但是我正在尝试使其在Windows 7开发框中工作最困难。 我已经与stream程监控器一起使用试错法来克服可怜的和不准确的文档,我设法使_()显示string从* .po目录对应于计算机的默认语言环境(在我的情况下,现代西class牙语) 。 我所有尝试设置不同的语言环境都被忽略了。

我写了一个testing脚本,有很多冗余的东西:

 <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上安装区域设置的模糊参考,但是没有确切的细节。 问题是什么?

(我知道常见的build议是转储ge​​ttext并使用任何其他库。)


进一步testing:

我的代码完美地运行在另外两台计算机上: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]registry树与其他七个框相同。

编辑:当在命令行上testing时,我发现在运行PHP脚本之前设置LANG环境variables最终会改变语言:

 C:\>set LANG=en_GB C:\>php C:\test\gettext.php 

这明确certificate,我的电脑有正确的资产,但也让我想知道为什么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'; 

这个问题已经被PHP团队承认和部分修复 。

这是一个相当技术性的东西,显然与环境变量(gettext在很大程度上取决于)的方式是由底层平台处理有关。 此外,Visual C运行时库中的某些内容已经从VC9更改为VC11,影响了所有这些。

总结一下:

  • 非线程安全构建已在2014年11月21 的源代码树中修复。
  • 线程安全的构建(如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'); 

第三个问题,大的问题:在Windows上的gettext扩展不是线程安全的。 每次你改变语言,改变是过程广泛的。 如果你以最快的速度运行php,你就可以。 如果你运行PHP作为apache模块(例如),这是一个混乱,因为每个php实例的语言更改。 问题是gettext()依赖于区域设置。 这个设置是在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 

关键是使用非线程安全(= 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安全在Windows 10.解决方法发现和解决这个问题在这里由sirio3mil。

显然PHP与TS只能访问Locale语言文件夹。 所以当setlocale和putenv函数用另外一种语言调用的时候,带.mo和.po的文件夹不能被读取。

解决方法是每个翻译语言只有一个带有系统语言的语言文件夹和多个.mo / .po文件对。 域将被设置为通缉语言。

瑞士法语,德语和意大利语例子:

文件夹结构

\区域\ 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); 

你必须升级到PHP 5.6.6的Windows,它的工作原理!

转到php.ini和取消注释扩展= p​​hp_intl.dll