This is my code, that works without problems:
import { createI18n } from 'vue-i18n'
import messages from './ponents/json/foo/foo_messages.json'
const app = createApp(App)
installI18n(app)
const i18n = createI18n({
locale: 'ru',
messages
})
app
.use(i18n)
.use(vuetify)
.mount('#app')
Now I need to load messages also from ./ponents/json/bar/bar_messages.json
. I tried to do this way:
import { createI18n } from 'vue-i18n'
import foo_msg from './ponents/json/foo/foo_messages.json'
import bar_msg from './ponents/json/bar/bar_messages.json'
const app = createApp(App)
installI18n(app)
const i18n = createI18n({
locale: 'ru',
messages: {foo_msg, bar_msg}
})
app
.use(i18n)
.use(vuetify)
.mount('#app')
But it didn't work. Could anyone say how to do it?
EDIT: This is my foo json file
{
"ru": {
"header": {
"hello": "Привет"
}
},
"en": {
"header": {
"hello": "Hello"
}
}
}
and this is bar json file
{
"ru": {
"footer": {
"bye": "Пока"
}
},
"en": {
"footer": {
"bye": "Goodbye"
}
}
}
This is my code, that works without problems:
import { createI18n } from 'vue-i18n'
import messages from './ponents/json/foo/foo_messages.json'
const app = createApp(App)
installI18n(app)
const i18n = createI18n({
locale: 'ru',
messages
})
app
.use(i18n)
.use(vuetify)
.mount('#app')
Now I need to load messages also from ./ponents/json/bar/bar_messages.json
. I tried to do this way:
import { createI18n } from 'vue-i18n'
import foo_msg from './ponents/json/foo/foo_messages.json'
import bar_msg from './ponents/json/bar/bar_messages.json'
const app = createApp(App)
installI18n(app)
const i18n = createI18n({
locale: 'ru',
messages: {foo_msg, bar_msg}
})
app
.use(i18n)
.use(vuetify)
.mount('#app')
But it didn't work. Could anyone say how to do it?
EDIT: This is my foo json file
{
"ru": {
"header": {
"hello": "Привет"
}
},
"en": {
"header": {
"hello": "Hello"
}
}
}
and this is bar json file
{
"ru": {
"footer": {
"bye": "Пока"
}
},
"en": {
"footer": {
"bye": "Goodbye"
}
}
}
Share
Improve this question
edited Jan 3, 2022 at 15:08
asked Jan 3, 2022 at 15:02
user5182503user5182503
7
- how do the json files look like? – Boussadjra Brahim Commented Jan 3, 2022 at 15:05
- @BoussadjraBrahim Please, see the edit. – user5182503 Commented Jan 3, 2022 at 15:09
- Objects can be merged like this: How can I merge properties of two JavaScript objects dynamically? – Peter Pointer Commented Jan 3, 2022 at 15:32
- @PeterKrebs This will not work as all top level properties (language identifiers) will overwrite other top-level properties from different sources... – Michal Levý Commented Jan 3, 2022 at 15:38
- @MichalLevý Look at the answers further down. For example a recursive object merge. Code can always be adapted to ones needs, like keeping all properties and so on. But it is a good inspiration either way for an answer. – Peter Pointer Commented Jan 3, 2022 at 15:52
2 Answers
Reset to default 4What you are trying to do is not very scalable. Given the format of the i18n JSON messages, you need to merge the input files to something like this:
{
"ru": {
"header": {
"hello": "Привет"
},
"footer": {
"bye": "Пока"
}
},
"en": {
"header": {
"hello": "Hello"
},
"footer": {
"bye": "Goodbye"
}
}
}
...this is definitely possible with JS but you must still import the JSON file for each ponent in your main.js
which is tedious and error prone
Did you consider using vue-i18n custom blocks in your ponents? You can even keep the translations in external JSON files and use a custom block like <i18n src="./myLang.json"></i18n>
this is much better approach but if you stil want to use yours, here is a simple code how to merge all translation files (objects imported from JSON) into a single object usable by vue-i18n:
// import foo_msg from './ponents/json/foo/foo_messages.json'
const foo_msg = {
"ru": {
"header": {
"hello": "Привет"
}
},
"en": {
"header": {
"hello": "Hello"
}
}
}
// import bar_msg from './ponents/json/bar/bar_messages.json'
const bar_msg = {
"ru": {
"footer": {
"bye": "Пока"
}
},
"en": {
"footer": {
"bye": "Goodbye"
}
}
}
const sources = [foo_msg, bar_msg]
const messages = sources.reduce((acc, source) => {
for(key in source) {
acc[key] = { ...(acc[key] || {}), ...source[key] }
}
return acc
},{})
console.log(messages)
The accepted solution is already a good solution, but if you assist to use .json files to translate text. Here is my solution.
Use vue-cli to add i18n dependency, it would generate all the requirement files that we need.
vue add vue-i18n
It would generate the locales folder inside src, which it stores all the translation json files. Then it would generate couple env variable on .env file and a i18n.js file
here is the i18n.js it generates
import { createI18n } from 'vue-i18n'
/**
* Load locale messages
*
* The loaded `JSON` locale messages is pre-piled by `@intlify/vue-i18n-loader`, which is integrated into `vue-cli-plugin-i18n`.
* See: https://github./intlify/vue-i18n-loader#rocket-i18n-resource-pre-pilation
*/
function loadLocaleMessages() {
const locales = require.context('./locales', true, /[A-Za-z0-9-_,\s]+\.json$/i)
const messages = {}
locales.keys().forEach(key => {
const matched = key.match(/([A-Za-z0-9-_]+)\./i)
if (matched && matched.length > 1) {
const locale = matched[1]
messages[locale] = locales(key).default
}
})
return messages
}
export default createI18n({
locale: process.env.VUE_APP_I18N_LOCALE || 'en',
fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE || 'en',
messages: loadLocaleMessages()
})
In our main.js, i had seen that vue has already add the ponent for me
import i18n from './i18n'
const app = createApp(App).use(i18n)
*Edit
I am using vite for building vue project, the loadLocaleMessages
does not work in my case.
I made some modification. It needs to manually import all the json files, but i did not find any alternative solution.
I also change the env variable with 'VITE' prefix, and process.env to import.meta.env.
// import all the json files
import en from './locales/en.json'
import zh from './locales/zh.json'
/**
* Load locale messages
*
* The loaded `JSON` locale messages is pre-piled by `@intlify/vue-i18n-loader`, which is integrated into `vue-cli-plugin-i18n`.
* See: https://github./intlify/vue-i18n-loader#rocket-i18n-resource-pre-pilation
*/
function loadLocaleMessages() {
const locales = [{ en: en }, { zh: zh }]
const messages = {}
locales.forEach(lang => {
const key = Object.keys(lang)
messages[key] = lang[key]
})
return messages
}
export default createI18n({
locale: import.meta.env.VITE_APP_I18N_LOCALE || 'en',
fallbackLocale: import.meta.env.VITE_APP_I18N_FALLBACK_LOCALE || 'en',
messages: loadLocaleMessages()
})