核心要点
许多公司最终都会将目标市场转向全球。这一目标将带来将公司网站翻译成一种或多种语言的需求。即使您不为大公司工作,您也可能需要以您的母语(假设您不是英语母语人士)推出新服务以瞄准当地市场,并以英语面向全球市场。作为开发者,我们的职责不是翻译文本,而是准备网站以支持翻译。在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()的示例代码如下(代码已添加注释,以便您快速了解其作用):
<?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"); ?>
将之前的代码保存在页面中并在浏览器中加载后,如果gettext()能够找到翻译文件,您将在屏幕上看到您进行的翻译。
到目前为止,一切顺利。坏消息是,一旦加载翻译,Apache就会对其进行缓存。因此,除非我们可以重新启动引擎,否则翻译文件的任何更新都将不会显示。如果我们在共享主机上工作并且没有管理员权限,那么这尤其令人恼火。如何解决此问题?Audero Shared Gettext来救援!
什么是Audero Shared Gettext
Audero Shared Gettext是一个PHP库(实际上只是一个类,但让我做梦吧),它允许您绕过通过gettext()函数加载的翻译被Apache缓存的问题。该库采用了一种简单而有效的方法,因此您将始终使用最新的翻译。Audero Shared Gettext需要PHP 5.3或更高版本,因为它使用命名空间,并且存在上一节中描述的结构。它有两个主要方法:updateTranslation()和deleteOldTranslations()。前者是库的核心,也是实现此技巧的方法。但是这个技巧是什么呢?让我们看看它的代码,以了解更多信息。为了充分理解它,值得强调的是,类的构造函数接受存储翻译的路径、要翻译到的语言以及翻译文件的名称(域)。
<?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"); ?>
该方法首先要做的是测试原始的二进制翻译文件(.mo文件)是否存在。如果不存在,则该方法会引发异常。然后,它根据提供给构造函数的参数和文件的最后修改时间戳计算翻译文件的完整路径。之后,它创建一个新的字符串,将原始域与之前计算的时间戳连接起来。完成后,这里就是技巧所在,它会创建翻译文件的镜像副本。如果已经存在具有此类名称的文件,则该类足够智能以避免此复制。最后,它返回将在bindtextdomain()、bind_textdomain_codeset()和textdomain()中使用的新名称。这样做,Apache将看到翻译就像它与原始翻译无关一样,从而避免了缓存问题。正如我所说,简单而有效!
“伟大的Aurelio!”,你在想,“但是这样我的文件夹就会因为这些复制而膨胀。”没错。这就是我创建deleteOldTranslations()的原因。它删除了选定翻译文件夹中除最后一个以外的所有镜像副本。
现在您已经了解了Audero Shared Gettext是什么以及它可以为您做什么,让我们看看如何获得它。
安装Audero Shared Gettext
您可以通过Composer获得“Audero Shared Gettext”,将以下几行添加到您的composer.json中:
/** * 创建翻译文件的镜像副本 * * @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; }
然后运行安装命令以解析和下载依赖项:
"require": { "audero/audero-shared-gettext": "1.0.*" }
Composer会将库安装到您项目的vendor/audero目录中。
如果您不想使用Composer(您真的应该这样做),您可以通过运行以下命令来通过Git获得Audero Shared Gettext:
php composer.phar install
您拥有的最后一个选项是访问存储库并将其下载为存档。
如何使用Audero Shared Gettext
假设您使用Composer获得了Audero Shared Gettext,您可以依靠其自动加载器来动态加载该类。然后,您必须创建一个SharedGettext实例并调用您需要的 method。您可以使用前面提到的方法之一,如下例所示。
git clone https://github.com/AurelioDeRosa/Audero-Shared-Gettext.git
结论
本文向您介绍了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中文网其他相关文章!