phpmyadmin / motranslator
使用 Gettext MO 文件进行 PHP 翻译的 API
Requires
- php: ^7.1 || ^8.0
- symfony/expression-language: ^4.0 || ^5.0 || ^6.0
Requires (Dev)
- phpmyadmin/coding-standard: ^3.0.0
- phpstan/phpstan: ^1.4.6
- phpunit/phpunit: ^7.4 || ^8 || ^9
Suggests
- ext-apcu: Needed for ACPu-backed translation cache
README
使用 Gettext MO 文件进行 PHP 翻译的 API。
特性
- 所有字符串都存储在内存中以便快速查找
- 快速加载 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_size
和 apc.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的翻译。使用自定义格式通常会为翻译者增加另一个障碍,我们希望让他们更容易地做出贡献。