phpmyadmin/motranslator

使用 Gettext MO 文件进行 PHP 翻译的 API

5.3.1 2023-08-23 18:32 UTC

This package is auto-updated.

Last update: 2024-09-22 01:38:50 UTC


README

使用 Gettext MO 文件进行 PHP 翻译的 API。

Test-suite codecov.io Scrutinizer Code Quality Packagist

特性

  • 所有字符串都存储在内存中以便快速查找
  • 快速加载 MO 文件
  • 低级 API 用于读取 MO 文件
  • Gettext API 模拟
  • 不使用 eval() 进行复数方程

限制

  • 默认的 InMemoryCache 不适合存储在内存中的大型 MO 文件
  • 输入和输出编码必须匹配(最好是 UTF-8)

安装

请使用 Composer 进行安装

composer require phpmyadmin/motranslator

文档

API 文档可在 https://develdocs.phpmyadmin.net/motranslator/ 查找。

对象 API 使用方法

// Create loader object
$loader = new PhpMyAdmin\MoTranslator\Loader();

// Set locale
$loader->setlocale('cs');

// Set default text domain
$loader->textdomain('domain');

// Set path where to look for a domain
$loader->bindtextdomain('domain', __DIR__ . '/data/locale/');

// Get translator
$translator = $loader->getTranslator();

// Now you can use Translator API (see below)

低级 API 使用方法

// Directly load the mo file
// You can use null to not load a file and the use a setter to set the translations
$cache = new PhpMyAdmin\MoTranslator\Cache\InMemoryCache(new PhpMyAdmin\MoTranslator\MoParser('./path/to/file.mo'));
$translator = new PhpMyAdmin\MoTranslator\Translator($cache);

// Now you can use Translator API (see below)

翻译器 API 使用方法

// Translate string
echo $translator->gettext('String');

// Translate plural string
echo $translator->ngettext('String', 'Plural string', $count);

// Translate string with context
echo $translator->pgettext('Context', 'String');

// Translate plural string with context
echo $translator->npgettext('Context', 'String', 'Plural string', $count);

// Get the translations
echo $translator->getTranslations();

// All getters and setters below are more to be used if you are using a manual loading mode
// Example: $translator = new PhpMyAdmin\MoTranslator\Translator(null);

// Set a translation
echo $translator->setTranslation('Test', 'Translation for "Test" key');

// Set translations
echo $translator->setTranslations([
  'Test' => 'Translation for "Test" key',
  'Test 2' => 'Translation for "Test 2" key',
]);

// Use the translation
echo $translator->gettext('Test 2'); // -> Translation for "Test 2" key

Gettext 兼容性使用方法

// Load compatibility layer
PhpMyAdmin\MoTranslator\Loader::loadFunctions();

// Configure
_setlocale(LC_MESSAGES, 'cs');
_textdomain('phpmyadmin');
_bindtextdomain('phpmyadmin', __DIR__ . '/data/locale/');
_bind_textdomain_codeset('phpmyadmin', 'UTF-8');

// Use functions
echo _gettext('Type');
echo __('Type');

// It also support other Gettext functions
_dnpgettext($domain, $msgctxt, $msgid, $msgidPlural, $number);
_dngettext($domain, $msgid, $msgidPlural, $number);
_npgettext($msgctxt, $msgid, $msgidPlural, $number);
_ngettext($msgid, $msgidPlural, $number);
_dpgettext($domain, $msgctxt, $msgid);
_dgettext($domain, $msgid);
_pgettext($msgctxt, $msgid);

使用 APCu 缓存

如果您已安装了 APCu 扩展,则可以使用它来存储翻译缓存。然后,.mo 文件将只加载一次,所有进程将共享相同的缓存,从而减少内存使用并实现与本地 gettext 扩展相当的性能。

如果您正在使用 Loader,在获取翻译器实例之前传递一个 ApcuCacheFactory

PhpMyAdmin\MoTranslator\Loader::setCacheFactory(
    new PhpMyAdmin\MoTranslator\Cache\AcpuCacheFactory()
);
$loader = new PhpMyAdmin\MoTranslator\Loader();

// Proceed as before 

如果您正在使用低级 API,直接实例化 ApcuCache

$cache = new PhpMyAdmin\MoTranslator\Cache\ApcuCache(
    new PhpMyAdmin\MoTranslator\MoParser('./path/to/file.mo'),
    'de_DE',     // the locale
    'phpmyadmin' // the domain
);
$translator = new PhpMyAdmin\MoTranslator\Translator($cache);

// Proceed as before

默认情况下,APCu 将缓存翻译直到下一次服务器重启,并将缓存条目前缀为 mo_ 以避免与其他缓存条目冲突。您可以通过将 $ttl$prefix 参数传递给 ApcuCacheFactory 或在实例化 ApcuCache 时来控制此行为

PhpMyAdmin\MoTranslator\Loader::setCacheFactory(
    new PhpMyAdmin\MoTranslator\Cache\AcpuCacheFactory(
        3600,     // cache for 1 hour
        true,     // reload on cache miss
        'custom_' // custom prefix for cache entries
    )
);
$loader = new PhpMyAdmin\MoTranslator\Loader();

// or...

$cache = new PhpMyAdmin\MoTranslator\Cache\ApcuCache(
    new PhpMyAdmin\MoTranslator\MoParser('./path/to/file.mo'),
    'de_DE',
    'phpmyadmin',
    3600,     // cache for 1 hour
    true,     // reload on cache miss
    'custom_' // custom prefix for cache entries
);
$translator = new PhpMyAdmin\MoTranslator\Translator($cache);

如果您收到更新的翻译文件,可以使用低级 API 加载它们而无需重新启动服务器

$parser = new PhpMyAdmin\MoTranslator\MoParser('./path/to/file.mo');
$cache = new PhpMyAdmin\MoTranslator\Cache\ApcuCache($parser, 'de_DE', 'phpmyadmin');
$parser->parseIntoCache($cache);

您应该确保 APCu 有足够的内存来存储所有翻译,以及您用于其他目的的任何其他条目。如果某个条目被逐出缓存,则 .mo 文件将被重新解析,从而影响性能。请参阅 apc.shm_sizeapc.shm_segments文档 并在首次推出时监控缓存使用情况。

如果您的 .mo 文件缺少大量翻译,则第一次请求缺少条目时将重新解析 .mo 文件。同样,这将在所有缺少的条目被击中一次之前影响性能。您可以通过将 $reloadOnMiss 参数设置为 false 来关闭此行为。如果您这样做,则必须确保 APCu 有足够的内存,否则当条目被逐出时,用户将看到未翻译的文本。

历史记录

此库基于 php-gettext。它添加了一些性能改进和能够使用 Composer 安装的能力。

动机

创建此库的动机包括

  • php-gettext 库不再维护
  • 它不与最新的 PHP 版本(phpMyAdmin 有补丁版本)兼容
  • 它依赖于 eval() 函数进行复数方程,这可能具有严重的安全影响,请参阅 CVE-2016-6175
  • 无法使用 Composer 安装。
  • 在库中存在性能改进的空间。

为什么不直接在PHP中使用native gettext呢?

我们尝试过,但这不是一个可行的解决方案。

  • 无法使用系统未知的区域设置,这是从Web应用中无法控制的事情。在使用最小化虚拟容器时,这个问题会更加复杂。
  • 修改MO文件通常会导致PHP段错误。它(或者更准确地说,Gettext库)缓存了MO文件的头信息,如果内容发生了变化(例如,新版本上传到服务器),它会尝试使用旧的引用访问新的数据。这是一个长期存在的bug:https://bugs.php.net/bug.php?id=45943

为什么选择Gettext而不是JSON、YAML或其他格式?

我们希望翻译者能够使用他们喜欢的工具,并且我们也希望能够使用Gettext提供的广泛工具,例如 使用Weblate进行的基于Web的翻译。使用自定义格式通常会为翻译者增加另一个障碍,我们希望让他们更容易地做出贡献。