kazupon / vue-i18n Goto Github PK
View Code? Open in Web Editor NEW:globe_with_meridians: Internationalization plugin for Vue.js
Home Page: https://kazupon.github.io/vue-i18n/
License: MIT License
:globe_with_meridians: Internationalization plugin for Vue.js
Home Page: https://kazupon.github.io/vue-i18n/
License: MIT License
Hey folks!
This is by far the best internationalization library for VueJs I've found so far, but like every other library I think it has a pretty major short-coming. Pluralization of course. The translators have to make a separate string for multiple items and one for a single item.
I would propose an API similar to that of Laravel/Symfony as it is already known by many developers (at least those of us who come from the back-end) and it is pretty straight-forward. https://laravel.com/docs/5.2/localization#pluralization
To fit with this library the API would maybe be something like {{ $tc('user.have_apples', x) }}
, which could then output either You have one apple
or You have four apples
depending on the value of x
.
A feature like this would be extremely helpful for pretty much all projects, especially as there are no real good workarounds. Hope we see this feature in an upcoming version! 😃
Hi there,
I have a JSON such as:
{
"statuses": {
"good: "Good",
"bad: "Bad",
}
}
In my .vue
files I'm using, for example:
<p>
{{ $t(`statuses.${status}`) }}
</p>
This works fine in all browsers except IE.
It works however if I change it to the classic style:
<p>
{{ $t('statuses.' + status') }}
</p>
Note: Remove use of template literals and concat string instead. Unfortunately this is then breaking the airbnb/javascript guidelines, so this is not an option for me.
Is this known? Any way around this?
I am using the webpack vue-cli template.
Thanks
about what time for 3.0.0 ?
Hello.
I have several big files with locales. What is the best way to include them to i18n?
I see only one solution now, add all locales anywhere in global scope (f.e. window
) and then init
Vue.use(window['vue-i18n'], {
lang: 'en', // here I want to set 1st language I defined
locales: window.locales
})
But uncomfortable, because I must define all locales before Vue.use()
.
Vue use function:
Vue.use = function (plugin) {
/* istanbul ignore if */
if (plugin.installed) {
return
}
// additional parameters
var args = toArray(arguments, 1)
args.unshift(this)
if (typeof plugin.install === 'function') {
plugin.install.apply(plugin, args)
} else {
plugin.apply(null, args)
}
plugin.installed = true
return this
}
and vue-i18n install function
function install(Vue) {
var opts = arguments.length <= 1 || arguments[1] === undefined ? { lang: 'en', locales: {} } : arguments[1];
defineConfig(Vue.config, opts.lang);
(0, _extend2['default'])(Vue, opts.locales);
}
with auto install of vue-i18n
if (typeof window !== 'undefined' && window.Vue) {
window.Vue.use(install);
}
Plugin will not install twice, which cause the locale always be empty and the following has no effect.
Vue.use(i18n, {
lang: 'ja',
locales: locales
})
My localization code consist of items like this
error: {
5: 'Invalid username or password'
}
$t('error.5')
returns error.5
string.
Where 5
is number of ESS code from server.
Works only with
'error.5': 'Invalid username or password'
But this style available only for root-placed keys. Look:
'ich.ni': {
'san': '3' // returns 'ich.ni.san' instead of '3'
}
ex: 2.0.0-beta.3, 4.1.0
// main.js
import Vue from 'vue'
import VueResource from 'vue-resource'
import VueI18n from 'vue-i18n'
import router from './router/routes.js'
import App from './App'
// =======================
// Store
// =======================
Vue.use(VueResource)
// =======================
// Localization
// =======================
Vue.use(VueI18n)
// let self = this
const lang = 'de'
Vue.locale(lang, function () {
// self.loading = true
return fetch('../static/lang_' + lang + '.json', {
method: 'get',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
}).then(function (res) {
return res.json()
}).then(function (json) {
// self.loading = false
if (Object.keys(json).length === 0) {
return Promise.reject(new Error('locale empty !!'))
} else {
return Promise.resolve(json)
}
}).catch(function (error) {
// self.error = error.message
console.error(error.message)
return Promise.reject()
})
}, function () {
Vue.config.lang = lang
})
/* eslint-disable no-new */
new Vue({
router,
render: h => h(App),
http: {
root: '/root',
headers: {
Authorization: 'Basic YXBpOnBhc3N3b3Jk'
}
}
}).$mount('app')
//lang_de.json
{
"apptitle": "App erstellen",
"headnav": {
"help": "Hilfe / FAQ",
"register": "Registrieren",
"login": "Anmelden"
}
}
// Template
<template lang="pug">
header.brandbar
h1.brand__title {{ $t("apptitle") }}
</template>
No warnings :)
I try to use your plugin with webpack and vue, and it does what it says - apptitle
is rendered as App erstellen
, but i get annoying console-warnings:
[vue-i18n] Cannot translate the value of keypath "apptitle". Use the value of keypath as default
Hello,
First of all, thank you for sharing this wonderful plugin! :)
I am facing a problem with loops.
In fact, the plugin returns the default value in loops.
Example:
<ul class="list-files">
<li v-for="file in files">
<ul class="file-actions">
<li><a href="#" @click="insertFile">{{ $t('insert') }}</a></li>
<li><a href="#" @click="deleteFile">{{ $t('delete') }}</a></li>
</ul>
<div class="file-name">
<a href="{{ file.url }}" title="{{ file.name }}">{{ file.name }}</a>
</div>
</li>
</ul>
Am I doing something wrong?
Thanks in advance.
ex: 1.0.26, 4.1
vue-i18n is working great in a project.
When I npm install my project on another computer however, it is making an error in the console and the translations don't display.
the error:
Error when evaluating expression "$t("my-expression": TypeError: Cannot read property 'util' of undefined
I don't see any diference in the 2 computers configuration. What can I do to solve this?
Thank you
Hello
As the title says, how i can change the language at runtime?
Using this $t('site.name', getLang()) and implementing getLang() in each component seems dumb.
And chaning Vue.config.lang does nothing.
Is there a way to change it?
Thanks, Ivan.
I would like to create translatable reusable component, but I cannot figure out how to override component default locales from global locales. Is it possible now?
Like this maybe
In component:
locales: {
en: { hello: 'world' },
}
In global locales:
en: { componentName: { hello: 'my world' } }
with version 4.3, there is a problem when doing npm install vue-i18n:
npm ERR! [email protected] postinstall: `gitbook install ./gitbook`
npm ERR! spawn ENOENT
npm ERR!
npm ERR! Failed at the [email protected] postinstall script 'gitbook install ./gitbook'.
and then it's not installed in node_modules
I have locale strings like
var locale = {
de: {
"Next": "Weiter",
"%{page} of %{total}": "%{page} von %{total}",
"fubar": "%{page} von %{total}",
}
}
and use them like
// This shows 'Weiter' for locale 'de'
$('Next')
// This does not work for either locale
$t("%{page} of %{total}", { page: human_page, total: total})
// This works for 'de' locale
$t("fubar", { page: human_page, total: total})
I expected the path
argument of $(t)
to be treated as a verbatim text string:
I'm getting Unknown TypeError: Vue.locale is not a function
var VueI18n = require('vue-i18n')
Vue.use(VueI18n)
Vue.config.lang = 'sv'
var locales = require('./lang/locales')
Object.keys(locales).forEach(function (lang) {
Vue.locale(lang, locales[lang])
})
And in my locales file I have like I had in 2.*:
module.exports = {
en: {
message: 'Hi',
},
sv: {
message: 'Hej',
}
}
vue: 2.0.0.rc3
vue-i18n: 4.3
vue-loader: 9.4.0
I try to update a project to vue 2.0.0 rc3
when I run webpack it makes the following error on every $t
:
ERROR in ./~/vue-loader/lib/template-compiler.js?id=data-v-1!./~/vue-loader/lib/selector.js?type=template&index=0!./src/templates/project/index.vue
template syntax error - invalid expression: {{{ $t("expression") }}}
vue 2.0.0.rc3
vue-i18n 4.3.1
vue-loader 9.4.0
vue-router 2.0.0-rc.3
I updated a project to vue 2, and now most of the translated strings don't display when the component loads for the first time. It makes an error
[vue-i18n] Cannot translate the value of keypath " ". Use the value of keypath as default.
When the component is re-used, the translated string appears.
Please, make it useful like angular-translate. I mean, it's really good to use it by directive and filter
For example,
<span v-translate="error.{{authError}}"></span>
Renders into
<span>Unexpected username!</span>
Hello. Please, look at example code:
var locale = {
en1:{
msg1:"Test1",
msg2:"Test2"
},
en2:{
msg1:"Test1",
}
}
Now, If I try to use $t('msg1') when lang is set to "en2" I'll see on screen "Test1". But if I try to use $t('msg2') I'll see "msg2". How can I set default lang, or what should I do, If I want to return default lang value, when the value is absent in current lang?
can't get to work vue-i18n plugin together with vue-router. Is there any issues or special config?
Hi,
Could someone, please, clarify for me the way Vue plugins should be connected to the framework.
1.
If I use vueify
(and I use it), I can use vue-i18n
in the next way:
// ready translated locales
var locales = {
'en-US': {
message: {
hello: 'the world'
}
}
}
// set plugins
// vue-i18n
Vue.use(require('vue-i18n'), {
lang: 'en-US',
locales: locales
});
// vue-router
Vue.use(require('vue-router'));
// vue-resource
Vue.use(require('vue-resource'));
// -- end of the plugins setup
Then, after my project will be "vueified", my target app.js would have vue-i18n
library's code inside.
It has no sense anymore, to connect it in index.html
directly, like:
<script src="/app/vendor/bower_modules/vue-i18n/dist/vue-i18n.js"></script>
2.
But what if I want to connect this plugin from index.html, not using vueify
.
What should I do then ? What should I write to the
Vue.use(***, {
lang: 'en-US',
locales: locales
});
under which variable, the plugin is exposed if it's connected via front-end? Should I ever use it this way?
I found vue-i18n/example/bower/index.html
, but it is missing the index.js file.
Regards,
Hi
I have a question or a feature request. Why isn't a dash (-
) a part of "indent" instead of "else" in path parsing?
Example:
{
a: {
b: 1,
"b-c": 2 // <--
}
}
I am migrating a SPA app to Vue and there internationalization keys use dashes.
I could make a PR for that if there is no reason why dash wouldn't be a part of a key name.
Hi,
I'm trying to do simple alert( $t('error') )
in my JavaScript file but $t is undefined.
I've also tried Vue.$t
but it is also undefined.
Is there any way to use the $t function outside a template ?
Thank you,
clem.
The unit tests use assert
when they should be using assert.equal
in some cases.
https://github.com/power-assert-js/power-assert#api
assert
just checks if the expression is not false.
I just want to use the plugin the standard way, like this :
<div id="test-i18n" class="message">
<p>{{ $t("message.hello") }}</p>
</div>
<script type="text/javascript " src="lib/vue.js "></script>
<script type="text/javascript " src="lib/vue-i18n.js"></script>
var locales = {
en: {
message: {
hello: 'the world'
}
},
ja: {
message: {
hello: 'ザ・ワールド'
}
}
};
// set plugin ???
Vue.use(i18n, {
lang: 'ja',
locales: locales
});
// create instance
new Vue({
el: '#test-i18n'
});
Thank you.
In the example docs, it uses fetch
, but I guess since most apps will use the vue-resource
package they can just use $http
. The fetch
call seems to add an additional 8Kb (minified) to my app file (I guess for polyfill's).
this.$http.get('/i18n/en-US.json', function (json) {
Vue.locale('en-US', json);
Vue.config.lang = 'en-US';
});
Might be useful to update the docs if there is no particular reason for using fetch
.
Great little plugin btw :-)
It seems some change in vue 1.0.9 made this plugin stop working.
If i pin my vue version to 1.0.8 everything works fine.
This will print out <br />
instead of a linebreak:
module.exports = {
en: {
index: {
headline: 'Testing html <br /> with i18n'
}
}
}
I'm using vue-router, so when I want to make a link, I use v-link. Unfortunately, that means it's impossible for me to make a link in a translation, because the text isn't being passed through the parser.
en-GB.js:
export default {
link: '<p>Click this <a v-link="{ path: \'/some-page\' }">link</a></p>',
};
Page.vue
:
<template>
<div>{{{ $t('link') }}}</div>
</template>
Expected output:
<p>Click this <a href="#!/some-page">link</a></p>
Actual output:
<p>Click this <a v-link="{ path: \'/some-page\' }">link</a></p>
In the named formatting, if I include an underscore in the named variable, the replacement failed. Is this an expected behavior?
(vue-i18n, v4.0.0)
For example:
var locales = {
en: {
message: {
hello: '{test_msg} world'
}
}
}
Template the following:
<p>{{ $t('message.hello', { test_msg: "hello" }) }}</p>
Output:
<p>{test_msg} world</p>
Expecting:
<p>hello world</p>
Does this plugin allow you to define a locale on a per component basis, or does it only work with one big global locale definition?
I ask because there's an alternative plugin that does support this, but it lacks in some other areas.
It would be helpful if we could use components as named arguments.
Suppose I have this message source:
{post: {posted_by: 'Posted by {author}'}}
And I want to display a tag with bindings or any kind of component in the place of {author}
:
Posted by <a class="foo" v-link="{name: 'author', params: {id: post.author.id}}">Foo</a>
Currently, there is no way to do something like this:
{{{ $t('post.posted_by', {author: myComponent}) }}}
When i want to write t function in a template i get this warning. It caused by the "continue" word in a string. Is it normal? :)
Example:
In the template file: {{ $t('continue-with-new-account') }}
Then the console says:
[Vue warn]: Avoid using reserved keywords in expression: 'continue-with-new-account'
[email protected], [email protected], [email protected]
Here's my code:
import Vue from 'vue';
import VueI18n from 'vue-i18n';
import en from 'locales/en';
import pl from 'locales/pl';
Vue.use(VueI18n);
Vue.locale('en', en);
Vue.locale('pl', pl);
Vue.config.lang = 'en';
export function langWatcher(store) {
store.on('mutation', (mutation, state) => {
if (mutation.type === 'CHANGE_LANG') {
Vue.config.lang = state.lang;
}
});
}
store.js
import Vue from 'vue';
import Vuex from 'vuex';
import { langWatcher } from '../i18n_old';
import {
CHANGE_LANG,
} from './mutation-types';
Vue.use(Vuex);
const initialState = {
lang: 'en',
langs: ['en', 'pl'],
};
const mutations = {
[CHANGE_LANG](state, lang) {
if (state.langs.indexOf(lang) > -1) {
state.lang = lang;
}
},
};
export default new Vuex.Store({
strict: process.env.NODE_ENV !== 'production',
state: initialState,
mutations,
plugins: [langWatcher],
});
and whenever i change language in vuex store I am getting an error in the console [vuex] Do not mutate vuex store state outside mutation handlers
. Can i somehow get rid of this error?
// EDIT: Ok apparently this error shows because i have enabled strict option in vuex store. You can close this issue now :))
I had to build this to track the missing translations, which is quite hacky. I would prefer a simple event listener.
var _warn = console.warn;
console.warn = function()
{
// track the missing translation
if (arguments[0].indexOf("i18n") !== -1)
{
var missingPhrase = arguments[0].replace('[vue-i18n] Cannot translate the value of keypath "', "");
missingPhrase = missingPhrase.replace('". Use the value of keypath as default', "");
WebService._call('translation/add-phrase', {phrase: missingPhrase});
return;
}
return _warn.apply(console, arguments);
};
Hey, is there any possibility to use the $t() function inside a javscript file? Like I have a method in my vue script that returns a string and I want it to be internationalized. :)
If key contains any special character (caret for example) the $t function generates an error:
vue.common.js:987[Vue warn]: Invalid expression. Generated function body: scope.foo-bar
Is it possible to i18n to access to the key like scope["foo-bar"] instead of scope.foo-bar? The translations keys are very limited because of that.
Thank you
Hi,
I would suggest to add a linking function between the translations, like angular-translate with the following syntax:
{
"SOME_NAMESPACE": {
"OK_TEXT": "OK"
},
"ANOTHER_NAMESPACE": {
"OK_TEXT": "@:SOME_NAMESPACE.OK_TEXT"
}
}
Thanks!
Why isn't data-placeholder="{{ $t('path.to.key') }} being translated when all the other "translations" are working, is it because its a data attribute? Shouldn't those work as well?
Hello,
is there a way to set a fallback language?
for example:
en.json
{
"message": {
"hello": "Hi"
}
}
spanish.json
{
"message": {
}
}
Vue.config.lang = 'spanish'
Vue.config.fallbackLang = 'en'
$t('message.hello')
// would return `Hi`
Is there a way to do this ?
Hi!
I'd like to re-visit the following issue that was reported earlier: #38
First off, we love the plugin and it appears to be the perfect solution for our multilingual app, but we're into a similar issue as linked above. The above issue was closed simply by the reporter changing their Vuex module setting of:
strict: true
to strict: false
To me this is not a "solution", but rather a kind of hack-fix. Would like to get to the bottom of the issue? While strict: true
should not be configured for production, we do use this mode in dev to ensure we're building correctly and if we're receiving the above error message there is an underlying issue.
Is there a simple way to dynamically change the locale without setting it affecting the state? Can you change the locale at the router and/or component level at all ? Is there some kind of deep watchers conflict between vue-i18n and vuex which is causing this? all kinds of questions :)
We are running into the same issue above, but are changing the language dynamically using vue-router
like so:
router.beforeEach((transition) => {
// determine language
// hyHeader.lang configured property defining what language to use
let hyHeader = document.querySelector('hy-header')
if (hyHeader !== null) {
Vue.config.lang = hyHeader.lang
}
console.log(`Language: ${Vue.config.lang}`)
window.scrollTo(0, 0)
transition.next()
})
Everything works fine in English locale (default), but as soon as we switch to French (fr) and after a transition the console errors state (Chrome):
vue.common.js?e881:3337 Uncaught Error: [vuex] Do not mutate vuex store state outside mutation handlers.Watcher.deep @ vuex.js?90cb:624Watcher.run @ vue.common.js?e881:3340Watcher.update @ vue.common.js?e881:3292update @ vue-i18n.common.js?2c49:134(anonymous function) @ vue-i18n.common.js?2c49:150Watcher.run @ vue.common.js?e881:3332runBatcherQueue @ vue.common.js?e881:3071flushBatcherQueue @ vue.common.js?e881:3042nextTickHandler @ vue.common.js?e881:445
vue.common.js?e881:3301 Uncaught Error: [vue] async stack trace
It doesn't really make sense to me because we are not using anything at all related to Vuex or state to configure our language?
Using:
VueJS 1.0.26
Vuex 1.0.0 RC2
Vue-Router 0.7.11
Vue-i18n 4.4.1
All versions of vue-i18n
We are cdnjs team. We want to host vue-i18n.
I found that vue-i18n.js
in dist
folder has been minified but vue-i18n.common.js
does not.
The auto-updater in cdnjs doesn't support partial minification, so in this case, we should manually minify vue-i18n.common.js
file.
I'll respectfully suggest you consider to provide vue-i18n.common.min.js
in dist folder so that auto-updater in cdnjs can work well. Thanks.
Hi,
Does this plugin support dynamic data interpolation for locales as in projects such as Polyglot?
Something like:
Locale object:
var locales = {
en: {
message: {
hello: 'total products %{num}'
}
}
};
Template:
<div id="message">
{{$t('message.hello', 10)}}
</div>
Rendered HTML:
<div id="message">
total products 10
</div>
Thanks in advance!
First and foremost, referencing an object literals
list locally works as expected, Such as this:
var locales = {
en: {
menu: {
about: "about",
news: "news",
contact: "contact"
}
},
fr: {
menu: {
about: "à propos",
news: "actualités",
contact: "contacter"
}
}
}
Vue.use(VueI18n, {
lang: 'fr',
locales: locales
});
However, I have been struggling to reference a json file (instead of a local object literals
list).
I attempted doing a XMLHttpRequest
directly:
function loadJSON(callback) {
var xobj = new XMLHttpRequest();
xobj.overrideMimeType("application/json");
xobj.open('GET', '../resources/i18n/locales.json', true);
xobj.onreadystatechange = function() {
if (xobj.readyState == 4 && xobj.status == "200") {
callback(xobj.responseText);
}
};
xobj.send(null);
}
var locales;
loadJSON(function(languageJSON) {
locales = JSON.parse(languageJSON);
Vue.use(VueI18n, {
lang: 'fr',
locales: locales
});
Have also tried doing an $.ajax
request (as well as the equivalent with $.getJSON
), like this:
$.ajax({
url: "../resources/i18n/locales.json",
dataType: "json",
type: "GET",
success: function (data) {
Vue.use(VueI18n, {
lang: 'fr',
locales: data
});
console.log(data);
}
});
My locales.json
is as follows:
[{
"en": {
"menu": {
"about": "about",
"news": "news",
"contact": "contact"
}
},
"fr": {
"menu": {
"about": "à propos",
"news": "actualités",
"contact": "contacter"
}
}
}]
Both the above approaches output the following:
Array[1]
0: Object
en: Object
menu: Object
about: "about"
contact: "contact"
news: "news"
fr: Object
menu: Object
about: "à propos"
contact: "contacter"
news: "actualités"
But other than that, I get several of these warnings (the expression is different in each of them): [Vue warn]: Error when evaluating expression $t("news.message2")
.
Regardless of the fact that I am most certainly doing something wrong (any hint appreciatted!), it would be much nicer if we could reference a (json) file path directly in the locales
option.
Any chance that one such feature could be added to this plugin in the near future?
Thanks in advance!
Reference:
https://tc39.github.io/ecma402/
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.