PHP/Gettext 问题

发布于 2024-09-12 15:21:40 字数 2126 浏览 7 评论 0原文

我记得几个月前用 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、deuptg - 在这种情况下,区域设置似乎已正确设置,但翻译仍然不正确不出现。我现在无法测试,因为我打开了数百个选项卡,但我认为对该脚本的第一次调用会产生正确的翻译(重新启动 Apache 不会成功)。

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


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

另外,是否绝对有必要使用 setlocale(LC_ALL, ...) ?我宁愿保留 TIMENUMERICMONETARY (特别是)区域设置不变(默认为 POSIX 区域设置)。


我有一个想法...是否可以使用非常常见的语言环境(例如 CPOSIX调用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

一身仙ぐ女味 2024-09-19 15:21:40

Gettext 对于网络应用程序来说不太实用。

  • 例如,它本身不尊重/使用 Accept-Language 样式首选项。
  • 通常在共享网络主机 (mod_php SAPI) 上会出现一些缓存问题。

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

您的选择:

  1. 无论如何,根据一些错误报告,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. 咬住gnu。放弃 gettext。 “PhpWiki”有一个自定义的 awk 转换脚本。它将 .po 文件转换为 .php 数组脚本(是的,非常老派),并且只使用 __() 函数。关闭。而且更可靠。

Gettext isn't overly practical for webapps.

  • As for example it doesn't honor/use Accept-Language style preferences by itself.
  • Typically incurs some caching issues on shared webhosts (mod_php SAPI).

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:

  1. 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, so putenv("LC_ALL", "fr_FR"); might work better than setlocale(). 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.

  2. Alternatively circumvent gettext. Your domain idea is close, but I'd simply use a pre-defined ./locale/ subdir for languages:

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

    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.

  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.

天生の放荡 2024-09-19 15:21:40

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

如果你想要一致性,你需要使用像 Zend_Translate 这样的东西,如果你在每个系统上安装 Zend(相同版本),它们都会彼此一致,因为它们使用相同的本地化数据、区域设置名称和代码库。

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

This 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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文