vue-i18n
vue-i18n copied to clipboard
Using vue-i18n with json files instead
Hello, so I am about to start using the plugin ,however I failed finding examples or pointers on how to utilize .json Files. The gist of it is this: I have 7 .json files - all in different languages(translations of one another) which i need to switch between in my app (basically in Vuex , within the store mutations ,actions etc) The folder structure is standart and I have created a -- translations[folder] --example.json[files] I can't figure out how to point to these files to get my translations from them , a basic example would probably get me going , thank you in advance! Sorry for the inconvenience I may cause. Yours truly,
Something like this: https://github.com/kimuraz/vue-i18n-json ?
@kimuraz Not exactly... I think , cause I have 7 json files that need to be switched between using vuex mutations and cases for each language. I attempted a couple of times to fetch(),axios.get() the folder containing those files , although I might be completely wrong in my approach. The basic Idea is to switch between the jsons for each translation using state and functions within the store that call the change of state and commit it (action,mutations) etc. That's why I was thinking that calling it somehow with fetch,axios etc and storing the resp.data of each to the state would be optimal for those needs...
If I understood correctly, you want something like this: Two json files for two different languages:
// en.json
{
"hello": "Hello"
}
// de.json
{
"hello": "Guten tag"
}
In the same folder, you can add an index.js file:
// index.js
import en from './en.json'
import de from './de.json'
export const defaultLocale = 'en'
export const languages = {
en: en,
de: de,
}
After that, in your main.js file you should do this:
// main.js
import VueI18n from 'vue-i18n'
Vue.use(VueI18n)
import { languages } from './i18n/index.js'
import { defaultLocale } from './i18n/index.js'
const messages = Object.assign(languages)
Vue.config.productionTip = false
var i18n = new VueI18n({
locale: defaultLocale,
fallbackLocale: 'de',
messages
})
...
// don't forget to pass i18n to the Vue instance
new Vue({
router,
i18n,
render: (h) => h(App),
}).$mount('#app')
If I understood correctly, you want something like this: Two json files for two different languages:
// en.json { "hello": "Hello" }
// de.json { "hello": "Guten tag" }
In the same folder, you can add an index.js file:
// index.js import en from './en.json' import hr from './de.json' export const defaultLocale = 'en' export const languages = { en: en, de: de, }
After that, in your main.js file you should do this:
// main.js import VueI18n from 'vue-i18n' Vue.use(VueI18n) import { languages } from './i18n/index.js' import { defaultLocale } from './i18n/index.js' const messages = Object.assign(languages) Vue.config.productionTip = false var i18n = new VueI18n({ locale: defaultLocale, fallbackLocale: 'de', messages }) ... // don't forget to pass i18n to the Vue instance new Vue({ router, i18n, render: (h) => h(App), }).$mount('#app')
Actally the json file looks like this { library : { "hello": "Hello from library" }, documents: { "hello": "Hello from documents" } i can't $t(documents.hello)
@bonchevski I think that's not a valid json file. Try it like this:
{
"library":{
"hello":"Hello from library"
},
"documents":{
"hello":"Hello from documents"
}
}
If I understood correctly, you want something like this: Two json files for two different languages:
// en.json { "hello": "Hello" }
// de.json { "hello": "Guten tag" }
In the same folder, you can add an index.js file:
// index.js import en from './en.json' import hr from './de.json' export const defaultLocale = 'en' export const languages = { en: en, de: de, }
After that, in your main.js file you should do this:
// main.js import VueI18n from 'vue-i18n' Vue.use(VueI18n) import { languages } from './i18n/index.js' import { defaultLocale } from './i18n/index.js' const messages = Object.assign(languages) Vue.config.productionTip = false var i18n = new VueI18n({ locale: defaultLocale, fallbackLocale: 'de', messages }) ... // don't forget to pass i18n to the Vue instance new Vue({ router, i18n, render: (h) => h(App), }).$mount('#app')
Exactly what I was looking for - works great paired together with .json files that are part of Laravel application!
From my perspective better create default locale folder near assets and in those folder store localization files. I mean it's better for developer and who will work with those files.
For big projects rather difficult to manage big files with localization and for that store files in pages folder. For now i don't know complexity of this but in vue files
vueI18n: {
messages: {
``` and manage in big projects it's something like pain
├── assets
├── locales
| ├── en.json
| └── de.json
├── pages
| ├── Home
| | ├── Home.vue
| | ├── locales
| | └── └── en.json
└── └── about.vue
In Nuxt strict structure for components and pages so for locales also will be good.
Any ideas?
Thanks
+1
From my perspective better create default locale folder near assets and in those folder store localization files. I mean it's better for developer and who will work with those files.
For big projects rather difficult to manage big files with localization and for that store files in pages folder. For now i don't know complexity of this but in vue files
vueI18n: { messages: { ``` and manage in big projects it's something like pain ├── assets ├── locales | ├── en.json | └── de.json ├── pages | ├── Home | | ├── Home.vue | | ├── locales | | └── └── en.json └── └── about.vue In Nuxt strict structure for components and pages so for locales also will be good. Any ideas? Thanks
@uharbachou Hi I am trying to implement similar structure for my i18n files. But my translations from the component folders are not being fetched. Can you help me on it ? Did you make some changes in default i18n.js
file ?
@ZtheLeader +1 And me interesting, how to realize this structure?
@Sendoo I found out the solution. You just give src
to your separate i18n.json
file. Like
<i18n src="source-to-your-file"></i18n>
For more info: http://kazupon.github.io/vue-i18n/guide/sfc.html#multiple-custom-blocks
// main.js
import VueI18n from 'vue-i18n'
Vue.use(VueI18n)
import { languages } from './i18n/index.js'
import { defaultLocale } from './i18n/index.js'
const messages = Object.assign(languages)
The Object.assign
does not work on IE. Can I replace it with something else?
// main.js import VueI18n from 'vue-i18n' Vue.use(VueI18n) import { languages } from './i18n/index.js' import { defaultLocale } from './i18n/index.js' const messages = Object.assign(languages)
The
Object.assign
does not work on IE. Can I replace it with something else?
https://stackoverflow.com/questions/42091600/how-to-merge-object-in-ie-11
// main.js import VueI18n from 'vue-i18n' Vue.use(VueI18n) import { languages } from './i18n/index.js' import { defaultLocale } from './i18n/index.js' const messages = Object.assign(languages)
The
Object.assign
does not work on IE. Can I replace it with something else?https://stackoverflow.com/questions/42091600/how-to-merge-object-in-ie-11
Or add a polyfill and make your code futureproof : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Polyfill
Personally I use polyfill.io in most of my projects as it polyfills based on the browser's needs : https://polyfill.io/v3/
In my perspective, I prefer to make different files based on models/classes. So my structure is:
// src/locales/user.json
{
"en": {
"user": {
"attributes": {
"login": "Login",
"password": "Password"
}
}
}
"pt": {
"user": {
"attributes": {
"login": "Usuário",
"password": "Senha"
}
}
}
}
// src/plugins/i18n.js
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import userMessages from '../locales/user.json'
export const defaultLocale = "en"
export const messages = Object.assign({
...userMessages,
(you can add here other json, with "...blabla")
})
// src/main.js
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import './plugins/i18n'
import { defaultLocale, messages } from './plugins/i18n'
const i18n = new VueI18n({
locale: defaultLocale,
fallbackLocale: 'pt',
messages
})
new Vue({ i18n }).$mount("#app")
Now you can use like this:
<span>{{ $t("user.attributes.role") }}</span>
The solution of @dekadentno helped me a lot!!
I have a similar issue so I decided to use this one instead creating another one. Here is:
I have an Settings page with an <option v-for>
iterating over the languages. Here is a piece of code:
<select v-model="$i18n.locale">
<option
v-for="locale in $i18n.availableLocales"
:key="`locale-${locale}`"
:value="locale"
>
{{ locale }}
</option>
</select>
It is working very nice, however the in the Front-End user was seeing the key of the locale (en, pt, ja). To solve this I did a weird solution that is working but it seems to be so incorrect:
import { createI18n } from "vue-i18n/index";
import en from "./en.json";
import ja from "./ja.json";
import pt from "./pt-br.json";
const messages = {
"English": en,
"Português": pt,
"日本語": ja,
};
// Create i18n instance with options
export const i18n = createI18n({
locale: "English",
fallbackLocale: ["Português", "日本語"],
messages,
});
Although this is working, it seems to me to be very incorrect. So how could I display the locales values instead of their keys?
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-compiled by `@intlify/vue-i18n-loader`, which is integrated into `vue-cli-plugin-i18n`.
* See: https://github.com/intlify/vue-i18n-loader#rocket-i18n-resource-pre-compilation
*/
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 component 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-compiled by `@intlify/vue-i18n-loader`, which is integrated into `vue-cli-plugin-i18n`.
* See: https://github.com/intlify/vue-i18n-loader#rocket-i18n-resource-pre-compilation
*/
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()
})
Anyone with an idea how to insert @
in a JSON? Already tried {@}
and almost all versions of @intlify/vite-plugin-vue-i18n
.
setup: quasar............. v2.11.5 vite............... v2.9.15
@BernhardSchlegel, if you using it in vite.config.ts
try this:
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite'
import vue from '@vitejs/plugin-vue'
import { fileURLToPath, URL } from 'node:url'
import path from 'path'
import { defineConfig } from 'vite'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
VueI18nPlugin({
include: path.resolve(__dirname, './src/i18n/**')
})
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
'vue-i18n': 'vue-i18n/dist/vue-i18n.runtime.esm-bundler.js'
}
}
})
Thanks @arnonrdp ! I suppose the relevant line is '@': fileURLToPath(new URL('./src', import.meta.url)),
. Can you elaborate a little bit what it does, I'd love to understand is.
So my goal is to have a JSON like
{
"hello": "w@rld"
}
This line of code is defining an alias named "@" to a path based on the URL of the folder "./src". The "fileURLToPath" function converts the URL to a file path and the alias is used as a shorter and more convenient way of referring to the path. This is useful for importing files and folders into other files in the project, allowing you to avoid having to write the full path to each file or folder you want to import. -- ChatGPT
More details here: https://github.com/intlify/bundle-tools/tree/main/packages/unplugin-vue-i18n