2024 年 PHP 日本研討會

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"
msgid "Open"

(原文誤植為 msgctxt)
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 檔案的更新不會立即生效。一些從網頁清除快取的解決方案包括重新啟動 Apache 伺服器,或每次使用不同的文字定義域名稱。這些方法都很麻煩。我目前還沒找到更好的解決方案。
php at devicenull dot org
16 年前
要在 Debian 上正確地使用這個功能,請安裝 locales-all 套件。我剛花了幾個小時才找到一個錯誤,原因就是缺少這個套件。
maximran800 at gmail dot com
6 年前
我在設定 gettext 時遇到一些問題。
我嘗試了上面提到的所有範例,但都沒有用。
不過,我找到了一個好方法,而且有效!
我的平台是 FreeBSD。

以下是該篇文章
https://php.dev.org.tw/manual/en/function.gettext.php

Gettext 翻譯會被快取。如果您更改了 *.mo 檔案,您的頁面可能不會如預期般翻譯。這裡有一個簡單的解決方法,不需要重新啟動網路伺服器(我知道,這只是一個不太正規的權宜之計)

<?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");
匿名
9 年前
對於所有嘗試在網域名稱中使用非字母字元的人:不要嘗試這樣做!!!我們花了幾個小時才意識到 "foo-bar" 不是一個好的網域名稱。有時我們可以得到正確的翻譯,有時則不行。所以,網域名稱只能使用 A-Z 的字元!
cucurella at gmail dot com
4 年前
<?php

// read directly .po files

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