Composer 项目无内置翻译提取命令,需借助 xgettext 或第三方库实现;推荐用 GNU xgettext 扫描 PHP/Blade 文件提取字符串生成 .pot/.po 文件,并注意排除 vendor、支持多参数及上下文注释。

Composer 项目里没有内置翻译提取命令
Composer 本身不处理国际化(i18n)或文本提取,它只是 PHP 的依赖管理工具。所谓“Composer 国际化翻译脚本”,实际是借助第三方库(如 symfony/translation 或 php-gettext)配合自定义脚本完成的。直接运行 composer translate:extract 会报错——这个命令根本不存在。
真正要做的,是写一个 PHP 脚本或使用现成 CLI 工具,扫描项目中调用翻译函数(如 __('Hello')、trans('welcome')、$translator->trans('save'))的 PHP/Blade/Twig 文件,把字符串抽出来生成 messages.pot 或直接写入 en.po。
用 xgettext 提取 PHP 字符串最轻量可靠
Linux/macOS 下推荐直接用 GNU xgettext(来自 gettext 工具集),它原生支持 PHP 语法解析,比手写正则或依赖框架解析器更稳,尤其对复杂表达式(如 __('Name: ' . $user->name))兼容性更好。
- 先确保已安装:
brew install gettext(macOS)或apt install gettext(Ubuntu) - 基础命令提取所有
__('...')和_e('...'):xgettext --language=PHP --keyword=__ --keyword=_e --output=lang/messages.pot src/ templates/
- 若项目用 Laravel 的
__('...')或trans('...'),加对应--keyword:xgettext --language=PHP --keyword=__ --keyword=trans --keyword=trans_choice --output=lang/messages.pot app/ resources/views/
- 注意:xgettext 默认不递归进子目录,路径末尾不加
/**;含 Blade 文件时,需加--from-code=UTF-8避免乱码
Laravel 项目优先用 vendor/bin/artisan lang:publish
如果你用的是 Laravel,别自己造轮子。Laravel 9+ 内置了 lang:publish 和社区广泛使用的 laravel-lang/publisher,但它们不提取——提取靠的是 laravel-lang/php-xgettext 这类封装脚本。
实操建议:
- 装依赖:
composer require --dev laravel-lang/php-xgettext - 在
composer.json的scripts段加一行:"extract-locales": "php-vendor/bin/xgettext --from-code=UTF-8 --language=PHP --keyword=__ --keyword=@lang --output=lang/en.pot app/ resources/views/"
- 然后运行:
composer extract-locales - 关键细节:Laravel Blade 中
@lang('save')和{{ __('save') }}都得显式加--keyword=@lang,否则漏掉
自定义 PHP 脚本提取时最容易漏掉的三件事
手写 PHP 扫描脚本看似灵活,但容易在边界情况翻车。以下三点几乎必踩:
- 没跳过
vendor/和node_modules/目录——结果把依赖包里的翻译也扫进来了,RecursiveDirectoryIterator初始化时必须手动排除 - 只匹配
__('xxx'),却忽略多参数形式如__('Hello :name', ['name' => $n])或带命名空间的Illuminate\Translation\Translator::get(),导致漏字符串 - 没处理注释上下文,比如
// @translate-context button后面的__('Save')应该打上msgctxt "button",否则中英文同词不同义时(如 “run” 作动词/名词)无法区分
真正跑得稳的提取逻辑,往往不是正则越短越好,而是宁可多几行判断文件后缀、跳过注释块、识别括号嵌套层级——这些细节不处理,后期合稿时人工补漏的成本远高于初期多写十行。











