I would like to internationalize a simple vue application and I utilized vue-i18n
and unplugin-vue-i18n
. I expect the following snippet in vue 3 api composition renders the word John:
<template>
...
<h2>{{ $tm('name') }}</h2>
...
<template>
but it returns weird json string as follows:
{ "type": 0, "start": 0, "end": 3, "loc": { "start": { "line": 1, "column": 1, "offset": 0 }, "end": { "line": 1, "column": 4, "offset": 3 }, "source": "John" }, "body": { "type": 2, "start": 0, "end": 3, "loc": { "start": { "line": 1, "column": 1, "offset": 0 }, "end": { "line": 1, "column": 4, "offset": 3 } }, "items": [ { "type": 3, "start": 0, "end": 3, "loc": { "start": { "line": 1, "column": 1, "offset": 0 }, "end": { "line": 1, "column": 4, "offset": 3 } } } ], "static": "John" } }
Here are the config files:
package.json:
...
"dependencies": {
"@headlessui/vue": "^1.7.23",
"@intlify/unplugin-vue-i18n": "^5.2.0",
"pinia": "^2.1.7",
"vue": "^3.5.9",
"vue-i18n": "^9.14.1",
"vue-router": "^4.3.3"
},
...
vite.config.ts:
import { fileURLToPath, URL } from 'node:url'
import { resolve, dirname } from "node:path";
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import VueI18nPlugin from "@intlify/unplugin-vue-i18n/vite";
export default defineConfig({
server: {
port: 5174
},
plugins: [
vue(),
VueI18nPlugin({
// runtimeOnly: false,
include: resolve(dirname(fileURLToPath(import.meta.url)), './src/locales/**'),
// strictMessage: false
})
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
})
main.ts:
import './assets/main.css';
import { createApp } from 'vue';
import { createI18n } from 'vue-i18n';
import { createPinia } from 'pinia';
import App from './App.vue';
import router from './router';
import messages from '@intlify/unplugin-vue-i18n/messages';
const i18n = createI18n({
legacy: false,
globalInjection: true,
locale: "en",
fallbackLocale: "en",
availableLocales: ["en", "fi"],
messages
});
const app = createApp(App)
app.use(i18n)
app.use(createPinia())
app.use(router)
app.mount('#app')
and en.json file:
{
"name": "John"
}
Would someone please help me to fix it.
Update:
I've created project using the following commands (for reproducing the problom)
npm init vue@latest test
npm install vue-i18n@latest @intlify/unplugin-vue-i18n@latest
Then I set the above configuration. That's it. Also I did according to this and this articles.
As explained in the documentation, tm
returns a message which needs to be resolved to a string with rt
. This can be optional when a message is a string, but this isn't so when they are compiled at build time with @intlify/unplugin-vue-i18n
The correct usage is:
$rt($tm('name'))
Despite that tm
correctly returns compiled message object that is listed in the question, it's not recognized by rt
, this causes this error:
Uncaught SyntaxError: Not support non-string message
at createCompileError (message-compiler.esm-browser.js:116:19)
at createCoreError (core-base.mjs:485:12)
at compileToFunction (core-base.mjs:1008:15)
at compileMessageFormat (core-base.mjs:1324:17)
at translate (core-base.mjs:1168:11)
at vue-i18n.mjs:559:48
at wrapWithDeps (vue-i18n.mjs:504:19)
at t (vue-i18n.mjs:559:16)
at Proxy.rt (vue-i18n.mjs:567:16)
at Proxy._sfc_render (HelloWorld.vue:10:17)
The problem here is version mismatch. Despite that this doesn't seem to be mentioned in the documentation, and major versions of @intlify/unplugin-vue-i18n
and vue-i18n
aren't synchronized, the timeline of new version releases is similar. It should be either @intlify/unplugin-vue-i18n@5
and vue-i18n@10
, or @intlify/unplugin-vue-i18n@4
and vue-i18n@9
, then it becomes workable. Since both major versions of the packages have just been released, this could be a bug.