本页要实现的目标
以多语言分发包的消息,并让使用方应用程序只修改所需的文案。将翻译键和占位符视为公开 API,并梳理在包更新时保留自定义内容的方法。 本地化介绍应用程序中的基本操作,Laravel 包开发介绍注册与发布的基础。本页将深入 Laravel 13 中ServiceProvider、FileLoader、Translator 的实现。
loadTranslationsFrom() 注册的是加载位置,publishes() 注册的是文件的复制目标。使用方无需为了使用翻译而必须执行 vendor:publish。以命名空间分发 PHP 翻译
如果希望拥有包专属的键,请使用 PHP 数组格式和命名空间。以下是名为Acme\Courier 的包的示例。
lang/ja/messages.php 中准备日语的默认值。
lang/en/messages.php 中也准备用于回退的英语。
boot() 中注册加载以及可选的发布。
ja,这与本文档站点 URL 中使用的 jp 不同。
courier 是 loadTranslationsFrom() 的第 2 个参数,并不会根据 Composer 的包名自动确定。
PHP 翻译不会整体替换文件
在使用方应用程序中,如果使用标准的语言目录,可以只在lang/vendor/courier/ja/messages.php 中写入要修改的键。即使更改了语言目录,也应使用 $this->app->langPath('vendor/courier') 下的路径。
queued 发生变化,failed 仍使用包的日语翻译。
FileLoader 的加载顺序
ServiceProvider::loadTranslationsFrom() 在 Translator 解析后注册命名空间。实际的文件读取发生在请求翻译时。
FileLoader::loadNamespaced() 会加载已注册包的语言文件,并将该数组传给 loadNamespaceOverrides()。在那里,它读取加载器各语言路径中的 vendor/{namespace}/{locale}/{group}.php,并通过 array_replace_recursive() 进行替换。
标准的 TranslationServiceProvider 会按此顺序将框架的语言路径和应用程序的语言路径传给加载器。即使存在注册额外路径的扩展,后加载的覆盖数组也会对相同的键优先。
JSON 翻译没有包专属的命名空间
对于以句子作为键的 JSON 翻译,按如下方式注册目录。这是与前面的 PHP 翻译不同的另一种选择。lang/ja.json 示例如下。
loadJsonTranslationsFrom() 没有命名空间参数。已注册的 JSON 翻译与其他包和应用程序共享同一个键空间。
JSON 的覆盖位置是应用程序的 ja.json
FileLoader::loadJsonPaths() 会先读取已注册的 JSON 路径,然后读取常规语言路径,并进行 array_merge()。在标准配置下,应用程序 lang/ja.json 中相同的字符串键会覆盖包的值。
- 如果多个包使用相同的字符串键,后加载的 JSON 的值优先。应避免依赖 Provider 顺序的设计。
lang/vendor/courier/ja.json不是标准 JSON 加载器的覆盖位置。即使将 PHP 用的发布设置直接套用到 JSON 上,该位置也不会被自动读取。- 即使通过
publishes()将包的 JSON 发布到应用程序的lang/ja.json,文件内容也不会被合并。为避免破坏现有翻译,请引导使用方只添加所需的键。
Translator::get() 会先查找 JSON 中完全匹配的键,如果在 JSON 中定义了 courier::messages.delivery.queued 这样的键,它会优先于 PHP 侧。通常应采用不混用句子键和 PHP 格式键的方针。
在不破坏已发布翻译的情况下更新
对于希望一次性发布 PHP 翻译的使用方,可以引导其使用限定对象范围的命令。- 保持键和命名空间不变 — 删除或移动键会影响使用方的
__()调用和覆盖位置。请考虑添加新键并保留旧键的过渡期。 - 保持占位符不变 — 如果将
:name改为:recipient,调用方的替换数组也需要修改。不要将其视为仅修改翻译文件的变更。 - 对比检查已发布的文件 — 比较使用方的覆盖与新的默认值。删除不再需要的覆盖键后,即可恢复为包的值。
- 避免无条件重新发布 — 使用
--force重新发布会覆盖使用方的自定义内容。在将 JSON 复制到应用程序文件的设计中,还可能丢失其他翻译。 - 在常驻进程中确认 —
Translator::load()会在实例内保存每个命名空间、分组和语言的数组。在仍保留已加载 Translator 的进程中,仅修改文件不一定会重新加载。请根据运维情况重启 Worker 等。
在使用方应用程序中确认的项目
在注册了服务提供者的验证用应用程序中,确认以下组合。关于包内测试环境的搭建,请参阅使用 Orchestra Testbench 测试 Laravel 包。
在加载后再创建覆盖文件的测试中,要确保 Translator 已有的加载结果不会产生影响。请先准备好文件再获取,或者为每个用例使用新的应用程序实例进行确认。
参考的一手资料
官方文档确认的是最新的默认分支13.x,内部实现确认的是参考时最新的发布版本 v13.35.0。