PHP/Gettext 问题
我记得几个月前用 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 下),这很好,因为我可以使用任意“语言环境” ”,而不必担心它们是否安装在系统上。然而,这似乎不再起作用了,我想知道为什么......
Red Hat + PHP 5.2.11:
我能够在各种语言环境中来回切换,并且只要 翻译就显示正确setlocale()
调用不会返回 false(如果区域设置可用/系统上已安装)。
这并不完美(如果我可以将 gettext 指向任何任意翻译目录而不必测试语言环境是否存在,那就太好了),但它是可以接受的。稍后我将进行更多测试。
Windows 7 + PHP 5.3.1 (XAMPP):
setlocale()
始终返回 false(即使使用 LC_ALL
而不是 LC_MESSAGES
),除非我使用一些有效的 Windows 区域设置,例如 eng、
deu
或 ptg
- 在这种情况下,区域设置似乎已正确设置,但翻译仍然不正确不出现。我现在无法测试,因为我打开了数百个选项卡,但我认为对该脚本的第一次调用会产生正确的翻译(重新启动 Apache 不会成功)。
我不确定这是否与 PHP Bug #49349 有关。我会测试一下这是几个小时。
有没有办法使用 gettext 扩展(不是纯 PHP 实现,例如 php-gettext 或 Zend Translate Adapter)可靠地跨不同操作系统(可能使用 自定义语言环境(例如 l33t
)?
另外,是否绝对有必要使用 setlocale(LC_ALL, ...) ?我宁愿保留 TIME
、NUMERIC
和 MONETARY
(特别是)区域设置不变(默认为 POSIX
区域设置)。
我有一个想法...是否可以使用非常常见的语言环境(例如 C
、POSIX
或 调用
)并通过域指定语言?像这样的事情:setlocale()
>en_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 平台上正常工作吗?
I remember running some tests a some months ago with gettext and the following code worked perfectly:
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!
This worked perfectly (under Windows XP and CentOS if I remember correctly), which was good because I could use arbitrary "locales", without having to bother if they were installed on the system or not. However, this doesn't seem to work anymore, I wonder why...
Red Hat + PHP 5.2.11:
I'm able to switch back and forth from various locales and the translations show up correclty as long as the setlocale()
call doesn't return false (if the locale is available/installed on the system).
This is not perfect (would be great if I could just point gettext to any arbitrary translation directory without having to test for the existence of the locale), but it's acceptable. I'll run some more tests later on.
Windows 7 + PHP 5.3.1 (XAMPP):
setlocale()
always returns false (even when using LC_ALL
instead of LC_MESSAGES
), unless I use some valid Windows locale such as eng
, deu
or ptg
- in this case the locale seems to be correctly set but the translations still don't show up. I can't test right now because I've hundreds of tabs open but I think the very first call to that script yields the correct translation (restarting Apache won't do the trick).
I'm not sure if this is related to the PHP Bug #49349. I'll test this is a couple of hours.
Is there any way to use the gettext extension (not pure PHP implementations like php-gettext or the Zend Translate Adapter) reliably across different operating systems (possibly with custom locales like l33t
)?
Also, is it absolutely necessary to use setlocale(LC_ALL, ...)
? I would preffer leaving the TIME
, NUMERIC
and MONETARY
(specially) locale settings untouched (defaulting to the POSIX
locale).
I had an idea... Would it be possible to call setlocale()
with a very common locale (like C
, POSIX
or en_US
) and specify the language via the domain? Something like this:
/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
Would this work on *nix and Windows plataforms without problems?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
Gettext 对于网络应用程序来说不太实用。
所以我有时希望 PHP 模块不存在,并且方便的
_()
函数名称快捷方式可用于用户态实现。(有我自己的 gettext.php,它工作更可靠。)
您的选择:
无论如何,根据一些错误报告,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。或者绕过 gettext。您的域想法很接近,但我只是使用预定义的 ./locale/ 语言子目录:
然后只需调用
bindtextdomain("default", "./lang/{$APP_LANG}/locale")
即可,无需给 gettext 太多解释空间。它总是会查找 /C/,但已经注入了正确的语言环境目录。但无论如何,请尝试在其中建立从 $LANG 到 /C/ 的符号链接。咬住gnu。放弃 gettext。 “PhpWiki”有一个自定义的 awk 转换脚本。它将 .po 文件转换为 .php 数组脚本(是的,非常老派),并且只使用 __() 函数。关闭。而且更可靠。
Gettext isn't overly practical for webapps.
So I sort of sometimes wish that PHP module wouldn't exist, and the convenient
_()
function name shortcut was available to userland implementations.(Had my own gettext.php, which worked more reliable.)
Your options:
Anway, according to a few bug reports the Windows port of gettext had some flaws with UTF-8. Maybe your version is affected again. So try
bind_textdomain_codeset('default', 'ISO-8859-1');
for starters. Also, it seems to prefer the environment variables on Windows IIRC, soputenv("LC_ALL", "fr_FR");
might work better thansetlocale()
. Especially workable if you dl(gettext.dll) later on.Also give it a chance with including a charset right there
LANG=en_GB.ISO-8859-1
. (Since your source text is English anyway, caring about the charset isn't very relavant here; but probably a common case where gettext trips over itself.) Oh and on occasion it's UTF8 not UTF-8; also try ASCII.Alternatively circumvent gettext. Your domain idea is close, but I'd simply use a pre-defined ./locale/ subdir for languages:
Then just invoke
bindtextdomain("default", "./lang/{$APP_LANG}/locale")
without giving gettext room to interpret much. It will always look up /C/, but the correct locale directory has been injected already. But try to have a symlink from the $LANG to /C/ in there anyway.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.
该代码不会在每个系统上完美运行,因为每个系统的区域设置存储库 + php 版本都是不同的。
如果你想要一致性,你需要使用像 Zend_Translate 这样的东西,如果你在每个系统上安装 Zend(相同版本),它们都会彼此一致,因为它们使用相同的本地化数据、区域设置名称和代码库。
setlocale
有很多错误,它只是不可靠。请参阅评论@ http://php.net/manual/en/function.setlocale.phpThis code won't run perfectly on every system, because every systems locale repository + php version is different, among other things.
If you want consistency you need to use something like Zend_Translate, which if you install Zend on each system ( the same version of it ) they would all be consistent with one another because they're using the same localization data, locale names and codebase.
There are numerous bugs with
setlocale
, it's just not reliable. See the comments @ http://php.net/manual/en/function.setlocale.php