12

我需要本地化一个仅限 Windows 的 PHP Web 应用程序,并且我正在评估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 版本似乎无关紧要(也在我的 PC 中尝试了最新的 32 位 PHP/5.5.5)。
  • 我的[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls]注册表树与其他七个框相同。

编辑:在命令行上进行测试时,我发现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';
4

7 回答 7

6

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

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

总结一下:

  • 非线程安全构建已于 2014 年 11 月 21 日在源代码树中修复
  • 线程安全的构建(例如 Apache 模块)还没有,也没有明确的解决方案。
于 2015-03-06T11:48:38.270 回答
3

关键是使用 PHP 的非线程安全 (=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

于 2017-01-17T12:51:03.850 回答
2

我在 Windows 10 上使用 PHP 5.6.30 VC11 Theard Safe 时遇到了同样的问题。解决方法在这里由 sirio3mil 找到并解决了这个问题。

显然,带有 TS 的 PHP 只能访问 Locale 语言文件夹。因此,当 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);
于 2017-02-10T09:37:08.023 回答
1

在 Ubuntu 上,如果您设置默认 LC_ALL 并将 LANG 和 LANGUAGE 留空,则它可以工作,如下所示:

LANG=
LANGUAGE=
LC_ALL= "en_US.utf8"
于 2017-11-30T13:30:17.413 回答
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
于 2014-02-13T11:23:25.640 回答
0

添加一个系统变量“LANG”,其值为所需的语言环境(例如“en_US”或“nl_NL”),重新启动 apache 并显示与该语言环境对应的翻译。

环境变量

这适用于 Windows 10 上带有 php 7.1(线程安全)的 XAMPP,语言环境目录结构如下:

    // Directory structure
    <locale_dir>\en_US\LC_MESSAGES\bundle.po
    <locale_dir>\nl_NL\LC_MESSAGES\bundle.po
    ...
于 2020-02-07T09:39:46.120 回答
-2

您必须升级到适用于 Windows 的 PHP 5.6.6,它可以工作!

于 2015-03-05T01:33:05.323 回答