Hyperf Translation 国际化组件实战指南:语言文件、占位符与复数规则的完整实现
后端微服务【免费下载链接】hyperf A coroutine framework that focuses on hyperspeed and flexibility. Building microservice or middleware with ease.项目地址https://gitcode.com/gh_mirrors/hy/hyperf点击查看免费下载Hyperf 的翻译Translation组件为应用提供了一套友好且完备的国际化I18n能力让你可以轻松地让项目支持多种语言。本文以官方文档 docs/en/translation.md 为骨架结合仓库中hyperf/translation组件的真实源码完整讲解组件的安装、语言文件组织、三种 locale 配置方式、字符串翻译、占位符替换与复数处理并深入剖析Translator、MessageSelector、FileLoader等核心类的底层实现让你既能直接上手使用也能理解其内部原理。组件概览一个可独立复用的翻译库Hyperf 的国际化组件hyperf/translation是从illuminate/translation演化而来的独立翻译组件见 src/translation/composer.json 中的描述。它是一个独立组件不依赖 Hyperf 框架主体可以单独引入到其他项目或框架中使用其依赖仅限于hyperf/collection、hyperf/context、hyperf/contract、hyperf/macroable、hyperf/stringable、hyperf/support等轻量级工具包与psr/container并不需要整个框架运行时。在 Hyperf 应用中该组件通过 ConfigProvider 完成自动装配TranslatorLoaderInterface绑定到FileLoaderFactory负责从语言文件加载翻译内容TranslatorInterface绑定到TranslatorFactory负责创建翻译器实例并注入默认 locale 与 fallback locale同时把默认配置文件发布到config/autoload/translation.php。安装使用 Composer 安装即可composer require hyperf/translation安装完成后组件会通过ConfigProvider自动注册依赖与配置发布项。如需生成配置文件执行以下命令Hyperf 框架标准发布方式php bin/hyperf.php vendor:publish hyperf/translation语言文件的组织方式Hyperf 的语言文件默认存放在storage/languages目录下你也可以在配置中修改该目录。每种语言对应一个子目录目录名即语言标识例如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()方法它会拼接{path}/{locale}/{group}.php路径若文件存在则通过getRequire()返回数组内容语言文件名如messages即翻译键中的组group。组件内部如何定位语言目录FileLoaderFactory.php 从配置中心读取translation.path默认值为BASE_PATH . /storage/languages$path $config-get(translation.path, BASE_PATH . /storage/languages); return make(FileLoader::class, compact(files, path));配置 locale国际化的相关配置集中在config/autoload/translation.php文件中该文件由组件发布原始模板见 publish/translation.php你可以按需修改?php // config/autoload/translation.php return [ // 默认语言 locale zh_CN, // 回退语言当默认语言中缺少对应翻译文本时会使用回退语言的对应文本 fallback_locale en, // 语言文件存放目录 path BASE_PATH . /storage/languages, ];配置项说明配置项默认值说明localezh_CN默认语言应用启动后翻译器使用的初始语言fallback_localeen回退语言当指定语言找不到翻译键时按此语言兜底pathBASE_PATH . /storage/languages语言文件所在目录的绝对路径工厂如何消费这些配置TranslatorFactory.php 的创建逻辑印证了上述配置的作用$locale $config-get(translation.locale, zh_CN); $fallbackLocale $config-get(translation.fallback_locale, en); $loader $container-get(TranslatorLoaderInterface::class); $translator make(Translator::class, compact(loader, locale)); $translator-setFallback((string) $fallbackLocale);配置临时 locale按请求 / 协程生效除了全局默认 locale你还可以在运行期为当前请求动态设置临时 locale。由于 Hyperf 运行在 Swoole 协程环境中Translator::setLocale()会把语言存入Context协程上下文因此临时 locale 只在当前请求或当前协程的生命周期内有效不会污染其他协程?php use Hyperf\Di\Annotation\Inject; use Hyperf\Contract\TranslatorInterface; class FooController { #[Inject] private TranslatorInterface $translator; public function index() { // 仅对当前请求或协程生命周期内有效 $this-translator-setLocale(zh_CN); } }其底层实现在 Translator.php 中public function getLocaleContextKey(): string { return sprintf(%s::%s, TranslatorInterface::class, locale); } public function getLocale(): string { $locale Context::get($this-getLocaleContextKey()); return (string) ($locale ?? $this-locale); } public function setLocale(string $locale) { Context::set($this-getLocaleContextKey(), $locale); }注意getLocale()优先返回协程上下文中的 locale只有未设置时才回落到构造时传入的默认 locale。对应的契约定义见 TranslatorInterface.php。翻译字符串方式一注入 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方法的完整签名见 TranslatorInterface.phppublic function trans(string $key, array $replace [], ?string $locale null): array|string;三个参数分别表示翻译键、占位符替换数组可选、临时指定语言可选。方式二使用全局函数__()或trans()组件通过 Functions.php 注册了三个全局函数。函数第一个参数采用key直接用翻译文本作为键或file.key文件加键的形式echo __(messages.welcome); echo trans(messages.welcome);其中__()与trans()完全等价都从容器中取出TranslatorInterface并调用其trans方法function __(string $key, array $replace [], ?string $locale null) { $translator ApplicationContext::getContainer()-get(TranslatorInterface::class); return $translator-trans($key, $replace, $locale); } function trans(string $key, array $replace [], ?string $locale null) { return __($key, $replace, $locale); }键的解析规则Translator::get()首先调用parseKey()把翻译键拆分为[namespace, group, item]三元组不含::的普通键如messages.welcome按.分割第一段是组名group其余段拼成条目名item含::的键视为命名空间键namespace key::前的部分是命名空间解析结果会被缓存到parsed数组避免同一键的重复解析开销。若某个 locale 下找不到翻译get()会按localeArray()返回的语言序列当前语言 fallback 语言依次查找最终仍找不到则直接返回原键名方便在 UI 中快速定位缺失的语言键——这是宁可返回 key 也不抛异常的设计具体逻辑在 Translator.php 的get()方法中。在翻译字符串中定义占位符你可以在语言字符串中定义占位符所有占位符都以:作为前缀。例如以用户名作为占位符?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.php 的makeReplacements()实现它对同一个键同时替换三种形态$line str_replace( [: . $key, : . Str::upper($key), : . Str::ucfirst($key)], [$value, Str::upper($value), Str::ucfirst($value)], $line );替换数组的排序细节makeReplacements()会先调用sortReplacements()对替换数组按键名长度降序排序再执行替换protected function sortReplacements(array $replace): array { return (new Collection($replace))-sortBy(fn ($value, $key) mb_strlen((string) $key) * -1)-all(); }这样可以避免短键名先被替换而截胡长键名的问题例如同时存在:name与:name_en时name_en会优先被替换保证结果的正确性。处理复数Pluralization不同语言的复数规则各不相同。中文通常不需要关注单复数但在翻译其他语言如英语、俄语、阿拉伯语时必须处理名词的复数形式。组件使用竖线字符|来区分字符串的单复数形式apples There is one apple|There are many apples,你也可以指定数字区间来构造更复杂的复数规则apples {0} There are none|[1,19] There are some|[20,*] There are many,区间语法说明语法含义{0}精确匹配数字 0[1,19]闭区间匹配 1 到 19含两端[20,*]从 20 到无穷大[*,5]从负无穷到 5组件同样支持*作区间下界使用 trans_choice 取复数文本定义好复数规则后可通过全局函数trans_choice根据给定的数量获取对应字符串。在下面的示例中由于数字大于1将返回翻译字符串的复数形式echo trans_choice(messages.apples, 10); // 输出There are many apples除了全局函数trans_choice()也可以使用Hyperf\Contract\TranslatorInterface的transChoice方法$this-translator-transChoice(messages.apples, 10);底层实现MessageSelector复数选择的核心逻辑位于 MessageSelector.php 的choose()方法处理流程分为两步区间条件优先匹配先调用extract()/extractFromString()用正则preg_match(/^[\{\[](https://link.gitcode.com/i/a2eb137607123d8aa67a39b8c892f326)[\}\]](.*)/s, ...)解析{0}、[1,19]这类带条件的片段若命中区间则直接返回对应文本语言复数索引兜底若无区间条件则剥掉条件前缀后调用getPluralIndex($locale, $number)根据语言获取复数索引。getPluralIndex()内置了覆盖数十种语言含zh_CN、en、fr、ru、ar等及各自地区变体的复数规则表例如中文恒返回索引0英语按number 1返回0否则1俄语则按%10与%100的组合规则返回三态索引。Translator::choice()在调用选择器之前还会注入一个特殊占位符$replace[count] $number;这意味着你可以在复数文本中使用:count占位符输出实际数量例如apples {0} There are none|[1,19] There are :count apples|[20,*] There are many。此外choice()的$number参数也支持传入数组或可计数的对象组件会自动取其元素数量作为判断依据。进阶能力JSON 翻译与命名空间覆盖除 PHP 语言文件外从 FileLoader.php 的源码可以看出组件还支持两类进阶用法文档中虽未展开但已内置于实现中JSON 翻译文件FileLoader::loadJsonPaths()会尝试加载{path}/{locale}.json文件例如storage/languages/zh_CN.json解析失败时会抛出RuntimeException。配合Translator::getFromJson()方法键可直接使用翻译文本本身例如__(Welcome to our application)会先在 JSON 文件中查找找不到再回落到普通语言文件最终返回makeReplacements()处理后的文本。FileLoader还支持通过addJsonPath()注册额外的 JSON 翻译目录。命名空间与 vendor 覆盖当翻译键包含::如package::messages.welcome时FileLoader::loadNamespaced()会先从命名空间提示路径addNamespace()注册的 hint加载翻译再尝试从{path}/vendor/{namespace}/{locale}/{group}.php读取覆盖文件并用array_replace_recursive()递归合并实现组件自带翻译 应用本地覆盖的分层机制。备选加载器ArrayLoader除了从文件加载组件还提供了内存加载器 ArrayLoader.php通过addMessages(string $locale, string $group, array $messages, ?string $namespace null)把翻译直接注入内存适合单元测试或动态注册翻译的场景。它与FileLoader共同实现TranslatorLoaderInterface可以在容器中替换绑定。组件装配与依赖注入关系一览综合 ConfigProvider.php 的注册内容整个组件的依赖关系如下接口 / 配置实现 / 来源说明Hyperf\Contract\TranslatorInterfaceTranslatorFactory创建的Translator翻译器主入口读取translation.locale与translation.fallback_localeHyperf\Contract\TranslatorLoaderInterfaceFileLoaderFactory创建的FileLoader语言加载器读取translation.pathconfig/autoload/translation.phppublish/translation.php发布组件配置文件全局函数__()/trans()/trans_choice()Functions.php通过ApplicationContext::getContainer()获取翻译器Translator还使用了Macroabletrait见 Translator.php 第 26 行允许你在运行时为其扩展自定义方法。测试验证组件在 tests 目录下提供了三组测试可用于验证本文描述的行为TranslatorTest.php验证工厂默认 localezh_CN、has()方法、占位符替换、复数选择与并发场景下的 locale 隔离等MessageSelectorTest.php验证区间条件、复数索引及各类语言规则FileLoaderTest.php验证文件加载、命名空间与 JSON 路径处理。你可以在仓库根目录运行对应测试来印证实现行为composer test src/translation 2/dev/null || vendor/bin/phpunit --configuration phpunit.xml.dist src/translation/tests总结Hyperf 的翻译组件以语言文件 翻译器 选择器 加载器四层结构提供了一套从基础翻译到复杂复数的完整国际化方案。日常使用中只需记住四件事语言文件放storage/languages并按locale/组.php组织配置文件设好locale、fallback_locale与path翻译时用__()、trans()或注入的TranslatorInterface复数场景用trans_choice()配合|与区间语法。需要更精细控制时还可借助协程上下文实现按请求切换语言、使用 JSON 翻译文件或通过命名空间机制实现组件翻译的本地覆盖。赞分享后端微服务【免费下载链接】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 I18n 多语言国际化translation 组件完整实战指南Hyperf I18n 多语言国际化translation 组件完整实战指南 Hyperf 的国际化I18n能力由独立的 hyperf/translati后端Web框架微服务RPC框架异步编程Docker快速部署Wan2.1-Fun-1.3B-InP从镜像拉取到视频输出全程实录Docker快速部署Wan2.1 Fun 1.3B InP从镜像拉取到视频输出全程实录 想要快速体验最新的AI视频生成技术吗 今天我将为大家详细介绍如何上一篇5分钟给Windows 11 24H2 LTSC装回Microsoft StoreLTSC-Add-MicrosoftStore快速上手教程下一篇工具调用、多轮强化学习与Deep ResearchHands-On Modern RL Agentic RL完整实战创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

ORA-01623 无法删除redo

ORA-01623 无法删除redo

这个是线程2的redo,当前环境是单机,关闭线程2即可删除关闭集群模式(重启生效) ALTER SYSTEM SET cluster_databaseFALSE SCOPESPFILE;关闭线程2(如果可以直接关闭) ALTER DATABASE DISABLE THREAD 2;

2026/10/13 20:09:24 阅读更多 →
DeepSeek V4 MegaMoE与DeepGEMM:大模型推理底层优化拆解

DeepSeek V4 MegaMoE与DeepGEMM:大模型推理底层优化拆解

做算法的人学 Infra,最怕的就是被一堆源码和术语劝退。但如果你真的想把一个大模型跑明白,绕不开 GPU 底层发生了什么。今天这篇是“算法同学学 Infra 系列”的第三篇,专门讲 DeepSeek V4 里最核心的 MegaMoE 架构,以及把它跑起来…

2026/10/13 7:38:27 阅读更多 →
AI应用工程化:Agent编排、MCP与RAG如何从Demo走向生产

AI应用工程化:Agent编排、MCP与RAG如何从Demo走向生产

搞AI应用开发的朋友最近都在聊Agent编排和MCP,我自己的体感是:单纯会调大模型API已经不够了,真正麻烦的是怎么把一个会思考、会查资料、会调工具的Agent稳定地推向生产环境。XXL-AI这个平台就是在这个背景下进入视野的,它把Agent编…

2026/10/13 8:05:18 阅读更多 →

最新新闻

PS5串流实战指南:从局域网到外网的远程游戏配置与延迟优化

PS5串流实战指南:从局域网到外网的远程游戏配置与延迟优化

直接接PS5玩家一个很现实的问题:这台机器买回来之后,是不是基本就长在客厅电视柜上了?客厅被占、卧室想玩、出差想刷两把,每次都只能乖乖回到电视前。我捣鼓AnyPS5这套串流方案,就是为了把这台主机从HDMI线的长度里解放…

2026/10/13 20:09:06 阅读更多 →
若依vue3前端页面框架:路由联动、权限指令与缓存机制解析

若依vue3前端页面框架:路由联动、权限指令与缓存机制解析

简介:若依vue3前端页面框架是一套基于Vue3与Element Plus的开源后台管理前端解决方案,面向需要快速搭建企业级系统的开发团队及初中级前端工程师,适用于中后台管理系统、权限控制界面、数据看板等典型场景。压缩包共299个文件、约3MB&#xf…

2026/10/13 20:09:06 阅读更多 →
嵌入式视觉系统中MT9M001C到LCD的端到端时序设计

嵌入式视觉系统中MT9M001C到LCD的端到端时序设计

简介:本资源是面向FPGA初学者与嵌入式图像处理学习者的实战项目,聚焦于MT9M001 CMOS图像传感器的驱动与实时显示实现,适用于基于Altera/Intel FPGA平台的开发板验证与课程实验。项目完整呈现了从传感器数据采集、FPGA逻辑控制(含时…

2026/10/13 20:09:06 阅读更多 →
PS5全机型优化指南:从版本识别、M.2扩展到HDMI 2.1设置与故障排查

PS5全机型优化指南:从版本识别、M.2扩展到HDMI 2.1设置与故障排查

如果你手头有一台 PS5,或者正打算入手,不管是初版、轻薄版还是 Pro 版,这篇文章都是给你准备的。我写这个东西的起因很简单:群里隔三差五就有人问"我这个 PS5 为什么风扇声音这么大""到底要不要上 Pro""…

2026/10/13 20:09:06 阅读更多 →
STM32跑马灯实验详解:从时钟配置到GPIO驱动与工程下载

STM32跑马灯实验详解:从时钟配置到GPIO驱动与工程下载

简介:这份资源是面向嵌入式初学者与STM32入门者的跑马灯实验例程包,围绕GPIO输出控制这一核心知识点,帮助读者快速上手STM32微控制器的基本开发流程。资源以ALIENTEK MINISTM32开发板为硬件平台,配套完整工程代码与详细注释&#…

2026/10/13 20:09:06 阅读更多 →
Steinberg VST插件开发包入门:从零构建VST3音频插件

Steinberg VST插件开发包入门:从零构建VST3音频插件

简介:Steinberg VST插件开发包(VST3 SDK 3.5版)面向音频插件开发者、音乐软件工程师及数字音频工作站扩展爱好者,提供创建虚拟乐器与音频效果处理器所需的完整开发环境。包内共5764个文件,以html文档、png界面素材、h头…

2026/10/13 20:08:06 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →