Vue.js i18n与Laravel共用翻译文件:变量插值格式不兼容问题的解决方案咨询
我之前开发Laravel+Inertia+Vue项目时,刚好碰到过和你一模一样的问题!当时也是想共用翻译文件,结果卡在了变量格式不兼容这儿,折腾了好一会儿才找到靠谱的解决办法,给你分享几个可行的思路:
方案1:启用Vue I18n兼容模式,配置插值分隔符
如果你的Vue I18n是v9+版本,其实可以通过启用legacy兼容模式来配置插值的前缀/后缀,让它直接支持Laravel的:variable格式,不用修改任何翻译文件。
具体代码如下:
import { createI18n } from 'vue-i18n' const i18n = createI18n({ legacy: true, // 关键:启用兼容模式,才能使用interpolation配置 locale: 'zh-CN', // 你的默认语言 fallbackLocale: 'en', messages: { // 直接加载Laravel的翻译文件,用:variable格式即可 zh: require('../lang/zh.json'), en: require('../lang/en.json') }, interpolation: { prefix: ':', // 匹配Laravel的变量前缀 suffix: '' // Laravel的变量没有后缀,留空即可 } })
这样配置后,Vue I18n就能像Laravel一样识别:variable格式的变量,完美共用同一套翻译文件。
方案2:加载翻译时自动转换变量格式
如果你不想用legacy模式,或者更倾向于保持Vue I18n的默认{variable}格式,可以在Laravel端返回翻译文件时,自动把:variable转换成{variable},这样Vue端不用做任何配置,直接用默认规则即可。
在Laravel里写一个接口来返回转换后的翻译:
// routes/api.php use Illuminate\Support\Facades\File; Route::get('/translations/{locale}', function ($locale) { $translations = []; // 加载指定语言的所有翻译文件 $files = File::allFiles(resource_path("lang/{$locale}")); foreach ($files as $file) { $key = str_replace('.php', '', $file->getFilename()); // 递归替换所有:var为{var} $translations[$key] = convertLaravelVars(require $file->getPathname()); } return response()->json($translations); }); // 递归处理数组中的翻译文本 function convertLaravelVars($array) { array_walk_recursive($array, function (&$value) { if (is_string($value)) { // 用正则把:xxx替换成{xxx} $value = preg_replace('/:(\w+)/', '{$1}', $value); } }); return $array; }
然后在Vue端,通过axios请求这个接口获取翻译数据,再注入到Vue I18n中即可:
import { createI18n } from 'vue-i18n' import axios from 'axios' const i18n = createI18n({ locale: 'zh-CN', fallbackLocale: 'en', messages: {} // 先留空,后续动态加载 }) // 动态加载翻译 async function loadTranslations(locale) { const response = await axios.get(`/translations/${locale}`) i18n.global.setLocaleMessage(locale, response.data) } // 初始化加载默认语言 loadTranslations('zh-CN') export default i18n
这个方案的好处是不依赖Vue I18n的版本,而且Laravel端依然可以正常使用原来的:variable格式。
方案3:自定义Vue I18n消息编译器(适用于v9+ Composition API)
如果你想用Vue I18n的新Composition API,又不想用legacy模式,可以自定义一个消息编译器,在编译翻译文本时自动转换变量格式。
代码示例:
import { createI18n } from 'vue-i18n' import { compile } from '@intlify/message-compiler' // 自定义编译器:先把:var转换成{var},再用默认编译器处理 const customCompiler = (message) => { const convertedMsg = message.replace(/:(\w+)/g, '{$1}') return compile(convertedMsg) } const i18n = createI18n({ locale: 'zh-CN', fallbackLocale: 'en', messages: { /* 加载Laravel格式的翻译文件 */ }, messageCompiler: customCompiler // 注入自定义编译器 })
这样Vue I18n在处理翻译文本时,会先自动转换变量格式,再进行编译,完美兼容Laravel的翻译文件。
另外,你之前碰到的[intlify] Not supported 'formatter'错误,是因为Vue I18n v9+已经移除了旧的formatter选项,换成了更灵活的messageCompiler或者legacy模式下的interpolation配置,所以旧方案才会失效。
内容的提问来源于stack exchange,提问作者Axel Moriceau

