核心要點
許多公司最終都會將目標市場轉向全球。這一目標將帶來將公司網站翻譯成一種或多種語言的需求。即使您不為大公司工作,您也可能需要以您的母語(假設您不是英語母語人士)推出新服務以瞄準當地市場,並以英語面向全球市場。作為開發者,我們的職責不是翻譯文本,而是準備網站以支持翻譯。在PHP中,最流行的方法是通過Gettext。這是一種很棒的方法,因為它允許將翻譯與應用程序分離,從而實現流程的並行化。問題在於,Apache緩存翻譯,因此,除非您可以重新啟動引擎,否則翻譯文件的任何更新都將不會顯示。如果您在共享主機上工作並且沒有管理員權限,那麼這一事實尤其令人惱火。在本文中,我將詳細描述此問題並解釋我找到的解決方案以避免此問題。
注意:如果您不熟悉I18N、翻譯和Gettext的概念,我強烈建議您在進一步探索本文之前閱讀本系列文章。它將為您提供比您在此處找到的簡要概述更詳細的信息,並幫助您更好地理解這些主題。
環境設置
在PHP中使用翻譯有很多方法。我能回憶起的最簡單的一種方法是擁有一個包含所有翻譯字符串的關聯數組,然後使用鍵來檢索正確的字符串。正如您可能猜到的那樣,此解決方案的擴展性不佳,除非您正在處理一個非常非常小的項目(也許不超過5行代碼),否則應避免使用此解決方案。對於嚴肅的翻譯,我們可以使用Gettext。這種方法使我們能夠為每個目標語言擁有不同的文件,這有助於維護業務邏輯、表示層和翻譯(我們可以將其視為表示層的附加組件)之間的分離。使用Gettext,我們可以並行化流程,因為在我們處理網站的某些功能時,翻譯人員仍然可以使用Poedit等軟件進行翻譯。
翻譯應存儲在具有固定結構的路徑中。首先,我們將有一個根據您的喜好命名的根文件夾(例如“languages”)。在其中,我們必須為每個目標語言創建一個文件夾,其名稱必須符合ISO 3166標準。因此,意大利語翻譯的有效名稱可以是“it_IT”(意大利語意大利語)、“it_CH”(意大利語瑞士語)、“en_US”(美國英語)等等。在具有語言代碼的文件夾中,我們必須有一個名為“LC_MESSAGES”的文件夾,最後,我們將在其中存儲翻譯文件。
Poedit分析網站的源代碼,根據我們在軟件中設置的一種或多種模式提取要翻譯的字符串。它將字符串保存在擴展名為.po(Portable Object)的單個文件中,該軟件(或等效軟件)會將其編譯成二進制.mo文件。後者是我們和PHP的gettext()函數感興趣的格式。 .mo文件是我們必須放置在我們之前創建的“LC_MESSAGES”目錄中的文件。
使用gettext()的示例代碼如下(代碼已添加註釋,以便您快速了解其作用):
<code class="language-php"><?php // 包含翻译文件的根文件夹的名称 $translationsPath = 'languages'; // 要翻译到的语言 $language = 'it_IT'; // 翻译文件的名称(在gettext中称为域) $domain = 'audero'; // 指示此会话将使用哪种语言 putenv("LANG=" . $language); setlocale(LC_ALL, $language); // 设置当前域的路径 bindtextdomain($domain, $translationsPath); // 指定字符编码 bind_textdomain_codeset($domain, 'UTF-8'); // 选择域 textdomain($domain); // 调用gettext()函数(它有一个名为_()的别名) echo gettext("HELLO_WORLD"); // 等效于echo _("HELLO_WORLD"); ?></code>
將之前的代碼保存在頁面中並在瀏覽器中加載後,如果gettext()能夠找到翻譯文件,您將在屏幕上看到您進行的翻譯。
到目前為止,一切順利。壞消息是,一旦加載翻譯,Apache就會對其進行緩存。因此,除非我們可以重新啟動引擎,否則翻譯文件的任何更新都將不會顯示。如果我們在共享主機上工作並且沒有管理員權限,那麼這尤其令人惱火。如何解決此問題? Audero Shared Gettext來救援!
什麼是Audero Shared Gettext
Audero Shared Gettext是一個PHP庫(實際上只是一個類,但讓我做夢吧),它允許您繞過通過gettext()函數加載的翻譯被Apache緩存的問題。該庫採用了一種簡單而有效的方法,因此您將始終使用最新的翻譯。 Audero Shared Gettext需要PHP 5.3或更高版本,因為它使用命名空間,並且存在上一節中描述的結構。它有兩個主要方法:updateTranslation()和deleteOldTranslations()。前者是庫的核心,也是實現此技巧的方法。但是這個技巧是什麼呢?讓我們看看它的代碼,以了解更多信息。為了充分理解它,值得強調的是,類的構造函數接受存儲翻譯的路徑、要翻譯到的語言以及翻譯文件的名稱(域)。
<code class="language-php"><?php // 包含翻译文件的根文件夹的名称 $translationsPath = 'languages'; // 要翻译到的语言 $language = 'it_IT'; // 翻译文件的名称(在gettext中称为域) $domain = 'audero'; // 指示此会话将使用哪种语言 putenv("LANG=" . $language); setlocale(LC_ALL, $language); // 设置当前域的路径 bindtextdomain($domain, $translationsPath); // 指定字符编码 bind_textdomain_codeset($domain, 'UTF-8'); // 选择域 textdomain($domain); // 调用gettext()函数(它有一个名为_()的别名) echo gettext("HELLO_WORLD"); // 等效于echo _("HELLO_WORLD"); ?></code>
該方法首先要做的是測試原始的二進制翻譯文件(.mo文件)是否存在。如果不存在,則該方法會引發異常。然後,它根據提供給構造函數的參數和文件的最後修改時間戳計算翻譯文件的完整路徑。之後,它創建一個新的字符串,將原始域與之前計算的時間戳連接起來。完成後,這裡就是技巧所在,它會創建翻譯文件的鏡像副本。如果已經存在具有此類名稱的文件,則該類足夠智能以避免此復制。最後,它返回將在bindtextdomain()、bind_textdomain_codeset()和textdomain()中使用的新名稱。這樣做,Apache將看到翻譯就像它與原始翻譯無關一樣,從而避免了緩存問題。正如我所說,簡單而有效!
“偉大的Aurelio!”,你在想,“但是這樣我的文件夾就會因為這些複製而膨脹。”沒錯。這就是我創建deleteOldTranslations()的原因。它刪除了選定翻譯文件夾中除最後一個以外的所有鏡像副本。
現在您已經了解了Audero Shared Gettext是什麼以及它可以為您做什麼,讓我們看看如何獲得它。
安裝Audero Shared Gettext
您可以通過Composer獲得“Audero Shared Gettext”,將以下幾行添加到您的composer.json中:
<code class="language-php">/** * 创建翻译文件的镜像副本 * * @return string 创建的翻译文件的名称(在gettext中称为域) * * @throws \Exception 如果找不到翻译文件 */ public function updateTranslation() { if (!self::translationExists()) { throw new \Exception('在给定路径中找不到翻译文件。'); } $originalTranslationPath = $this->getTranslationPath(); $lastAccess = filemtime($originalTranslationPath); $newTranslationPath = str_replace(self::FILE_EXTENSION, $lastAccess . self::FILE_EXTENSION, $originalTranslationPath); if(!file_exists($newTranslationPath)) { copy($originalTranslationPath, $newTranslationPath); } return $this->domain . $lastAccess; }</code>
然後運行安裝命令以解析和下載依賴項:
<code class="language-json">"require": { "audero/audero-shared-gettext": "1.0.*" }</code>
Composer會將庫安裝到您項目的vendor/audero目錄中。
如果您不想使用Composer(您真的應該這樣做),您可以通過運行以下命令來通過Git獲得Audero Shared Gettext:
<code class="language-bash">php composer.phar install</code>
您擁有的最後一個選項是訪問存儲庫並將其下載為存檔。
如何使用Audero Shared Gettext
假設您使用Composer獲得了Audero Shared Gettext,您可以依靠其自動加載器來動態加載該類。然後,您必須創建一個SharedGettext實例並調用您需要的 method。您可以使用前面提到的方法之一,如下例所示。
<code class="language-bash">git clone https://github.com/AurelioDeRosa/Audero-Shared-Gettext.git</code>
結論
本文向您介紹了Audero Shared Gettext,這是一個簡單的庫(嗯……類),它允許您繞過通過gettext()函數加載的翻譯被Apache緩存的問題。 Audero Shared Gettext具有廣泛的兼容性,因為它要求您至少擁有PHP 5.3(已經發布一段時間了),因為它使用了命名空間。隨意使用存儲庫中包含的演示和文件,如果您發現問題,請提交Pull Request和問題。我已經根據CC BY-NC 4.0許可證發布了Audero Shared Gettext,因此可以免費使用。
您是否遇到過此問題?您是如何解決的?不要害羞,在評論中發布您的解決方案!
(以下為FAQ部分,已根據原文進行偽原創,並保持原文大意)
關於在共享主機上管理Gettext翻譯的常見問題解答 (FAQ)
在共享主機上安裝Gettext可能有點棘手,因為您可能沒有root訪問權限。但是,您仍然可以通過cPanel或Plesk安裝它。在cPanel中,您可以在“選擇PHP版本”部分下找到啟用Gettext的選項。在Plesk中,您可以在“PHP設置”部分下啟用它。如果您找不到這些選項,您可能需要聯繫您的主機提供商尋求幫助。
您的Gettext翻譯不起作用可能有幾個原因。一個常見的問題是.mo文件沒有正確編譯或文件路徑不正確。確保.mo文件位於正確的目錄中,並且代碼中的文件路徑正確。另一個問題可能是您使用的區域設置不受服務器支持。您可以使用locale -a命令檢查這一點。
調試Gettext翻譯可以通過檢查.po和.mo文件中的錯誤來完成。您可以使用Poedit等工具打開這些文件並檢查是否存在任何語法錯誤。此外,您可以在代碼中使用gettext函數來檢查翻譯是否正在正確獲取。如果該函數返回原始字符串,則表示找不到翻譯。
是的,您可以在WordPress中使用Gettext。 WordPress使用Gettext作為其本地化框架。您可以在WordPress中使用__()和_e()函數來獲取翻譯。這些函數在後台使用Gettext。
您可以通過更新.po文件然後將其編譯成.mo文件來更新您的Gettext翻譯。 .po文件是一個純文本文件,您可以使用任何文本編輯器打開它。完成更改後,您可以使用Poedit之類的工具將.po文件編譯成.mo文件。
此錯誤通常發生在您的服務器正在使用的存儲庫中沒有該軟件包時。您可以嘗試使用sudo apt-get update命令更新您的軟件包列表。如果錯誤仍然存在,您可能需要添加其他存儲庫或手動安裝軟件包。
您可以通過使用gettext函數在PHP中使用Gettext。此函數將字符串作為參數,並返回翻譯後的字符串。在您可以使用此函數之前,您需要使用setlocale函數設置區域設置,並使用bindtextdomain函數指定.mo文件的路徑。
是的,您可以在Ubuntu上使用Gettext。您可以使用sudo apt-get install gettext命令安裝它。安裝後,您可以使用終端中的gettext命令來處理.po和.mo文件。
您可以使用Poedit之類的工具創建.po和.mo文件。此工具允許您創建和編輯.po文件並自動將其編譯成.mo文件。您也可以使用文本編輯器手動創建.po文件,但是您需要Poedit或msgfmt之類的工具才能將其編譯成.mo文件。
.po文件是包含原始字符串及其翻譯的純文本文件。它們可以使用任何文本編輯器打開和編輯。另一方面,.mo文件是根據.po文件生成的二進製文件。它們在運行時由Gettext用於獲取翻譯。
以上是管理共享託管上的getText翻譯的詳細內容。更多資訊請關注PHP中文網其他相關文章!