Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to run gettext function in custom js module? #76

Open
pantuchy opened this issue Oct 4, 2018 · 15 comments
Open

How to run gettext function in custom js module? #76

pantuchy opened this issue Oct 4, 2018 · 15 comments

Comments

@pantuchy
Copy link

pantuchy commented Oct 4, 2018

Hello.
Please advise, how to run translation functions like (gettext, ngettext and etc. ) in custom js file? For example Vue-Gettext is installed and initiated in main.js file, everything is working fine, but if I want to use gettext functions in router.js file, functions are not working, I have tried:

Vue.$gettext('Some text')
this.$gettext('Some text')
Vue.prototype.$gettext('Some text')

Nothing works.
In Router file I am setting titles for each page, and I wish, that they will be available for translating.
Please help.
Thank you.

@p4t5h3
Copy link

p4t5h3 commented Oct 11, 2018

Have you tried router.app.$gettext('Some text')? The app property on the router instance is the Vue instance on which the global gettext methods are available.

@sandroden
Copy link

This is interesting but I have a similar need for vuex and for a pure js module (messages used by vuelidate-error-extractor). Do you have a solution for these situations?

@escapedcat
Copy link
Contributor

escapedcat commented Dec 16, 2018

We're doing this:
gettext.js:

import Vue from 'vue'

export const interpolate = Vue.prototype.$gettextInterpolate
export default Vue.prototype.$gettext

And in a js-file:

import gettext from '@helper/gettext'

export default {
  mainNav: {
    animals: {
      itemText: gettext('AnimalsText'),
      routeName: 'Animals',
    },
   ...

Does this help?

@sandroden
Copy link

I tried it, I created gettext.js and then I imported it in the store and I get the error:
cv.js?c148:113 Uncaught TypeError: Object(...) is not a function.

@escapedcat
Copy link
Contributor

Did you add the plugin to your Vue instance? The idea assumes that you integrated vue-gettext into your Vue-project already. If yes we need to check more detailed. Maybe you can create a test-repo and share it.

@sandroden
Copy link

Yes, I integrated vue-gettext with following conf:


Vue.use(GetTextPlugin, {
  translations: translations,
  availableLanguages: {
    en_GB: 'British English',
    it_IT: 'Italiano',
    pl: 'Polski',
    pt: 'Português',
    pt_BR: 'Português brasileiro',
  },
  defaultLanguage: navigator.language.replace('-', '_'),
  silent: false,
}

And is working perfectly. Honestly -due to my poor knowledge of js, my background is Python...- I'm, uncertain of what happens when you write Vue.use(...): any instance of Vue will get that plugin from Vue.prototype? that means that if it works I can get also $language in the same way? Could you even use Vue.prototype.$gettext directly?
Anyhow I'll come back later with a complete codesandbox example.

@sandroden
Copy link

sandroden commented Dec 18, 2018

I prepared this codesandbox that shows the error I'm getting.
In main.js I tried to change the import order so that plugin is loaded before App is read, but the error doesn't change.

Any hint is appreciated.

@kemar
Copy link
Contributor

kemar commented Jan 10, 2019

@sandroden as its name implies, this plugin is thightly coupled to a Vue.js application. All components of an app are sharing the same Vue instance (in your codesandbox it's the one in main.js).

When you're importing Vue in your gettext.js file, you're creating another instance of Vue that is not aware of the plugin without $gettext in its prototype. That's why your codesandbox shows an error.

As suggested by others, you can find some ways to share the Vue instance and somewhat use the plugin in custom js modules, but you will loose the reactivity that is provided by the component and the directive.

All use cases supported by the plugin are covered in the documentation.

@sandroden
Copy link

My codesandbox sample was in fact the attempt to implement @escapedcat 's suggestion. Reactivity may not be an issue in mutations and actions at least. I just realized that store has an instance of vue as store._vm, that can be used at least to translate messages from within an action. The case that is left unresolved to me is a message list used in a separate file. As an example I use vuelidate-error-extractor to display validation error messages.

@PetrovskYYY
Copy link

There is another easy working way to do this: you can push this.$gettext object into a vuex store as a state variable and then use it there.

@duduklein
Copy link

Any solution to this? how could we use gettext in a completely separate js file?

@pantuchy
Copy link
Author

pantuchy commented Jan 1, 2020

Any solution to this? how could we use gettext in a completely separate js file?

I recommend to use i18n for Vue projects. It also has Nuxt Js module

@duduklein
Copy link

Well, I'm actually switching from i18n. gettext is the standard way of handling translations in linux and has automatic extraction of string. I don't really understand why the vue community opted for a different approach.

Besides lacking the automatic extraction of string, i18n is more verbose, since we have to write message.key everywhere and it makes more difficult to non-programmers translators to translate the files. AFAIK, there is no software like poedit that allows a non technical person to translate the strings.

@brunobg
Copy link

brunobg commented Feb 3, 2020

This might be helpful to people here: #51 (comment)

@imrim12
Copy link

imrim12 commented Aug 15, 2023

There's another way of doing this by using a "lazy-string" technique
JavaScript will try to convert objects into string before rendering them to the UI (You can often see something like [Object object])
Taking advantage of that, we can make a custom object, and then override the toString() method with the gettext function, so it only runs when rendered

class LazyString {
  constructor(msgid, locale) {
    this.toString = translate.gettext.bind(translate, msgid, locale)
  }
}

const gettextLazy = (msgid, locale) => new LazyString(msgid, locale)

In any files, you can just use it

const YOUR_CONST = {
  HELLO: gettextLazy("Hello World!")
}

And that should work with your components

<template>
  <div>{{ YOUR_CONST.HELLO }}</div>
</template>

This should also work for SSR too, if you use Nuxt, please make sure the language is set properly before the page rendered, there're hooks that run after plugin initialization and before rendering, you should set your language in those hooks from your cookies, user's settings or whatever, good luck

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants