多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Hyperf 国际化(i18n)组件实战:从语言文件、翻译函数到复数规则

Hyperf 国际化(i18n)组件实战:从语言文件、翻译函数到复数规则 后端微服务【免费下载链接】hyperf A coroutine framework that focuses on hyperspeed and flexibility. Building microservice or middleware with ease.项目地址https://gitcode.com/gh_mirrors/hy/hyperf点击查看免费下载本文以 Hyperf 官方国际化组件hyperf/translation为核心系统讲解如何在 Hyperf 项目中搭建多语言支持从安装、语言文件组织、语言环境配置到翻译字符串、占位符替换与复数规则处理并深入到源码层解析键解析、回退链与协程安全实现。读完本文你将能独立为 Hyperf 应用接入完整的 i18n 能力并理解其底层工作机制。安装与组件定位Hyperf 的国际化组件可通过 Composer 直接安装composer require hyperf/translation从 composer.json 可以看出该组件是一个独立组件仅依赖hyperf/collection、hyperf/context、hyperf/contract、hyperf/macroable、hyperf/stringable、hyperf/support与psr/container要求 PHP 8.2。这意味着它不绑定框架的完整运行环境可以独立复用于其它项目或框架中。组件通过ConfigProvider完成与框架的对接见 ConfigProvider.php将TranslatorInterface绑定到TranslatorFactory将TranslatorLoaderInterface绑定到FileLoaderFactory注册配置发布项把 publish/translation.php 发布到项目的config/autoload/translation.php。安装后可以通过以下命令发布配置Hyperf 标准的配置发布机制php bin/hyperf.php vendor:publish hyperf/translation语言文件的组织与编写Hyperf 的语言文件默认放在storage/languages目录下也可以在config/autoload/translation.php内更改语言文件的文件夹。每种语言对应其中的一个子文件夹例如en指英文语言文件zh_CN指中文简体的语言文件你可以按照实际需要创建新的语言文件夹和里面的语言文件。目录结构示例如下/storage /languages /en messages.php /zh_CN messages.php所有的语言文件都是返回一个数组数组的键是字符串类型的?php // storage/languages/en/messages.php return [ welcome Welcome to our application, ];语言文件的加载由 FileLoader 完成它根据路径/语言文件夹/组名.php的约定查找文件loadPath方法并将文件 return 的数组作为该语言该组group的翻译行集合。这里的「组名」对应语言文件名也就是翻译键的第一段例如messages.php对应messages组。除了 PHP 数组文件FileLoader还支持JSON 语言文件loadJsonPaths方法每个语言目录下的{locale}.json文件会被加载为键值映射并支持通过addJsonPath()注册额外的 JSON 路径。JSON 文件被解析时如果结构非法会抛出RuntimeExceptionTranslation file [...] contains an invalid JSON structure.便于尽早发现问题。此外组件还提供 ArrayLoader一个纯内存的加载器可通过addMessages()在运行时直接注入翻译内容适合测试或动态语言包场景。命名空间Namespace支持从 Translator.php 的parseKey方法可以看到翻译键支持两种形式普通键组.条目如messages.welcome命名空间键命名空间::组.条目如module::messages.welcome。命名空间通过addNamespace($namespace, $hint)注册对应的语言文件存放在 hint 指定的目录下同时FileLoader的loadNamespaceOverrides还支持在{path}/vendor/{namespace}/{locale}/{group}.php中放置覆盖文件对组件提供的翻译进行局部覆盖——这在扩展包Package场景中非常实用。配置语言环境国际化组件的相关配置都在config/autoload/translation.php配置文件中设定你可以按照实际需要修改它?php // config/autoload/translation.php return [ // 默认语言 locale zh_CN, // 回退语言当默认语言的语言文本没有提供时就会使用回退语言的对应语言文本 fallback_locale en, // 语言文件存放的文件夹 path BASE_PATH . /storage/languages, ];这三个配置项的读取分别发生在两个工厂中TranslatorFactory 通过config-get(translation.locale, zh_CN)与config-get(translation.fallback_locale, en)读取默认语言与回退语言构造Translator后调用setFallback()注入回退语言FileLoaderFactory 通过config-get(translation.path, BASE_PATH . /storage/languages)读取语言文件根目录并注入FileLoader。配置临时语言环境除了全局默认语言你还可以在运行时为当前请求或协程生命周期临时切换语言。此时应通过依赖注入获得TranslatorInterface然后调用setLocale()?php use Hyperf\Di\Annotation\Inject; use Hyperf\Contract\TranslatorInterface; class FooController { #[Inject] private TranslatorInterface $translator; public function index() { // 只在当前请求或协程生命周期有效 $this-translator-setLocale(zh_CN); } }值得说明的是setLocale()的「临时」语义在源码中有明确的实现支撑Translator的setLocale()并非直接修改对象属性而是调用Context::set()将语言写入Hyperf 协程上下文见 Translator.php 的getLocale/setLocale/getLocaleContextKey。由于协程上下文按协程隔离切换语言不会污染其它协程也不会产生并发下「串语言」的问题——这正是 Hyperf 作为协程框架对国际化能力的原生适配。翻译字符串通过 TranslatorInterface 翻译可直接通过注入Hyperf\Contract\TranslatorInterface并调用实例的trans方法实现对字符串的翻译?php use Hyperf\Di\Annotation\Inject; use Hyperf\Contract\TranslatorInterface; class FooController { #[Inject] private TranslatorInterface $translator; public function index() { return $this-translator-trans(messages.welcome, [], zh_CN); } }trans()方法签名支持三个参数翻译键、占位符替换数组、以及可选的locale不传则使用当前语言环境。其底层实现会依次查找当前语言与回退语言见下文「回退链机制」最终把翻译行中的占位符替换为真实值后返回。通过全局函数翻译您也可以通过全局函数__()或trans()来对字符串进行翻译。函数的第一个参数使用键指使用翻译字符串作为键的键或者是文件. 键的形式。echo __(messages.welcome); echo trans(messages.welcome);这两个全局函数定义在 Functions.php 中内部通过ApplicationContext::getContainer()-get(TranslatorInterface::class)获取翻译器实例后转发给trans()。由于Functions.php已通过 composer 的files字段自动加载见 composer.json你在项目的任意位置都可以直接调用这两个函数无需手动引入。翻译不存在的键当某个键在当前语言与回退语言中都找不到时Translator::get()会原样返回传入的键名见 Translator.php 中return $line ?? $key;。这意味着界面上的翻译键本身就是最好的错误提示——你一眼就能看出哪个键缺失或拼写错误这在大型多语言项目中非常利于排查。翻译字符串中定义占位符您也可以在语言字符串中定义占位符所有的占位符使用:作为前缀。例如把用户名作为占位符?php // storage/languages/en/messages.php return [ welcome Welcome :name, ];替换占位符使用函数的第二个参数echo __(messages.welcome, [name Hyperf]); // 输出Welcome Hyperf如果占位符全部是大写字母或者是首字母大写那么翻译过来的字符串也会是相应的大写形式welcome Welcome, :NAME, // Welcome, HYPERF goodbye Goodbye, :Name, // Goodbye, Hyperf这一行为由Translator::makeReplacements()实现见 Translator.php对于替换数组中的每个键它会一次性把:key、:KEY全大写与:Key首字母大写三种形态替换为对应的大小写变体。此外sortReplacements()会先按键长度降序排序确保较长的占位符如:first_name不会先被较短的键如:first错误替换——这是 Laravel 系翻译实现中常见的边界细节。处理复数不同语言的复数规则是不同的在中文中可能不太关注这一点但在翻译其它语言时我们需要处理复数形式的用词。我们可以使用「管道」字符|用来区分字符串的单数和复数形式apples There is one apple|There are many apples,也可以指定数字范围创建更加复杂的复数规则apples {0} There are none|[1,19] There are some|[20,*] There are many,使用「管道」字符定义好复数规则后就可以使用全局函数trans_choice来获得给定「数量」的字符串文本。在下面的例子中因为数量大于 1所以就会返回翻译字符串的复数形式echo trans_choice(messages.apples, 10);当然除了全局函数trans_choice()您也可以使用Hyperf\Contract\TranslatorInterface的transChoice方法$this-translator-transChoice(messages.apples, 10);复数选择器底层原理复数规则的实现集中在 MessageSelector.php 的choose()方法中处理流程分为两步内联条件匹配extract/extractFromString逐段解析{0}...、[1,19]...、[20,*]...这类条件前缀。支持区间语法[from,to]、[from,*]大于等于 from、[*,to]小于等于 to以及{n}等于 n精确匹配并支持小数数量。这些规则在 MessageSelectorTest.php 中有大量测试用例覆盖例如{0} first|[1,9] second在数量为 0、1、10 时分别命中不同的分支。语言复数规则getPluralIndex如果没有命中内联条件则按目标语言选择复数索引。该方法内置了数十种语言的复数规则例如中文zh_CN、日语ja、韩语ko等语言无复数区分恒返回 0英语en等语言按「数量是否为 1」返回 0 或 1俄语ru、乌克兰语uk等语言存在三种复数形式单数、少数、多数阿拉伯语ar则多达六种复数形式。Translator::choice()在调用选择器之前还会把数量写入$replace[count]因此你可以在复数文本中通过:count占位符输出实际数量见 Translator.php。同时它支持传入Countable对象或数组作为数量内部会自动count()统计元素个数例如trans_choice(messages.apples, $orderItems)。回退链机制默认语言与回退语言如何协作前面提到配置中有locale与fallback_locale两个语言二者在源码中的协作关系很清晰。Translator::get()会调用localeArray()构建「查找语言数组」protected function localeArray(?string $locale): array { return array_filter([$locale ?: $this-locale(), $this-fallback]); }即先查目标语言或当前语言查不到再查回退语言逐个尝试直到找到翻译行为止。例如默认语言为zh_CN、回退语言为en时trans(messages.welcome)会先在zh_CN中查找若zh_CN/messages.php中没有welcome键则自动到en/messages.php中查找。这套回退机制保证了多语言项目在个别语言翻译不完整时用户依然能看到可用的文案而不是空白或异常。对应的查找行为在 TranslatorTest.php 中均有测试覆盖包括has()与hasForLocale()对回退开关的区分。小结Hyperf 的hyperf/translation组件以「语言文件 语言环境 翻译函数」为核心提供了从基础键值翻译、占位符大小写替换、复数规则选择到命名空间扩展的完整国际化能力。其关键设计包括独立组件不绑定 Hyperf 框架可复用于其它项目composer.json语言文件驱动storage/languages/{locale}/{group}.php约定目录结构支持 PHP 数组与 JSON 两种格式支持命名空间与 vendor 覆盖FileLoader.php协程安全临时语言环境写入协程上下文互不干扰Translator.php默认语言 回退语言双保险键缺失时原样返回键名便于排查占位符与复数:name/:NAME/:Name自动大小写|管道与{n}/[from,to]/[from,*]区间支持复杂复数规则MessageSelector.php。对于构建面向多语言用户的 Hyperf 应用如中英文官网、国际化 API 提示信息、多语言邮件模板按照本文的目录约定组织语言文件、合理配置locale与fallback_locale再配合__()/trans()/trans_choice()三个全局函数即可快速落地一套稳定、易维护的多语言方案。赞分享后端微服务【免费下载链接】hyperf A coroutine framework that focuses on hyperspeed and flexibility. Building microservice or middleware with ease.项目地址https://gitcode.com/gh_mirrors/hy/hyperf点击查看免费下载相关推荐Hyperf 国际化多语言组件完整实战指南语言文件、占位符与复数规则Hyperf 国际化多语言组件完整实战指南语言文件、占位符与复数规则 导读 Hyperf 提供了开箱即用的国际化i18n支持让您的应用可以轻松面向多后端微服务Hyperf 国际化translation组件实战指南多语言文件、占位符与复数规则全解析Hyperf 国际化translation组件实战指南多语言文件、占位符与复数规则全解析 Hyperf 框架对国际化i18n的支持非常友好通过 hy后端Web框架微服务RPC框架异步编程Hyperf Translation 国际化组件实战指南语言文件、占位符与复数规则的完整实现Hyperf Translation 国际化组件实战指南语言文件、占位符与复数规则的完整实现 Hyperf 的翻译Translation组件为应用提供了一后端微服务上一篇Polipo完全配置手册10个关键参数优化你的代理性能下一篇如何用binarytree快速验证二叉树的各种性质创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表