PHP Conference Japan 2024

Gettext

添加注释

用户贡献注释 11 条注释

marioandrea dot petruccelli at gmail dot com
6 年前
如何在 Windows 上使用 gettext。

如果您使用 Linux,请从步骤 2 开始,并将 cmd 视为 Linux shell。

1] 首先,您需要下载并安装此软件
https://mlocati.github.io/articles/gettext-iconv-windows.html

在安装过程中选中所有选项并继续。


2] 在您的网站目录中创建一个 index.php 文件,并在其中包含以下代码

<?php
echo _("Good Morning");
?>

3] 打开 cmd 并使用 cd 导航到您的网站文件夹

4] 现在使用以下命令直接从 php 文件创建 .mo 文件
xgettext -n index.php

使用 xgettext -help 查看如何包含更多 php 文件。

5] 完成后将生成一个名为 messages.mo 的文件。现在您需要设置语言和字符集。使用记事本打开 messages.mo 并编辑以下行

- "Language: \n" 变为 "Language fr\n"
- "Content-Type: text/plain; charset=CHARSET\n" 变为 "Content-Type: text/plain; charset=UTF-8\n"

6] 请记住翻译每行出现 msgstr "" 的地方,将 msgid 实例翻译成您选择的语言。例如

#: index.php:2
msgid "Good Morning"
msgstr "Bonjour"

7] 完成后打开 cmd 并使用 cd 导航到您的网站文件夹,然后键入
msgfmt messages.po

这将生成一个名为 messages.mo 的文件。它是 messages.po 文件的二进制版本

8] 现在您需要在网站文件夹中创建如下所示的文件夹结构。对于您要添加的每种语言都执行此操作。

website/locale/fr_FR/LC_MESSAGES

9] 将 messages.mo 和 messages.po 移动到 locale/fr_FR/LC_MESSAGES

10] 现在按如下方式编辑 index.php

<?php

$locale
= "fr_FR";

if (
defined('LC_MESSAGES')) {
setlocale(LC_MESSAGES, $locale); // Linux
bindtextdomain("messages", "./locale");
} else {
putenv("LC_ALL={$locale}"); // windows
bindtextdomain("messages", ".\locale");
}


textdomain("messages");

echo
_("Good Morning");
?>

11] 在浏览器中打开 index.php,如果看到“Bonjour”,则表示一切正常。如果不是,请从步骤 2 重新开始。

如果对您有用,请投票支持!

访问我的 GitHub 个人资料 https://github.com/TheoRelativity/
jpatokal at iki dot fi
15 年前
警告 Linux(Ubuntu)用户!您的系统*仅*支持操作系统上安装的语言环境,并且必须使用操作系统给出的*完全相同*的格式。(另请参见 PHP setlocale 手册。)要获取这些语言环境的列表,请输入 locale -a,这将为您提供类似以下内容

C
en_US.utf8
ja_JP.utf8
POSIX

因此,此计算机仅支持英语和日语!要添加例如芬兰语,请安装软件包

sudo apt-get install language-pack-fi-base

重新运行 locale -a,然后“fi_FI.utf8”应该会出现。确保在 PHP 代码中使用相同的名称

setlocale(LC_ALL, "fi_FI.utf8");

调整您的 po 路径以使其匹配,例如“./locale/fi_FI.utf8/LC_MESSAGES/messages.po”。

现在重新启动 Apache,它应该最终可以工作。弄清楚这一点花了一些时间……
sasq1 at go2 dot pl
15 年前
那么 pgettext 和 npgettext 呢?它们在 gettext 文档中,但在 PHP 中没有。如果您需要翻译相同的消息,但处于不同的上下文中,它们非常有用,因此应分别翻译,并且可能翻译方式不同。

幸运的是,有一个简单的解决方法,可能会有所帮助
从 gettext.h 标头中可以发现,pgettext() 只是内部调用 dcgettext() 的宏,并使用适当的混淆参数 - msgctxt 和 msgid 使用 ASCII 字符 4 [EOT,文本结束] 粘合在一起。它们在 .mo 文件中以相同的方式编写,因此可以这样引用它们。

这是我“模拟”的 pgettext() 函数

<?php
if (!function_exists('pgettext')) {

function
pgettext($context, $msgid)
{
$contextString = "{$context}\004{$msgid}";
$translation = dcgettext('messages', contextString,LC_MESSAGES);
if (
$translation == $contextString) return $msgid;
else return
$translation;
}

}
?>

默认情况下,xgettext 不支持 PHP 源文件的 pgettext 函数。但是有一个参数可以解决此问题。以下是我如何调用 xgettext

xgettext --force-po --keyword="pgettext:1c,2" -c -o messages.po sourceFile.php

在 sourceFile.php 中,我使用了以下测试代码

pgettext('menu', 'Open'); //替换“Otwórz”
pgettext('forum', 'Open'); //替换“Otwarty”,不同的上下文

生成的 .po 文件片段

msgctxt "menu"
msgid "Open"
msgstr "Otwórz"

msgctxt "forum"
msgctxt "Open"
msgstr "Otwarty"

我测试过它,一切正常:-) 如果任何人有任何进一步的建议或修复,请写;-)
rainwalker at seznam dot cz
15 年前
我的 PHP 应用程序是为 UTF-8 制作的,但我遇到了一个问题,即 gettext 总是返回所有 ISO-8859-2 而不是 UTF-8 的文本。

然后我发现您必须在 PHP 中将语言环境精确设置为请求的编码。因此,当我想要捷克语 UTF-8 时,我使用了

setlocale(LC_ALL, "cs_CZ.UTF-8");

现在可以用了……
yuricardenas at gmail dot com
15 年前
*需要牢记的一点*
不要忘记在 .po 文件中设置字符集!
例如

"Content-Type: text/plain; charset=UTF-8\n"

然后 PHP 将能够找到您使用 msgfmt 从 .po 文件生成的 .mo 文件,其中包含设置的字符集。

由于这一点,我浪费了很多时间调试我的代码,测试每个人在这个手册和互联网上建议的每一个细微的更改



<?php

// 以下选项之一:
setlocale( LC_MESSAGES, 'pt_BR')
// 或以下选项之一:
setlocale( LC_MESSAGES, 'pt_BR.utf8')
// 或以下选项之一:
setlocale( LC_MESSAGES, '')

// 以下选项之一:
putenv("LANG=pt_BR.utf8");
// 或以下选项之一:
putenv("LANGUAGE=pt_BR.utf8");

// 以下选项之一:
bindtextdomain('mydomain', dirname(__FILE__).'/locale');
// 或以下选项之一:
bindtextdomain("*", dirname(__FILE__).'/locale');
// 或以下选项之一:
bindtextdomain('*', dirname(__FILE__).'/locale');

// 设置或不设置 "bind_textdomain_codeset()":
bind_textdomain_codeset("mydomain", 'UTF-8');
?>

以及要设置的区域设置目录名称
./locale/pt_BR.UTF8/LC_MESSAGES/mydomain.mo

./locale/pt_BR/LC_MESSAGES/mydomain.mo

./locale/pt/LC_MESSAGES/mydomain.mo

最后,产生正确翻译字符串(以及正确的字符集)的代码是

<?php

$directory
= dirname(__FILE__).'/locale';
$domain = 'mydomain';
$locale ="pt_BR.utf8";

//putenv("LANG=".$locale); //在我的测试中不需要,但人们说它对 Windows 有用

setlocale( LC_MESSAGES, $locale);
bindtextdomain($domain, $directory);
textdomain($domain);
bind_textdomain_codeset($domain, 'UTF-8');
?>

使用 pt_BR.utf8 区域设置,这三个目录名称都成功了。(我的测试是在重启 Apache 后尝试每个目录进行的)。

我希望可以帮助其他人避免浪费我浪费的时间... =P

使用
Ubuntu 8.04 (hardy)
Apache 2.2.8
PHP 5.2.4-2ubuntu5.6
Johnny
10 年前
还需要注意的是,服务器会在第一次加载时缓存 .mo 文件,然后“很少”重新加载它,因此您对 .mo 文件的更新将不会显示。从 Web 中清除缓存的一些解决方案是重新启动 Apache 服务器,或者每次都为 textdomain 使用另一个名称。这些都很繁琐。我还没有找到更好的解决方案。
php at devicenull dot org
16 年前
要在 Debian 上使其正常工作,请安装 locales-all 包。我刚刚花了几个小时才找到一个错误,因为它缺少该包而无法工作。
maximran800 at gmail dot com
6 年前
我在设置 gettext 时遇到了一些问题。
我已经尝试了上面提到的所有示例,但没有一个起作用。
但是,我在此处发现了一个不错的技巧,并且它有效!!
我的平台是 FreeBSD。

以下是帖子
https://php.net/manual/en/function.gettext.php

Gettext 翻译会被缓存。如果您更改 *.mo 文件,您的页面可能不会按预期翻译。以下是一个简单的解决方法,不需要重新启动 Web 服务器(我知道,这只是一个肮脏的技巧)

<?php
function initialize_i18n($locale) {
putenv('LANG='.$locale);
setlocale(LC_ALL,"");
setlocale(LC_MESSAGES,$locale);
setlocale(LC_CTYPE,$locale);
$domains = glob($locales_root.'/'.$locale.'/LC_MESSAGES/messages-*.mo');
$current = basename($domains[0],'.mo');
$timestamp = preg_replace('{messages-}i','',$current);
bindtextdomain($current,$locales_root);
textdomain($current);
}
?>

要使此方法有效,您必须将您的区域设置放在 messages-[unix_time].mo 文件中,并使用此名称(不含 .mo)作为您的域来欺骗缓存机制(域名称不同)

msgfmt messages.po -o messages-`date +%s`.mo

对我来说,这很好用(尽管这不是一个非常优雅的解决方案)
afrimuchkov at yandex dot ru
7 年前
所以……这很困难)
最后
1)如果目录是“en”,而不是“en_GB”或“en_GB.utf8”,则有效。只有“en”。
2)但使用 setlocale(LC_MESSAGES, "en_GB.utf8");
Anonymous
9 年前
对于所有尝试在域名称中使用非字母字符的人:不要尝试这样做!!!我们搜索了几个小时才意识到“foo-bar”不是域名称的好主意。有时我们得到了正确的翻译,有时没有。所以只对域名称使用 A-Z 字符!
cucurella at gmail dot com
4 年前
<?php

// 直接读取 .po 文件

function T_($contenido) {

global
$language;

if (
$language == "en") { $translation_file = "langs/en.po"; }
if (
$language == "es") { $translation_file = "langs/es.po"; }

if (
file_exists("$translation_file")) {
$IDIOMA_CONTENT = file("$translation_file");
$num_lineas = count($IDIOMA_CONTENT);
} else {
return
$contenido;
}

for (
$i = 0; $i <= $num_lineas; $i++) {
$linea1 = $IDIOMA_CONTENT[$i];
$linea1 = rtrim($linea1);
$string6 = substr($linea1, 0, 6);

if (
$string6 == "msgid ") {
$orig = str_replace($string6, "", $linea1);
$orig = str_replace("\"", "", $orig);

if (
"$orig" == "$contenido") {
$linea2 = $IDIOMA_CONTENT[$i + 1];
$linea2 = rtrim($linea2);
$string7 = substr($linea2, 0, 7);

if (
$string7 == "msgstr ") {
$trad = str_replace($string7, "", $linea2);
$trad = str_replace("\"", "", $trad);
return(
"$trad");
}
} else {
$i = $i + 3;
}
}
}

return(
"$contenido");
}

$language = "es";

print
T_("I on puc comprar el meu domini ?");
print
T_("Aquí tens alguns links...");

?>
To Top