18

我记得几个月前使用 gettext 运行了一些测试,以下代码运行良好:

putenv('LANG=l33t');
putenv('LANGUAGE=l33t');
putenv('LC_MESSAGES=l33t');

if (defined('LC_MESSAGES')) // available if PHP was compiled with libintl
{
    setlocale(LC_MESSAGES, 'l33t');
}

else
{
    setlocale(LC_ALL, 'l33t');
}

bindtextdomain('default', './locale'); // ./locale/l33t/LC_MESSAGES/default.mo
bind_textdomain_codeset('default', 'UTF-8');
textdomain('default');

echo _('Hello World!'); // h3110 w0r1d!

这工作得很好(如果我没记错的话,在 Windows XP 和 CentOS 下),这很好,因为我可以使用任意的“语言环境”,而不必担心它们是否安装在系统上。但是,这似乎不再起作用了,我想知道为什么...


红帽 + PHP 5.2.11:

我可以在各种语言环境中来回切换,只要setlocale()调用不返回错误(如果系统上可用/安装了语言环境),翻译就会显示正确。

这并不完美(如果我可以将 gettext 指向任何任意翻译目录而不必测试语言环境的存在,那就太好了),但这是可以接受的。稍后我将进行更多测试。

Windows 7 + PHP 5.3.1 (XAMPP):

setlocale()总是返回 false (即使使用LC_ALL而不是LC_MESSAGES),除非我使用一些有效的 Windows 语言环境,例如eng,deuptg- 在这种情况下,语言环境似乎设置正确,但翻译仍然不显示。我现在无法测试,因为我打开了数百个选项卡,但我认为对该脚本的第一次调用会产生正确的翻译(重新启动 Apache 不会成功)。

我不确定这是否与PHP Bug #49349 有关。我会测试这是几个小时。


有什么方法可以跨不同的操作系统(可能使用自定义语言环境,如)可靠地使用 gettext 扩展(不是纯 PHP 实现,如php-gettextZend Translate Adapter)?l33t

另外,绝对有必要使用setlocale(LC_ALL, ...)吗?我宁愿保留TIME,NUMERICMONETARY(特别是)语言环境设置不变(默认为POSIX语言环境)。


我有一个想法......是否可以setlocale()使用非常常见的语言环境(如C,POSIXen_US)进行调用并通过域指定语言?像这样的东西:

/lang/C/LC_MESSAGES/domain.pt.mo
/lang/C/LC_MESSAGES/domain.de.mo
/lang/C/LC_MESSAGES/domain.en.mo
/lang/C/LC_MESSAGES/domain2.pt.mo
/lang/C/LC_MESSAGES/domain2.de.mo
/lang/C/LC_MESSAGES/domain2.en.mo

这可以在 *nix 和 Windows 平台上正常工作吗?

4

2 回答 2

19

Gettext 对于 webapps 来说并不太实用。

  • 例如,它本身不尊重/使用 Accept-Language 样式偏好。
  • 通常会在共享虚拟主机 (mod_php SAPI) 上引发一些缓存问题。

所以有时我有点希望 PHP 模块不存在,并且方便的_()函数名称快捷方式可用于用户空间实现。
(有我自己的gettext.php,它更可靠。)

您的选择:

  1. Anway,根据一些错误报告,gettext 的 Windows 端口在 UTF-8 上有一些缺陷。也许您的版本再次受到影响。所以尝试bind_textdomain_codeset('default', 'ISO-8859-1');初学者。此外,它似乎更喜欢 Windows IIRC 上的环境变量,因此putenv("LC_ALL", "fr_FR");可能比setlocale(). 如果您稍后使用 dl(gettext.dll) 尤其可行。

    也给它一个机会,在那里包括一个字符集LANG=en_GB.ISO-8859-1。(由于您的源文本无论如何都是英文的,因此关心字符集在这里并不是很相关;但可能是 gettext 自身绊倒的常见情况。)哦,有时它是 UTF8 而不是 UTF-8;也试试 ASCII。

  2. 或者绕过gettext。您的领域想法很接近,但我只需使用预定义的 ./locale/ 子目录来表示语言:

    ./lang/en/locale/C/LC_MESSAGES/domain.mo
    

    然后只调用bindtextdomain("default", "./lang/{$APP_LANG}/locale")而不给 gettext 解释空间。它总是会查找 /C/,但已经注入了正确的语言环境目录。但是无论如何都要尝试从 $LANG 到 /C/ 的符号链接。

  3. Bite in the gnu. Give up on gettext. "PhpWiki" had a custom awk conversion script. It transforms .po files into .php array scripts (yeah very oldschool), and just utilizes a __() function instead. Close. And more reliable.

于 2010-08-21T01:24:43.407 回答
6

此代码不会在每个系统上完美运行,因为每个系统区域设置存储库 + php 版本都不同,等等。

如果你想要一致性,你需要使用 Zend_Translate 之类的东西,如果你在每个系统(相同版本)上安装 Zend,它们都将彼此保持一致,因为它们使用相同的本地化数据、语言环境名称和代码库。

有很多错误setlocale,它只是不可靠。见评论@http: //php.net/manual/en/function.setlocale.php

于 2010-08-17T15:14:10.780 回答