gettext_在共享主机上管理Gettext转换

gettext

If you’re working for a big company, chances there are that sooner or later your employers will start to target the global market. With this ambition will come the need to translate the company’s website into one or more languages. Even if you don’t work for a big company, you may have a new service to launch in your native language (assuming you’re not a native English speaker) to target your local market, and in English for the global one. As developers, our role isn’t to translate texts but to prepare the website to support translations. The most popular method to do that in PHP is via Gettext. It’s a great method because it allows to separate translations from the application, enabling the parallelization of the process. The problem with it, is that Apache caches the translations, so unless you can restart the engine, any update to a translation file won’t be seen. This fact is particularly annoying if you work on a shared hosting where you don’t have administrator permissions. In this article, I’ll describe this issue in detail and explain the solution I found to avoid it.

如果您在一家大公司工作,那么您的雇主迟早会有机会开始瞄准全球市场。 有了这个雄心壮志,就需要将公司的网站翻译成一种或多种语言。 即使您不在一家大公司工作,也可能会提供一项新服务,以您的母语(假设您不是说英语的人)启动您的本地市场,并以英语面向全球市场。 作为开发人员,我们的职责不是翻译文本,而是准备网站以支持翻译。 在PHP中最流行的方法是通过Gettext。 这是一个很好的方法,因为它允许将翻译与应用程序分开,从而实现流程的并行化。 它的问题是Apache缓存了翻译,因此除非您可以重新启动引擎,否则将看不到翻译文件的任何更新。 如果您在没有管理员权限的共享主机上工作,这一事实尤其令人讨厌。 在本文中,我将详细描述此问题,并说明为避免该问题而找到的解决方案。

Note: If you aren’t familiar with the concepts of I18N, translations, and Gettext, I strongly encourage you to read this series before exploring this article further. It will provide you with more details than the brief overview you’ll find here, and will help you have a better comprehension of these topics.

注意 :如果您不熟悉I18N,翻译和Gettext的概念,强烈建议您在进一步研究本文之前阅读本系列文章。 它比为您提供的简要概述为您提供了更多详细信息,并且将帮助您更好地理解这些主题。

搭建环境 (Setting up the Environment)

There a lot of ways to use translations in PHP. The simplest one I can recall is to have an associative array containing all the translated strings and then use the keys to retrieve the right. As you may guess, this solution doesn’t scale well and should be avoided unless you’re working on a very very small project (perhaps something not longer than 5 lines of code). For serious translations we can use Gettext. This approach enables us to have different files for every targeted language which helps in maintaining separation between the business logic, the presentation layer, and the translations (which we can see as an add-on of the presentation layer). With Gettext, we can parallelize the process because while we’re working on some features of the website, translators can still work on translations using software like Poedit.

在PHP中有很多使用翻译的方法。 我能想到的最简单的方法是拥有一个包含所有已转换字符串的关联数组,然后使用键来检索正确的字符串。 您可能会猜到,除非您正在做一个非常小的项目(也许不超过5行代码),否则此解决方案将无法很好地扩展,应该避免使用。 对于严重的翻译,我们可以使用Gettext 。 这种方法使我们能够为每种目标语言使用不同的文件,这有助于维持业务逻辑,表示层和翻译(我们可以将其视为表示层的附加组件)之间的分隔。 使用Gettext,我们可以并行化流程,因为当我们在处理网站的某些功能时,翻译人员仍可以使用Poedit之类的软件来进行翻译。

Translations should be stored in a path having a fixed structure. First of all, we’ll have a root folder named to your taste (for example “languages”). Inside it, we have to create a folder for every targeted language whose name must comply to the ISO 3166 standard. So, valid names for an Italian translation can be “it_IT” (Italian of Italy), “it_CH” (Italian of Switzerland), “en_US” (English of USA), and so on. Within the folder having the language code, we must have a folder named “LC_MESSAGES” where, finally, we’ll store the translation files.

翻译应存储在具有固定结构的路径中。 首先,我们将根据您的喜好命名一个根文件夹(例如“语言”)。 在其中,我们必须为每种目标语言都必须创建一个文件夹,其名称必须符合ISO 3166标准。 因此,意大利语翻译的有效名称可以是“ it_IT”(意大利的意大利语),“ it_CH”(瑞士的意大利语),“ en_US”(美国英语)等等。 在具有语言代码的文件夹中,我们必须有一个名为“ LC_MESSAGES”的文件夹,最后,我们将在其中存储翻译文件。

Poedit, analyzing the source of the website, extracts the strings to translate based on one or more patterns we set in the software. It saves the strings in a single file having .po (Portable Object) as its extention that this software (or one equivalent) will compile into binary .mo file. The latter is the format of interest for us and for the PHP’s gettext() function. The .mo file is the one we must place inside the “LC_MESSAGES” directory we created earlier.

Poedit分析网站的来源,根据我们在软件中设置的一种或多种模式提取字符串进行翻译。 它将字符串保存在单个文件中,该文件具有.po(可移植对象)的扩展名,此软件(或一个等效文件)将编译为二进制.mo文件。 后者是我们和PHP的gettext()函数感兴趣的格式。 .mo文件是我们必须放置在我们先前创建的“ LC_MESSAGES”目录中的文件。

A sample code that uses gettext() is the following (the code is commented to give you a quick grasp of what it does):

以下是使用gettext()示例代码(对代码进行注释以使您快速了解其功能):

<?php
   // The name of the root folder containing the translation files
   $translationsPath = 'languages';
       // The language into which to translate
       $language = 'it_IT';
   // The name of the translation file (referred as domain in gettext)
   $domain = 'audero';

   // Instructs which language will be used for this session
   putenv("LANG=" . $language); 
       setlocale(LC_ALL, $language);

   // Sets the path for the current domain
   bindtextdomain($domain, $translationsPath);
   // Specifies the character encoding
   bind_textdomain_codeset($domain, 'UTF-8');

   // Choose domain
   textdomain($domain);

   // Call the gettext() function (it has an alias called _())
   echo gettext("HELLO_WORLD"); // equivalent to echo _("HELLO_WORLD");
?>

Once you save the previous code in a page and load it in your browser, if gettext() is able to find the translation file, you’ll see the translations you made on the screen.

将先前的代码保存在页面中并将其加载到浏览器中后,如果gettext()能够找到翻译文件,您将在屏幕上看到所做的翻译。

So far, so good. The bad news is that once a translation is loaded, Apache caches it. Therefore, unless we can restart the engine, any update to a translation file won’t be seen. This is particularly annoying if we work on a shared hosting where we don’t have administrator permissions. How to solve this issue? Audero Shared Gettext to the rescue!

到目前为止,一切都很好。 坏消息是,一旦加载翻译,Apache就会对其进行缓存。 因此,除非我们可以重新启动引擎,否则将看不到翻译文件的任何更新。 如果我们在没有管理员权限的共享主机上工作,这将特别令人讨厌。 如何解决这个问题? Audero共享Gettext进行救援!

什么是Audero共享Gettext (What’s Audero Shared Gettext)

Audero Shared Gettext is a PHP library (actually is just a single class, but let me dream) that allows you to bypass the problem of the translations, loaded via the gettext() function, that are cached by Apache. The library employs a simple yet effective trick so that you’ll always have the most up-to-date translation in use. Audero Shared Gettext requires PHP version 5.3 or higher because it uses namespaces, and the presence of the structure described in the previous section. It has two main methods: updateTranslation() and deleteOldTranslations(). The former is the core of the library and the method that implements the trick. But what is this trick? Let’s see its code, to discover more. To fully understand it, it’s worth highlighting that the constructor of the class accepts the path where the translations are stored, the language into which to translate, and the name of the translation file (domain).

Audero Shared Gettext是一个PHP库(实际上只是一个类,但是让我梦dream 以求 ),它使您可以绕过通过gettext()函数加载的Apache缓存的翻译问题。 该库采用了一个简单而有效的技巧,因此您将始终拥有最新的翻译版本。 Audero Shared Gettext需要PHP 5.3或更高版本,因为它使用名称空间,并且存在上一节中描述的结构。 它有两个主要方法: updateTranslation()deleteOldTranslations() 。 前者是库的核心,也是实现窍门的方法。 但是,这是什么把戏? 让我们看看它的代码,以发现更多信息。 为了完全理解它,值得强调的是,该类的构造函数接受翻译存储的路径,翻译所用的语言以及翻译文件(域)的名称。

/**
 * Create a mirror copy of the translation file
 *
 * @return string The name of the created translation file (referred as domain in gettext)
 *
 * @throws \Exception If the translation's file cannot be found
 */
public function updateTranslation()
{
    if (!self::translationExists()) {
        throw new \Exception('The translation file cannot be found in the given path.');
    }
    $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;
}

The first thing the method does is to test if the original, binary translation file exists (the .mo file). In case it doesn’t exist, the method throws an exception. Then, it calculates the complete path to the translation file based on the parameters given to the constructor, and the timestamp of the last modification of the file. After, it creates a new string concatenating the original domain to the previously calculated timestamp. Once done, and here is the trick, it creates a mirror copy of the translation file. The class is smart enough to avoid this copy if a file with such a name already exists. Fianlly, it returns the new name that we’ll employ in bindtextdomain(), bind_textdomain_codeset(), and textdomain(). Doing so, Apache will see the translation as if it isn’t related to the original one, avoiding the caching problem. As I said, simple but effective!

该方法要做的第一件事是测试原始的二进制翻译文件(.mo文件)是否存在。 如果不存在,该方法将引发异常。 然后,它根据提供给构造函数的参数以及文件最后修改的时间戳计算转换文件的完整路径。 之后,它将创建一个新字符串,将原始域连接到先前计算的时间戳。 一旦完成,这就是窍门,它将创建翻译文件的镜像副本。 如果已经存在具有此类名称的文件,则该类足够聪明,可以避免此副本。 Fianlly,它返回新的名称,我们将在采用bindtextdomain() bind_textdomain_codeset()textdomain() 这样,Apache将看到与原始翻译无关的翻译,从而避免了缓存问题。 正如我所说,简单但有效!

“Great Aurelio!”, you’re thinking, “but in this way my folders will be bloated by these replications.” Right. That’s why I created deleteOldTranslations(). It removes all the mirror copies but the last from the folder of the chosen translation.

您在想:“很棒的Aurelio!但是,这样的复制会使我的文件夹膨胀。” 对。 这就是为什么我创建了deleteOldTranslations()的原因。 它会从所选翻译的文件夹中删除所有镜像副本,但最后一个镜像副本。

Now that you know what Audero Shared Gettext is and what it can do for you, let’s see how to obtain it.

现在您知道了什么是Audero Shared Gettext,它可以为您做什么,让我们看看如何获​​得它。

安装Audero共享Gettext (Installing Audero Shared Gettext)

You can obtain “Audero Shared Gettext” via Composer adding the following lines to your composer.json:

您可以通过Composer将以下行添加到composer.json来获取“ Audero Shared Gettext”:

"require": {
    "audero/audero-shared-gettext": "1.0.*"
}

And then run the install command to resolve and download the dependencies:

然后运行install命令来解析和下载依赖项:

php composer.phar install

Composer will install the library to your project’s vendor/audero directory.

Composer会将库安装到项目的vendor/audero目录中。

In case you don’t want to use Composer (you should, really) you can obtain Audero Shared Gettext via Git running the command:

如果您不想使用Composer(确实应该),则可以通过运行以下命令通过Git获取Audero Shared Gettext:

git clone https://github.com/AurelioDeRosa/Audero-Shared-Gettext.git

The last option you have is to visit the repository and download it as an archive.

您所拥有的最后一个选择是访问存储库并将其作为存档下载。

如何使用Audero Shared Gettext (How to use Audero Shared Gettext)

Assuming you obtained Audero Shared Gettext using Composer, you can rely on the its autoloader to dynamically load the class. Then, you have to create an SharedGettext instance and call the method you need. You can use one of the previously cited methods as shown in the following example.

假设您使用Composer获得了Audero Shared Gettext,则可以依靠其自动加载器来动态加载类。 然后,您必须创建一个SharedGettext实例并调用所需的方法。 您可以使用前面引用的方法之一,如以下示例所示。

<?php
    // Include the Composer autoloader
    require_once 'vendor/autoload.php';

    $translationsPath = 'languages';
        $language = 'it_IT';
    $domain = 'audero';

    putenv('LC_ALL=' . $language);
        setlocale(LC_ALL, $language);

    try {
       $sharedGettext = new Audero\SharedGettext\SharedGettext($translationsPath, $language, $domain);
       // Create the mirror copy of the translation and return the new domain
       $newDomain = $sharedGettext->updateTranslation();

       // Sets the path for the current domain
       bindtextdomain($newDomain, $translationsPath);
       // Specifies the character encoding
       bind_textdomain_codeset($newDomain, 'UTF-8');

       // Choose domain
       textdomain($newDomain);
        } catch(\Exception $ex) {
       echo $ex->getMessage();
    }
?>

结论 (Conclusions)

This article has introduced you to Audero Shared Gettext, a simple library (emh…class) that allows you to bypass the problem of the translations, loaded via the gettext() function, cached by Apache. Audero Shared Gettext has a wide compatibility because it requires that you have at least PHP 5.3 (released for a while now) because of its use of namespaces. Feel free to play with the demo and the files included in the repository, to submit Pull Requests and issues if you find them. I’ve released Audero Shared Gettext under the CC BY-NC 4.0 license, so it’s free to use.

本文向您介绍了Audero Shared Gettext,这是一个简单的库(emh…class),通过该库,您可以绕过Apache缓存的通过gettext()函数加载的翻译问题。 Audero Shared Gettext具有广泛的兼容性,因为由于使用了命名空间,它要求您至少具有PHP 5.3(现已发布了一段时间)。 随意使用演示和存储库中包含的文件,如果发现请求和问题,则提交它们。 我已经按照CC BY-NC 4.0许可证发布了Audero Shared Gettext,因此可以免费使用。

Have you ever encountered this issue? How did you solve it? Don’t be shy and post your solutions in the comments!

您是否遇到过此问题? 您是如何解决的? 不要害羞,并在评论中发布您的解决方案!

翻译自: https://www.sitepoint.com/managing-gettext-translations-shared-hosting/

gettext

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值