GithubHelp home page GithubHelp logo

panter / vue-i18next Goto Github PK

View Code? Open in Web Editor NEW
177.0 15.0 47.0 3.21 MB

Internationalization for vue using the i18next i18n ecosystem.

Home Page: https://panter.github.io/vue-i18next/

JavaScript 98.30% TypeScript 1.70%
vue i18n i18next javascript plugin typescript

vue-i18next's Introduction

DEPRECATED, please use https://github.com/i18next/i18next-vue ! Thanks for your support!

vue-i18next

Build Status Coverage Status semantic-release

Internationalization for vue using the i18next i18n ecosystem. https://panter.github.io/vue-i18next/

Introduction

18next goes beyond just providing the standard i18n features such as (plurals, context, interpolation, format). It provides you with a complete solution to localize your product from web to mobile and desktop.

vue-i18next is the vue support for i18next and provides:

  • Component based localization
  • Component interpolation
  • Lazy load namespaces
  • Namespaced translation for components

Requirements

  • vue >= 2.0.0
  • i18next >= 6.0.1

Documentation

See here

Init

import Vue from 'vue';
import i18next from 'i18next';
import VueI18Next from '@panter/vue-i18next';

Vue.use(VueI18Next);

i18next.init({
  lng: 'de',
  resources: {
    ...
  }
});

const i18n = new VueI18Next(i18next);
new Vue({
  ...
  i18n: i18n,
});

Changelog

Detailed changes for each release are documented in the releases.

Issues

Please make sure to read the Issue Reporting Checklist before opening an issue. Issues not conforming to the guidelines may be closed immediately.

Contribution

Please make sure to read the Contributing Guide before making a pull request.

License

MIT

vue-i18next's People

Contributors

claudiocro avatar henriquebremenkanp avatar joelpintoribeiro avatar macrozone avatar menthol avatar mtorromeo avatar pioniro avatar saraedum avatar smitt04 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

vue-i18next's Issues

Reload translations without page refresh

So im trying to hot reload translations. The changes are detected and i can do a console.log with the correct new translations, but the ui itself is not updated weird enough.

import Vue from "vue";
//import VueI18n from "vue-i18n";
import i18next from "i18next";
import LanguageDetector from "i18next-browser-languagedetector";

import VueI18Next from "@panter/vue-i18next";

import messages from "src/i18n";

//import { applyI18NextHMR } from "i18next-hmr";

Vue.use(VueI18Next);

import moment from "moment";

i18next.use(LanguageDetector).init({
  resources: messages,
  fallbackLng: "en-US",
  ns: ["translation", "md", "wiki"],
  defaultNS: "translation"
});

const i18n = new VueI18Next(i18next);

moment.locale(i18next.language);

if (module.hot) {
  module.hot.accept("src/i18n", () => {
    // this method will be invoked each time webpack sees a change in `src/i18n` import
    const newResources = require("src/i18n");
    Object.keys(newResources).forEach(lang => {
      const langObj = newResources[lang];

      Object.keys(langObj).forEach(namespace => {
        const nsResource = langObj[namespace];
        i18next.addResourceBundle(lang, namespace, nsResource);
      });
    });
  });
}

export default ({ app }) => {
  app.i18n = i18n;
};
export { i18n };

String Prop defaults being translatable

Example component prop:

title: {
      type: String,
      default: 'Create New',
},

It would be nice to replace the default string with $t{'create'} or this.$t{'create'} (currently results in undefined/error). Is there a way to achieve this?

Site Notice About Documentation Version (Wrong Version)

Hi
At the first tnx for implementing this useful package 👍

A little thing I did found in site home page that mentioned:

This documentation is for vue-i18next v0.0.12 or later.

I guess it means 0.12.0 instead of 0.0.12 :)

Memory leak in vue-i18next

Hey!

Have spent today tracking down a memory leak in our app, and figured out it's somewhere inside vue-i18next.

On projects with a lot of translations, it's a pretty significant leak. It also seems to keep the entire Vue instance alive.

After creating 1000 vue instances and throwing them away, this is what happens:

image

(look for everything with "1000" written in "New")

In theory, they should have been cleaned up by the garbage collector, but something is keeping them alive.

Here's a repository you can replicate the problem in: https://github.com/callumacrae/vue-i18next-leak

It's definitely vue-i18next, not i18next.

peerDependencies

Hi,
I just installed latest version of vue-i18next, but it seems that you got some version mismatches?
I can see that @panter/vue-i18next/typings/index.d.ts and i18next have different names for some functions. In package.json I noticed:

  "peerDependencies": {
    "i18next": ">= 6.0.1",
    "vue": ">=2.0.0"
  },

Shouldn't you use ^ operator to target minor versions instead of >= which I never use, but I assume that targets any latest major versions :D

Namespace question

Is there a way to pass namespace with the translation?? For example:
$t('my-name-space:key')

If not, is there a way to load name space based on a variable?

Install the plugin without the new Vue

I have a Vue app.
And I have build a Vue plugin which contains all my UI component.
I would like that my UI plugin would also contain the i18n functionality.
Installing it it should add all my filters/component/directives and the i18n.
This is the code I would like to write:

let VueUi = Vue => {

  Vue.use(VueI18Next);

  i18next.init({
    lng: 'de',
    resources: {
      ...
    }
  });

  Object.values(Components).forEach(Component => {
    Vue.use(Component);
  });

  Object.values(Directives).forEach(Directive => {
    Vue.use(Directive);
  });

  Object.values(Filters).forEach(Filter => {
    Vue.use(Filter);
  });
};

The problem is that I get an error. I suppose because I miss this part:

new Vue({
  ...
  i18n: i18n,
});

Do I have a way to not write this code?

TypeScript Support

Would you consider adding TypeScript support to your project? This would make it even more useful. :)

v-waitForT not working properly

I'm using vue-i18next 0.15.0, i18next 12.0.0, i18next-xhr-backend 1.4.2 (to load data from backend).
I'm using vue Filter for translations
{{ "common:hello" | t }}
My translation resource files are loaded after component is loaded. So translation does not take place correctly.
To avoid this I added v-waitForT with root element of current component i.e. component in which I placed translation. This works fine.
<template> <nav v-waitForT>...
This component is contained within a parent component. If I remove v-waitForT from root element of current component and put it with the parent component, then translation is not working properly.
<app-header v-waitForT></app-header>
Is it possible that I put v-waitForT at very root component, so that all the components gets loaded only when translation resource files are loaded properly?

v-t directive not works

Hi

I use vue-i18next with i18next-xhr-backend.
I used such locale files.

en/translation.json

{
  "navbar": {
    "mapEdit": "Edit Map"
  }
}

ja/translation.json

{
  "navbar": {
    "mapEdit": "地図編集"
  }
}

And if I use this in template:

<a href="#">{{$t('navbar.mapEdit')}}</a>

works fine.

But

<a href="#" v-t="{path:'navbar.mapEdit'}"></a>

Don't work (The result is, just showing "navbar.mapEdit").

How to solve this?

UI Flicker when loading a page, when variable-name text is being replaced with localized text

Hi,

When a page is loaded on initial load the text shown is the variable name of the label, and after ~0,5s it is replaced with the localized version. Which causes a flicker-effect in the UI.

There was a ticket in i18next (i18next/i18next#885) regarding this, where answer was to hide the text until resources are loaded, is there any way to configure this in vue-i18next? (similar to "wait" in react-i18next)

Also is there any way to reduce the amount of time before the text is loaded?

Add filter for $t

Adding a filter like:

Vue.filter('t', (value) => {
  if (!value) return ''
  return i18n.t(value)
})

greatly improves readability and de-clutters the code (given i18n is your i18n instance). Maybe should think about adding this as a standard functionality.
A practical example would be:

{{ $t('some_text') }}
{{ 'some text' | t }}

Translation issue in validation messages

Hi there,
First of all thank you for this library. When I tried to translate my error messages, it only shows the keys. Check the code below.

export default {
        name: "login",

        data () {
            return {
                passwordShow: false,
                loading: false,
                credentials: {
                    username: '',
                    password: ''
                },
                rules: {
                    username: [{
                        required: true,
                        message: this.$i18n.i18next.t('form.validation.required', {name: this.$i18n.i18next.t('form.label.email')}),
                        trigger: 'blur'
                    }],
                    password: [{
                        required: true,
                        message: this.$i18n.i18next.t('form.validation.required', {name: this.$i18n.i18next.t('form.label.password')}),
                        trigger: 'blur'
                    }],
                }
            }
        },
    }

It would be really appreciated if you guys can help me on this.

How to configure backend.loadPath with vue-cli 3.x?

Hello!
I use i18next with vue-cli 2.x with this config:

import Vue from 'vue'
import i18next from 'i18next'
import VueI18Next from '@panter/vue-i18next'
import XHR from 'i18next-xhr-backend'

Vue.use(VueI18Next);

i18next
  .use(XHR)
  .init({
    lng: 'ru',
    preload: ['ru'],
    fallbackLng: 'en',
    debug: true,
    backend: {
      loadPath: '/static/i18n/{{ns}}.{{lng}}.json',
      addPath: '/static/i18n/{{ns}}-{{lng}}',
    },

    ns: [
      'common',
    ],
    defaultNS: ['common']
  });

export default new VueI18Next(i18next);

But with vue-cli 3.x this config not working:

i18next::backendConnector: loading namespace common for language ru failed failed parsing /static/i18n/common.ru.json to json
i18next::backendConnector: loading namespace common for language en failed failed parsing /public/i18n/common.en.json to json

How to configure load path to load translations with vue-cli 3.x?

`v-t` and HTML in Translation Strings

In my apps I have several cases where I'd like to use v-t, but my translations often include HTML content. Since v-t uses el.textContent (https://github.com/panter/vue-i18next/blob/master/src/directive.js#L68), I have to resort to other workarounds like v-html="$t()", which are more verbose and trigger ESLint warnings (b/c ESLint can't know my translations are safe).

Would you be open to a PR that adds an option for v-t to use el.innerHTML instead? Or possibly prefer another approach? I'm willing to put in the work!

Thanks for your time :)

Translation arguments to i18next component to translate the "path" prop

I'm trying to implement a paging footer
image
that needs to be localized to display any text, inline with the select component. Naturally, It is a single key in the culture json:

"footer": "Candidates {{pagination}} of {{count}}"

and is used by an i18n component:

<i18next tag="span" path="my.key.prefix.footer">
        <... place="pagination" ... />
        <... place="count" ... />
</i18next>

Although this properly displays, it does not allow me to use count to pluralize, because i18n isn't actually seeing the count.

One solution is for i18next component to receive some sort of translation arguments prop.

I suppose another could be for the component to take exactly 1 of a format or path prop. Allowing me to translate my path in my parent, then passing the result into format would also solve the completely unrelated issue wherein I'm currently having to rewrite my parent component's i18nOptions component option's keyPrefix. Like:

<i18next tag="span" :format="$t('footer', { count: ... })">
        <... place="pagination" ... />
        <... place="count-to-display" ... />
</i18next>

Is something like this possible?

Use i18n component/tag

With normal i18n, you can do something like this:

  <i18n path="term" tag="label" for="tos">
    <a :href="url" target="_blank">{{ $t('tos') }}</a>
  </i18n>

This doesn't work in i18next. It throws an error, that i18n is not a known tag. Is there a way to enable that functionality for i18next as well?

Component interpolation fails in case of miltiple placeholders

Hi there!

Thanks for this lib, it helps a lot!
Yesterday I discovered the failure in component interpolation. The code below throws an exception

TypeError: Cannot read property 'attrs' of undefined"

in the line

if (!child && e.data.attrs && e.data.attrs.place && e.data.attrs.place === place) {

<i18next path="frontend.acceptance" tag="span">
  <a :href="tosUrl" target="_blank" place="tos">
    {{ $t("frontend.tos") }}
  </a>

  <a :href="privacyUrl" target="_blank" place="privacy">
    {{ $t("frontend.privacy") }}
  </a>
</i18next>

The frontend.acceptance is: I agree with {{tos}} and {{privacy}}.
The single placeholder is processed normally without errors.
Using latest versions of vue / i18next / vue-i18next.

Am I doing something wrong or this is an expected behaviour?

Support Arrays[]

Is there any possibilities to support arrays for example i need to use something like that

 headers: [
   {value: 'due', label: 'Fälligkeit'},
   {value: 'name', label: 'Name'},
 ]

Then i can simply loop through it which is default case with Vue i18n

<div v-for="header in $t('headers')">
   <div> {{ header.value }} </div>
    <div> {{ header.name }} </div>
</div>

Thank you

LG
Adel

key fallback

I'm tryign to do key-fallback, as described here https://www.i18next.com/principles/fallback#key-fallback, using your library, but i just get an empty result back rather than the key when a translation value is missing.
My config is as follows:

Vue.i18nOptions = {
   debug: true,
    lng: window.language,
    preload: [ window.language ],
    load: 'languageOnly',
    fallbackLng: false,    // the key is the fallback
    fallbackNS: false,		// not  using namespaces
    // allow keys to be phrases having `:`, `.`
    nsSeparator: false,
    keySeparator: false,
    backend: {
        loadPath: '/translations/{{lng}}.json'
    }
};

i18next
    .use(XHR)
    .init(Vue.i18nOptions);

This works fine as long as there's a value for every key. For ones without, I want to fallback to the key but I just get nothing.
Is key-fallback supported by your library and if so what am I doing wrong? thanks.

Lazy loading possible?

Is it possible to lazy load the translations? I'd like to be able to only load the translation for a particular language when it's required.

problem with mocking i18next module

Hi,

I want to setup test environment for existing Vue project with jest and vue-test-utils.

However I have a problem with mocking i18next module.

jest.mock('i18next', () => ({
  use: () => ({
    init: () => ({
      t: k => k,
      on: () => {}
    })
  })
}));

this mock throws this error:


  TypeError: this.i18next.on is not a function

      38 |      .init(i18nextOptions);
      39 |
    > 40 | export default new VueI18Next(i18next);
      41 |

      at new n (node_modules/@panter/vue-i18next/dist/vue-i18next.js:1:3444)
      at Object.<anonymous> (src/app/locale/i18n.js:40:1)
      at Object.<anonymous> (src/app/store/modules/account/mutations.js:6:13)
      at Object.<anonymous> (src/app/store/modules/account/index.js:7:18)
      at Object.<anonymous> (src/app/store/index.js:17:16)
      at src/app/pages/home/index/index.vue:24:14
      at Object.<anonymous> (src/app/pages/home/index/index.vue:230:3)
      at Object.<anonymous> (test/unit/home.spec.js:17:187)

Without mock whatsoever, it just says i18next is undefined.

https://stackoverflow.com/questions/48789110/how-to-mock-i18next-module-in-jest
i18next/i18next#1017

Any help is appreciated.

Async i18next backend leads to missing keys request

Hi there!

Thanks for your lib, it's very well done.
However, I'm facing with an issue with VueI18next initialization before translation is fetched by i18next async backend. This leads to triggering all used keys as missing in i18next-xnr-backend (coz they are not loaded yet). I've used i18next.init with callback as a temporary fix but I think that this case needs to be covered by your library so VueI18next init will be executed only after i18next successful init.

This is an example of my wrapper for i18n (issue is covered here):

import Vue from 'vue';
import i18next from 'i18next';
import XhrBackend from 'i18next-xhr-backend';
import LangDetector from 'i18next-browser-languagedetector';
import VueI18Next from "@panter/vue-i18next";

export default {
  init(afterInitCallback) {
    i18next
      .use(XhrBackend)
      .use(LangDetector)
      .init({ ...options... }, (err) => {
        if (err) {
          return console.log('Something went wrong with i18n loading', err);
        }

        Vue.use(VueI18Next);

        const i18n = new VueI18Next(i18next);

        afterInitCallback(Vue, i18n);
      });
  }
};

and example of using this wrapper in the client code:

vueI18n.init((Vue, i18n) => {
  new Vue({
    el: '#container',
    store: Store,
    i18n,
    render: h => h(Form)
  });
});

Make component namespace loading optional

Right now, each time you mount a component, it tries to fetch the namespace for that component. This is fine when your resources are already loaded, but if you use a remote backend to provide these resources such as GraphQL API / XHR backend, it makes a large amount of network calls.

Please provide an option to disable that behavior. I already defined the namespaces to load while initializing i18next. The automatic component namespace loading is useless in this case and only generate errors.

Thanks!

Vue CLI 3 plugin

Hey,

Would you consider writing a plugin for the new Vue CLI? The generator could make example files for registering vue-i18next with Vue, and loading localized strings from .json files for example.

Is it possible to include components in translation string?

Hey!

Objective

I'd like to let my translators include vue components in their strings, example:

Check out new items in {{url:shop|our shop}}

Such translation string would later be transformed using i18next post processor into vue template:

Check out new items in <router-link :to="{ name: 'shop' }">our shop</router-link>

And eventually rendered. This would be similar to i18next component, but allow more flexibility.

Why?

In this particular example it allows to keep link display text in the same translation string as the whole sentence, making it significantly easier to maintain, especially for languages in which a word takes different form depending on context.

Take the following sentences in English and Polish as an example, the word marked with astrix is meant to be transformed into display text of router-link:

// English
Visit our *store*
Check out new items in the *store*

// Polish
Odwiedź nasz *sklep*
Zobacz nowe przedmioty w *sklepie*

While in English the word is the same, in other languages we may need to adjust it's grammatical case.

Existing solution

The problem could be solved by i18next component and unique translation string for each display name (I don't think using context is sufficient, as it's language-specific), but this approach adds a lot of unnecessary complexity.

i18next allows for custom post processors, we can use it to create HTML string (eg. <a href="#"></a>) and use it in v-html. Such solution works as a workaround for simple components.

We can probably post process the i18n string into Vue template, then use Vue.compile to get the render function, but that comes with a cost of including full Vue build I'd like to avoid.

Abstracting the problem

General solution would be to utilize vue's dynamic <component>, example:

Codepen snippet: {vue:codepen-snippet|user=XXX,id=XXXXX}
// Renders to
Codepen snippet <component is="codepen-snippet" user="XXX" id="XXXXX"></component>

Actual question

Do you think such feature is possible to be implemented within the library?

If not, what's your opinion on extending i18next component capabilities to allow props in translation strings, eg. {{0:prop-name=1}}?

Edit: Updated wikipedia link so it points to grammatical case, not declination.
Edit 2: Redacted

wait for initialization

Hello,

is there a way to wait for the module to finish initializing before moving forward with the loading of the main.js file?

Cannot redefine property: $i18n

With the latest version of vue-i18next i have the same problem that is discussed here : kazupon/vue-i18n#421

image

Is it possible to do the same fix for this plugin ? It's consist to check the property before we define it like this :

if (!Vue.prototype.hasOwnProperty('$i18n')) {
  Object.defineProperty(Vue.prototype, '$i18n', {
    get () { return this._i18n }
  })
}

Thank you guys !

keyPrefix should not be inherited by child components

When I set the keyPrefix option for a component and include a different component inside, the keyPrefix of that child component will also be set to the value I choose for the parent component. I think that should not be the case.

import Child from 'Child.js'
export default {
	components: { Child },
	i18nOptions: { keyPrefix: "view.home" } },
	template: `<section><h1>{{ $t("title") }}</h1><Child /></section`
}

Child could be used in multiple places and every time it will have a different prefix set.

I don’t think this is a good approach, because it makes the translations really hard to control.

If you really want to support it, I would suggest allowing a function for the keyPrefix option, which takes the parent prefix and returns the childs’ prefix.

In any case, please default to having no prefix, if the keyPrefix option is not given in a component.

Typescript issues

I'm trying to use 0.15.0 with the latest version of i18next (14.1.1) but I'm having some troubles. It seems like TranslationFunction was renamed to TFunction in one of the latest releases and this is causing problems.

i18next/i18next#1180

What version of i18next is properly supported by this lib? Thanks.

Vue 3 support

Vue 3 is in an RC state and will be released any time now.
Can we expect v3 support here any time soon?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.