Git Product home page Git Product logo

vue3-gettext's Introduction


Translate Vue 3 applications with gettext.


Getting started | Demo | Documentation | 中文


Basic usage

In templates:

<span>
  {{ $gettext("I'm %{age} years old!", { age: 32 }) }}
</span>

In code:

const { $gettext } = useGettext();

console.log($gettext("Hello World!"));

Features

  • simple, ergonomic API
  • reactive translations in Vue templates and TypeScript/JavaScript code
  • CLI to automatically extract messages from code files
  • support for pluralization and message contexts

Contribute

Please make sure your code is properly formatted (the project contains a prettier config) and all the tests run successfully (npm run test) when opening a pull request.

Please specify clearly what you changed and why.

Credits

This plugin relies heavily on the work of the original vue-gettext.

License

MIT

vue3-gettext's People

Contributors

0xjacky avatar audunhov avatar cpontvieux-systra avatar fedorsherbakov avatar itechmeat avatar jeremyzahner avatar lesuisse avatar lzurbriggen avatar olof-nord avatar tabun-matadorov avatar tcitworld avatar win0err avatar youthlin 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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

vue3-gettext's Issues

Messages in native <template> tags do not get extracted

Versions:

  • vue 3.2.31
  • vue3-gettext 2.2.0-alpha.1
  • gettext-extractor 3.5.4

The messages are not extracted in this configuration

<template>
  <router-link>
    <template v-if="mode === 'list'">{{ $gettext('Map') }}</template>
    <template v-else>{{ $gettext('List') }}</template>
  </router-link>
</template>

But this one works

<template>
  <router-link>
    <span v-if="mode === 'list'">{{ $gettext('Map') }}</span>
    <span v-else>{{ $gettext('List') }}</span>
  </router-link>
</template>

Possibly a limitation with Gettext Extractor itself, didn't check yet.

Allow exporting to one JSON file per language

Using gettext-compile it was possible to export each language in their own JSON file, so that it can be dynamically loaded, something like:

@for lang in $(LOCALES); do \
        gettext-compile --output $(OUTPUT_DIR)/translations/$$lang.json $(OUTPUT_DIR)/locale/$$lang/app.po; \
done;

In next gettext_compile.ts doesn't support that. This could be handled with a split option under output in gettext.config.js.

Lazy load language files to minimize download size

It appears that, despite having specified splitJson: true in the config, ultimately all translations get minified into the same file for my app. It would be ideal to lazily load languages only upon their activation. Once you have multiple languages with nontrivial amounts of content, the file size really starts to add up, with no benefit to your average single-language user.

Issue extracting texts inside labels.

Hello! Apparently there is an issue extracting texts inside labels when they have the for attribute. i.e
This doesn't work:
<label for="company-website" class="tw-block tw-text-sm tw-font-medium tw-leading-6 tw-text-gray-900">{{ $gettext("bla bla") }}</label>
but this one does:
<label class="tw-block tw-text-sm tw-font-medium tw-leading-6 tw-text-gray-900">{{ $gettext("bla bla") }}</label>

UPDATE
Seems to happening only when label with for attribute is inside a v-for block.

Is there a known workaround? Thanks in advance!

gettext-extract not working on Windows

While running the gettext-extract on windows, getting the following error:

Error: Command failed: find ./src -name '.js' -o -name '.ts' -o -name '*.vue' 2> /dev/null
The system cannot find the path specified.

at ChildProcess.exithandler (child_process.js:308:12) at ChildProcess.emit (events.js:315:20) at maybeClose (internal/child_process.js:1048:16) at Process.ChildProcess._handle.onexit (internal/child_process.js:288:5) { killed: false, code: 1, signal: null, cmd: "find ./src -name '*.js' -o -name '*.ts' -o -name '*.vue' 2> /dev/null" }

Obviously the find command is failing on Windows.

Possible Fix:

In gettext-extract.ts import "os" module

const os = require("os");

Change line number 43 to:

var files = null;
if(os.type() === "Windows_NT"){
files = await execShellCommand(cd ${srcDir} & dir *.js *.ts *.vue /S /B 2> NUL);
}
else{
files = await execShellCommand(find ${srcDir} -name '*.js' -o -name '*.ts' -o -name '*.vue' 2> /dev/null);
}

LanguageVmMixin option

Hello,

I used for a long time vue-gettext for VUE2 ; I'm very glad to found your project.

But there is an option it can't provide :

...
 languageVmMixin: {
    computed: {
      currentKebabCase: function () {
        return this.current.toLowerCase().replace("_", "-");
      },
      currentLang: function () {
        return this.current.replace("_", "-");
      },
    },
    watch: {
      currentLang: function (n, o) {
        console.log("GetTextPlugin:: currentLang o > n ", o, n);
        // Then change html lang attr
        if (n) document.documentElement.setAttribute("lang", n);
      },
    },
  },

Regarding to VUE2 documentation :

languageVmMixin {Object} optional A mixin that will be passed to the main languageVminstance (exposed via $language) that can be used, for example, to add custom computed properties

Well this option was very useful in many cases ; can you help me on this ?

Best regards, Wilhem

Thank you

Hi, I just wanted to thank you for porting vue-gettext to Vue 3. I've integrated in a project of mine this morning and it seem to works exactly as expected. I didn't observe any regression compared to the original vue-gettext package used on a Vue 2 app.

So, kudos and thank you 🙏 🙏 🙏

(Feel free to close this of course ;)

Problems with extracting text from <script setup>

Hello !
First of all thanks for creating this tool :D

I'm currently having difficulties to extract translated text inside the script setup.

<script setup>
import { computed } from "vue";
import gettext from "../utils/gettext";
const { $gettext } = gettext;
const someText1 = $gettext(
  "hi this is just some text in a variable translated"
);
const someText2 = computed(() =>
  $gettext("This is a computed text translated")
);
</script>

<template>
  <div>
    <h1>
      {{ $gettext("Hello from Dashboard") }}
    </h1>
    <h2>{{ someText1 }}</h2>
    <h2>{{ someText2 }}</h2>
    <div>
    </div>
  </div>
</template>

The $gettext function works just fine in the template, but it's not extracting the strings from the script template.
I was wondering if i'm missing something or this feature is not yet implemented.

my gettext.js is just the createGettext instance that gets also imported in main.js and used in the app.

Thanks beforehand for any help !

Running vue-gettext-extract produces *.po, *.pot but no translations.json file?

Good day,

Not sure if I found a bug for the latest version or not. Like the title states I get the required po and pot files created but the translations.json file remains empty. Naturally running the vue-gettext-compile command fails with an error: no language headers found.

Here's my gettext.config.js file:

module.exports = {
    input: {
        path: './src',
        include: ['**/*.js', '**/*.vue'],
    },
    output: {
        locales: ['en', 'fr'],
        splitJson: true,
        path: './src/languages',
        potPath: './messages.pot',
        jsonPath: './',
        flat: false,
        linguas: true,
   },
}

Thanks in advance for any tips/help

Allow passing a read-only props as context

  • vue3-gettext version: 2.0.0-alpha.3
  • vue version: 3.2.27
<template>
  <div>
    <p v-translate="{ indexName }" >
      <strong>%{indexName}</strong>  something something something
    </p>
  </div>
</template>

<script lang="ts">
  import { defineComponent } from 'vue'

  export default defineComponent({
    props: {
      indexName: {
        type: String,
        required: true,
      },
    },
  })
</script>

Gives

[Vue warn]: Attempting to mutate prop "indexName". Props are readonly. 

The trace points to

const context = Object.assign(binding.instance, binding.value);

`$locale/app.po` hard-coded into locale compile script

Hey all! Thanks for your work in bringing this very useful tool to Vue 3.

I'm trying to use the JSON compiler tool to assist in building translations for my app, but I'm noticing that the paths for the individual locales are hard-coded in a few places.

In my case, my folder structure looks like:

translations
|  es_ES.UTF-8
|  |  LC_MESSAGES
|  |  |  default.po

I can override the folder name by just setting the locale name as es_ES.UTF-8/LC_MESSAGES (although that feels a little hacky), but the extractor hard-codes in the app.po path afterwards. That isn't the namespace I use for my translations, and renaming it would involve a lot of downstream difficulty.

Would it be possible to have the locales config optionally be a callback function returning the path for each locale's translation? Similar to the existing map call that's done on the library side, but checking if the config value is a function and then calling that instead to yield the locales to work with and their respective paths.

Cosmiconfig version upgrade

Sorry @lzurbriggen, @jshmrtn , the latest release is not enough to read ESM config module: cosmiconfig should be updated to version 9.0.0.

I see there is a pull request which drops cosmiconfig in favor of lilconfig. I cannot comment on it, but if the result is an ESM config module readable, then that’s ok.

I don’t know when this would be ready though. BTW, if you need help and/or testing, I’m available as I use your project a lot at work.

Render html with functions

Since directives are now depreciated in 2.0.0-beta, what's the method to perform interpolation with HTML using functions?

Should there be a render-html option passed to the functions?

scripts aren't working with $.gettext, only with the useGettext hook

Issue: after running vue-gettext-extract, the expected pot and po files are created, but they have not the translation strings when using $.gettext in templates. It works when using the useGettext hook tho.

This works:

<script setup lang="ts">
import { useGettext } from 'vue3-gettext';
...
const { $gettext } = useGettext();
...
</script>
<template>
  <span>{{ $gettext('Some text...') }}</span>
</template>

but this doesn't:

<template>
  <span>{{ $.gettext('Some text...') }}</span>
</template>

Details:

"vue": "3.2.33",
"vue3-gettext": "2.2.3"

App setup

import { createGettext } from 'vue3-gettext';
import translations from './i18n/translations.json';

const gettext = createGettext({
  availableLanguages: {
    en: 'English',
    es: 'Spanish',
  },
  defaultLanguage: 'en',
  translations: translations,
});

const app = createApp(App);
app.use(gettext);
app.mount('#app');

msginit "Command failed"

Extraction successful, src\language\messages.pot created.

152 messages extracted

322 total usages
6374 files (219 with messages)
1 message context (default)

Error: Command failed: msginit --no-translator --locale=en --input=src\language\messages.pot --output-file=src\language\en\app.po
'msginit' n�o � reconhecido como um comando interno
ou externo, um programa oper�vel ou um arquivo em lotes.

at ChildProcess.exithandler (node:child_process:387:12)
at ChildProcess.emit (node:events:527:28)
at maybeClose (node:internal/child_process:1090:16)
at Socket.<anonymous> (node:internal/child_process:449:11)
at Socket.emit (node:events:527:28)
at Pipe.<anonymous> (node:net:715:12) {

code: 1,
killed: false,
signal: null,
cmd: 'msginit --no-translator --locale=en --input=src\language\messages.pot --output-file=src\language\en\app.po'
}
node:fs:1858
handleErrorFromBinding(ctx);
^

Error: ENOENT: no such file or directory, chmod 'src\language\en\app.po'
at Object.chmodSync (node:fs:1858:3)
at C:\DEV__Vue\Mindu\node_modules\vue3-gettext\dist\bin\gettext_extract.js:324:40
at step (C:\DEV__Vue\Mindu\node_modules\tslib\tslib.js:193:27)
at Object.next (C:\DEV__Vue\Mindu\node_modules\tslib\tslib.js:174:57)
at fulfilled (C:\DEV__Vue\Mindu\node_modules\tslib\tslib.js:164:62)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
errno: -4058,
syscall: 'chmod',
code: 'ENOENT',
path: 'src\language\en\app.po'
}

Node.js v18.2.0

It's a example of an error, even I tried to change folders or clear caches/reinstall too this errors persist... the directory/folder has been created but appears a permission maybe about msginit?
I wrote this because someday, someone - maybe - will have the same issue
You guys saving our bacon. Thanks for this implementation - will be fantastic

Implement JetBrains `web-types.json` file for Vue template type hinting

I've been implementing vue3-gettext in my application, and I've noticed that the $gettext calls in templates themselves, while they resolve correctly within Vue, are being treated by the JetBrains IDE as unknown function calls, which causes them to appear as warnings, show up in inspection results, etc...

JetBrains has a standardized file type to define types in Vue component files (which is particularly useful for templates), and as long as such a file exists for it to reference, it'll be able to smartly identify the $gettext and other related function calls.

The schema for this file is here: https://raw.githubusercontent.com/JetBrains/web-types/master/schema/web-types.json

Another project, BootstrapVue, automatically generates this file (along with type-hinting for the VSCode Vetur extension) with this script: https://github.com/bootstrap-vue/bootstrap-vue/blob/dev/scripts/create-web-types.js

If there's interest in adding support for this, I'd be happy to look into possibly submitting a PR.

Option to merge .pot files

Is there any way to merge or specify several .pot files before extracting them to .po files?

This would be really handy when extracting from several sources, or when we need to add additional custom keys (for example to translate dynamic text coming from an external source) which just get removed from the .pot and .po files otherwise when running the extract command.

I believe the original xgettext program from GNU gettext utilities (https://www.gnu.org/software/gettext/manual/html_node/xgettext-Invocation.html) allows to specify several input files and concatenate them into one as suggested in the answers here: https://stackoverflow.com/questions/4052736/how-can-i-merge-2-pot-files-translation-files

Another option could be using the merge option and/or dgettext domains as suggested in this elixir implementation https://stackoverflow.com/questions/37411810/add-gettext-translation-keys-manually (which is basically what I was trying to do)

Is it possible to use _() as translation function name?

jshmrtn,

Great work!

I use _() as translation function with other languages previously, and prefer it.

So is it possible to use _() with vue3-gettext also? if it is , how to do it?

e.g.


{{ _('Console Login') }}

Thanks!

vue-gettext-extract: "Error: Command failed: find ..."

Hello! First of all, thanks for your work.

What is the problem?

Executing vue-gettext-extract command results in error:

Error: Command failed: find ./src/components -name '*.js' -o -name '*.vue' 2> /dev/null

But an empty locales directory is created in src directory.

Details in the screenshot:
image

How to reproduce the problem

In a clean project created via @vue/cli after installing @jshmrtn/vue3-gettext, in package.json add the line in the scripts section:

"gettext:extract": "vue-gettext-extract --src ./src/components --out ./src/locales --locales \"ru_RU,en_US\""

At the command line, run the command gettext:extract.

Environment

Windows 10
Vue 3.0.0
@vue/cli 4.5.10
@jshmrtn/vue3-gettext 1.0.1

Multiple messages in one HTML node are not extracted

Not sure if this is a vue3-gettext issue or a gettext-extractor issue, but it seems that for HTML nodes containing multiple messages, only the first message is extracted.
For example:

<span>
  {{ $gettext("Message 1") }}
  <br>
  {{ $gettext("Message 2") }}
</span>

When running npm run gettext:extract, the output .po file only contains "Message 1".

Translation seems fails with & symbol

In a vue3 project, this code fails translating :

<translate>Use 8 or more characters with a mix of letters, numbers & symbols.</translate>

Best !

Use vue-demi for vue 2 compatibility

I'm currently migrating a big project that uses vue-gettext from vue 2 to vue 3. If there would be an option for vue3-gettext to use vue-demi internally, it'd be much easier for me to migrate.

tslib.__spreadArray is not a function when running extraction.

Running on 2.0.0-alpha.3

vue-gettext-extract
Input directory: ./src
Output directory: ./src/locale
Output POT file: src/locale/messages.pot
Locales: bn,de,el,en_US,es,fr_FR,fy,gd,gl,id,it,ja,nl,oc,pl,pt_BR,ru,sq,sv,th

Searching: src/**/*.js
Searching: src/**/*.ts
Searching: src/**/*.vue
~project/node_modules/vue3-gettext/dist/bin/gettext_extract.js:274
                filesFlat = allFiles.reduce(function (prev, curr) { return tslib.__spreadArray(tslib.__spreadArray([], prev, true), curr, true); }, []);
                                                                                                     ^

TypeError: tslib.__spreadArray is not a function
    at ~project/node_modules/vue3-gettext/dist/bin/gettext_extract.js:274:102
    at Array.reduce (<anonymous>)
    at ~project/node_modules/vue3-gettext/dist/bin/gettext_extract.js:274:38
    at step (~project/node_modules/tslib/tslib.js:141:27)
    at Object.next (~project/node_modules/tslib/tslib.js:122:57)
    at fulfilled (~project/node_modules/tslib/tslib.js:112:62)

Seems related to microsoft/tslib#149

BUG: script translations with $gettext does not get extracted/detected

App.vue

<template>
      <h2>
        {{ $gettext("My message") }}
        {{ $gettext("My message 3") }}
      </h2>
      <h3>
        {{ data2 }}
      </h3>
      <h3>
        {{ data2ref }}
      </h3>
</template>

<script setup lang="ts">
import { useGettext } from "vue3-gettext";
import { ref } from "vue";
const language = useGettext();

const data2 = language.$gettext("My message2");
const data2ref = ref(language.$gettext("My message2ref"));
</script>

This is my code and when I run gettext:extract I only get My message and My message 3 everything else from script is ignored

msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"

#: src/App.vue:35
msgid "My message"
msgstr ""

#: src/App.vue:36
msgid "My message 3"
msgstr ""

Cannot extract messages from code

i'm using window 11, pnpm and my current vue3-gettext's version is 3.0.0-beta.6
I have tried many times, but it still can't be exact

image
image
image
My config
image

Thanks

inject() can only be used inside setup() or functional components.

Is there a way to use in composable file/method instead of a component?

If I try to do a composable file outside vue component:
const { $gettext } = useGettext(); in composable file/method

I've got an error:
inject() can only be used inside setup() or functional components.

Recent issue when extract or compile : Error [ERR_REQUIRE_ESM]: require() of ES Module


> vue-gettext-compile

/Users/wilhemarnoldy/Developpements/Berlioz/node_modules/cosmiconfig/dist/loaders.js:32
    throw error;
                                                          ^

Error [ERR_REQUIRE_ESM]: require() of ES Module /Users/wilhemarnoldy/Developpements/Berlioz/gettext.config.js from /Users/wilhemarnoldy/Developpements/Berlioz/node_modules/cosmiconfig/dist/loaders.js not supported.
gettext.config.js is treated as an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which declares all .js files in that package scope as ES modules.
Instead rename gettext.config.js to end in .cjs, change the requiring code to use dynamic import() which is available in all CommonJS modules, or change "type": "module" to "type": "commonjs" in /Users/wilhemarnoldy/Developpements/Berlioz/package.json to treat all .js files as CommonJS (using .mjs for all ES modules instead).

    at module.exports (/Users/wilhemarnoldy/Developpements/Berlioz/node_modules/import-fresh/index.js:32:59)
    at loadJs (/Users/wilhemarnoldy/Developpements/Berlioz/node_modules/cosmiconfig/dist/loaders.js:16:18)
    at ExplorerSync.loadFileContentSync (/Users/wilhemarnoldy/Developpements/Berlioz/node_modules/cosmiconfig/dist/ExplorerSync.js:84:26)
    at ExplorerSync.createCosmiconfigResultSync (/Users/wilhemarnoldy/Developpements/Berlioz/node_modules/cosmiconfig/dist/ExplorerSync.js:89:30)
    at ExplorerSync.loadSearchPlaceSync (/Users/wilhemarnoldy/Developpements/Berlioz/node_modules/cosmiconfig/dist/ExplorerSync.js:70:25)
    at ExplorerSync.searchDirectorySync (/Users/wilhemarnoldy/Developpements/Berlioz/node_modules/cosmiconfig/dist/ExplorerSync.js:55:32)
    at run (/Users/wilhemarnoldy/Developpements/Berlioz/node_modules/cosmiconfig/dist/ExplorerSync.js:35:27)
    at cacheWrapperSync (/Users/wilhemarnoldy/Developpements/Berlioz/node_modules/cosmiconfig/dist/cacheWrapper.js:28:18)
    at ExplorerSync.searchFromDirectorySync (/Users/wilhemarnoldy/Developpements/Berlioz/node_modules/cosmiconfig/dist/ExplorerSync.js:47:49)
    at ExplorerSync.searchSync (/Users/wilhemarnoldy/Developpements/Berlioz/node_modules/cosmiconfig/dist/ExplorerSync.js:27:25)
    at loadConfig (/Users/wilhemarnoldy/Developpements/Berlioz/node_modules/vue3-gettext/dist/bin/gettext_compile.js:105:30)
    at Object.<anonymous> (/Users/wilhemarnoldy/Developpements/Berlioz/node_modules/vue3-gettext/dist/bin/gettext_compile.js:144:14) {
  code: 'ERR_REQUIRE_ESM'
}


Package version is : 2.4.0

Thanks a lot

startLine can be undefined

When running vue-gettext-extract on the latest alpha version:

[...]/my_project/node_modules/vue3-gettext/dist/bin/gettext_extract.js:79
                lineNumberStart: (_a = element.sourceCodeLocation) === null || _a === void 0 ? void 0 : _a.attrs[attr.name].startLine,
                                                                                                                            ^

TypeError: Cannot read properties of undefined (reading 'startLine')
    at [...]/my_project/node_modules/vue3-gettext/dist/bin/gettext_extract.js:79:125
    at Array.forEach (<anonymous>)
    at [...]/my_project/node_modules/vue3-gettext/dist/bin/gettext_extract.js:76:23
    at HtmlParser.parseNode ([...]/my_project/node_modules/gettext-extractor/dist/html/parser.js:19:13)
    at HtmlParser.parseNode ([...]/my_project/node_modules/gettext-extractor/dist/html/parser.js:24:49)

Read languages from LINGUAS file

Currently when running vue-gettext-extract or vue-gettext-compile only languages specified in gettext.config.js are processed. It would be nice if I could configure to read the LINGUAS file and process all languages specified in there.

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.