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

时间:2013-10-24 14:54:47

标签: php windows apache gettext

我需要本地化一个仅限Windows的PHP Web应用程序,我正在评估gettext extension,但我正在努力让它在我的Windows 7开发框中运行。我和Process Monitor一起使用了试验和错误来克服糟糕和不准确的文档,我设法从* .po目录中显示_()显示字符串,该字符串对应于计算机的默认语言环境(Modern在我的情况下西班牙语)。 我会默默忽略设置不同区域设置的所有尝试。

我编写了一个包含大量冗余内容的测试脚本:

<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上也需要安装语言环境的模糊引用,但没有确切的细节。 问题是什么?

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


进一步测试:

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

编辑:在命令行上进行测试时,我发现在运行PHP脚本之前设置LANG环境变量最终会更改语言:

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';

7 个答案:

答案 0 :(得分:6)

PHP团队已经确认了issue并且partially fixed

这是一个相当技术性的事情,显然与底层平台处理环境变量(gettext严重依赖)的方式有关。此外,从VC9到VC11的Visual C运行时库中的某些内容已经发生了变化,影响了所有这些。

总结一下:

  • 2014年11月21日 st 的源代码树中修复了非线程安全版本。
  • 线程安全版本(例如Apache模块)没有,并且看不到明确的解决方案。

答案 1 :(得分:2)

关键是使用PHP的非线程安全(= NTS)版本

不幸的是,Windows和PHP无法很好地处理线程进程的环境,因此putenv(&#39; LC_ALL =&#39;。$ locale);命令不起作用。

最后,我最终得到了Apache 2.4 + FCGID + PHP 7.1 NTS,它现在在Windows 7上运行良好,并且它是一个非线程安全的安装。

有关如何安装此类系统的分步说明,请访问:https://www.youtube.com/watch?v=UXrJPrGaPB0

我已将VC14和x64版本用于所有组件(VC是&#34; Microsoft Visual C ++ Redistributable&#34;的缩写)。为此,我首先安装了VC14,从这里下载:https://www.microsoft.com/en-us/download/details.aspx?id=48145

答案 2 :(得分:1)

我遇到了与PHP 5.6.30 VC11 Theard Safe在Windows 10上相同的问题。解决方法通过sirio3mil找到并解决了这个问题here

显然,带有TS的PHP只能访问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);

答案 3 :(得分:1)

在Ubuntu上,如果您设置了默认的LC_ALL并将LANG和LANGUAGE保留为空,则它会起作用,如下所示:

LANG=
LANGUAGE=
LC_ALL= "en_US.utf8"

答案 4 :(得分:0)

第一个问题:setlocale()

要使其工作,您需要设置有效的区域设置。在Windows上,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作为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

答案 5 :(得分:0)

添加具有所需语言环境值的系统变量“ LANG”(例如“ en_US”或“ nl_NL”),重新启动apache并显示与该语言环境相对应的转换。

Environment variables

这适用于Windows 10和区域结构目录上具有php 7.1(线程安全)的XAMPP:

    // Directory structure
    <locale_dir>\en_US\LC_MESSAGES\bundle.po
    <locale_dir>\nl_NL\LC_MESSAGES\bundle.po
    ...

答案 6 :(得分:-2)

您必须升级到PHP 5.6.6 for Windows,它才有效!