Gettext

添加笔记

用户贡献的笔记 12 个笔记

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,它应该最终可以正常工作。弄清楚这一点花了相当长的时间...
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");

现在它可以正常工作了...
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"

我测试过它,一切正常 :-) 如果有任何人有任何进一步的建议或修复方法,请告诉我 ;-)
Johnny
10 年前
请注意,服务器会在第一次加载时缓存 .mo 文件,然后“很少”重新加载它,因此您对 .mo 文件的更新将不会显示。从 Web 清除缓存的一些解决方案是重启 Apache 服务器,或每次使用不同的文本域名称。这些方法很繁琐。我目前还没有找到更好的解决方案。
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
php at devicenull dot org
15 年前
要在 Debian 上正常运行它,请安装 locales-all 包。我刚花了几个小时才找到一个由于缺少此包而无法正常工作的错误。
maximran800 at gmail dot com
6 年前
我在设置 geettext 时遇到了一些问题。
我已经尝试了上面提到的所有示例,但都没有成功。
然而,我在一个地方发现了一个很好的技巧,并且它起作用了!
我的平台是 FreeBSD。

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

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

<?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
6 年前
所以……这真的很困难!
最终
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
3 年前
<?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...");

?>
djogopatrao at gmail dot com
15 年前
值得注意的是,根据 GNU gettext FAQ[1],*源代码必须为 ASCII*。这意味着你不能像这样写代码:

<?= _("áááàààãã")?>

使用 UTF-8、ISO-8859-1 或其他编码,并希望它能正常工作。它不会。

[1]http://www.gnu.org/software/gettext/FAQ.html#nonascii_strings
To Top