{"id":13418884,"url":"https://github.com/Polyconseil/vue-gettext","last_synced_at":"2025-03-15T04:30:59.100Z","repository":{"id":9596094,"uuid":"62710418","full_name":"Polyconseil/vue-gettext","owner":"Polyconseil","description":"Translate your Vue.js applications with gettext.","archived":false,"fork":false,"pushed_at":"2022-12-30T17:51:55.000Z","size":1551,"stargazers_count":278,"open_issues_count":38,"forks_count":55,"subscribers_count":36,"default_branch":"master","last_synced_at":"2024-08-30T23:25:08.987Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Polyconseil.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-07-06T09:51:43.000Z","updated_at":"2024-07-23T02:23:00.000Z","dependencies_parsed_at":"2023-01-13T15:27:24.032Z","dependency_job_id":null,"html_url":"https://github.com/Polyconseil/vue-gettext","commit_stats":null,"previous_names":[],"tags_count":47,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Polyconseil%2Fvue-gettext","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Polyconseil%2Fvue-gettext/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Polyconseil%2Fvue-gettext/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Polyconseil%2Fvue-gettext/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Polyconseil","download_url":"https://codeload.github.com/Polyconseil/vue-gettext/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242640907,"owners_count":20162054,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-30T22:01:08.370Z","updated_at":"2025-03-15T04:30:58.797Z","avatar_url":"https://github.com/Polyconseil.png","language":"JavaScript","funding_links":[],"categories":["JavaScript","Awesome Vue.js [![Awesome](https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg)](https://github.com/sindresorhus/awesome)","公用事业","Components \u0026 Libraries","Utilities","Utilities [🔝](#readme)"],"sub_categories":["Libraries \u0026 Plugins","国际化","Utilities","i18n"],"readme":"# vue-gettext\n\nTranslate [Vue.js](http://vuejs.org) applications with [gettext](https://en.wikipedia.org/wiki/Gettext).\n\n[Live demo](https://polyconseil.github.io/vue-gettext/).\n\n## No Vue 3 support\n\nThis project **does not** support Vue 3. Please, have a look at [vue3-gettext](https://github.com/jshmrtn/vue3-gettext) for Vue 3 support.\n\n## Contribution\n\nPlease make sure to read the [Pull request guidelines](https://github.com/Polyconseil/vue-gettext/blob/master/README_DEV.md#pull-request-guidelines) before making a pull request.\n\n## Known issues\n\nAny help is greatly appreciated:\n\n- It could be tricky to parse some `.vue` files, see [#28](https://github.com/Polyconseil/vue-gettext/issues/28)\n- Translations in attributes is not supported yet, see [#9](https://github.com/Polyconseil/vue-gettext/issues/9)\n- `vue-gettext` is not SSR compliant, see [#51](https://github.com/Polyconseil/vue-gettext/issues/51)\n\n# Introduction\n\n`vue-gettext` is a plugin to translate Vue.js applications with [`gettext`](http://www.labri.fr/perso/fleury/posts/programming/a-quick-gettext-tutorial.html). It relies on the [GNU gettext toolset](https://www.gnu.org/software/gettext/manual/index.html) and [`easygettext`](https://github.com/Polyconseil/easygettext).\n\n## How does `vue-gettext` work at a high level?\n\n1. **Annotating strings**: to make a Vue.js app translatable, you have to annotate the strings you want to translate in your JavaScript code and/or templates.\n\n2. **Extracting strings**: once strings are annotated, you have to run extraction tools ([`gettext-extract`](https://github.com/Polyconseil/easygettext#gettext-extract) and some GNU gettext utilities) to run over a Vue.js app source tree and pulls out all strings marked for translation to create a message file. A message file is just a plain-text file with a `.po` file extension, representing a single language, that contains all available translation strings as keys and how they should be represented in the given language.\n\n3. **Translating message files**: a translator needs to fill out the translations of each generated `.po` files.\n\n4. **Compiling translations**: once all message files have been translated, use [`gettext-compile`](https://github.com/Polyconseil/easygettext#gettext-compile) to make the translated `.po` files usable in a Vue app. This will basically merge all translated `.po` files into a unique `.json` translation file.\n\n5. **Dynamically render translated strings to the DOM**: `vue-gettext` currently uses a custom component for this.\n\n## What does `vue-gettext` provide?\n\n- a custom `component` and a custom `directive` to annotate strings in templates and dynamically render translated strings to the DOM\n\n- a set of methods to annotate strings in JavaScript code and translate them\n\n- a `language` ViewModel exposed to every Vue instances that you can use to:\n\n  - get all available languages (defined at configuration time)\n\n  - get or set the current language (*initially* defined at configuration time)\n\n  - access whatever you passed to the plugin mixin (defined at configuration time)\n\n- a global and reactive `language` property added to `Vue.config` you can use to get or set the current language *outside* of Vue instances\n\n## What does `vue-gettext` depend on?\n\n- [`easygettext`](https://github.com/Polyconseil/easygettext)\n\n    - [`gettext-extract`](https://github.com/Polyconseil/easygettext#gettext-extract) to extract annotated strings from template files and produce a `.pot` (Portable Object Template) file.\n\n    - [`gettext-compile`](https://github.com/Polyconseil/easygettext#gettext-compile) to produce the sanitized JSON version of a `.po` file.\n\n- Some GNU gettext utilities to extract annotated strings from JavaScript files and generate `.po` files\n\n    - [`msgmerge`](https://www.gnu.org/software/gettext/manual/html_node/msgmerge-Invocation.html#msgmerge-Invocation)\n\n    - [`msginit`](https://www.gnu.org/software/gettext/manual/html_node/msginit-Invocation.html#msginit-Invocation)\n\n    - [`msgattrib`](https://www.gnu.org/software/gettext/manual/html_node/msgattrib-Invocation.html#msgattrib-Invocation)\n\nThose tools should be integrated in your build process. We'll show you an example later.\n\n# Installation\n\n## NPM\n\n```javascript\nnpm install vue-gettext\n```\n\n## Basic installation\n\nBasic installation with ES6 modules:\n\n```javascript\n// ES6\nimport Vue from 'vue'\nimport GetTextPlugin from 'vue-gettext'\nimport translations from './path/to/translations.json'\n\nVue.use(GetTextPlugin, {translations: translations})\n```\n\n## Configuration\n\nThere are a number of options you can use to configure the `vue-gettext` plugin:\n\n| Option | Type | Requirement | Description |\n| ------------- | ------------- | ------------- | ------------- |\n| `autoAddKeyAttributes` | `{Boolean}` | optional | If `true`, key attributes are auto-generated if not present in your code. See the [`key` documentation](https://vuejs.org/v2/api/#key) and issues [#29](https://github.com/Polyconseil/vue-gettext/issues/29) and [#66](https://github.com/Polyconseil/vue-gettext/issues/66). Default value is `false`. Enable this option only if you know what you're doing. |\n| `availableLanguages` | `{Object}` | optional | An object that represents the list of the available languages for the app whose keys are [**local names**](http://www.localeplanet.com/icu/) (e.g. [`en`](https://www.gnu.org/software/gettext/manual/html_node/Language-Codes.html#Language-Codes) or [`en_US`](https://www.gnu.org/software/gettext/manual/html_node/Country-Codes.html#Country-Codes)) and whose values are [**language names**](http://docs.translatehouse.org/projects/localization-guide/en/latest/l10n/languagenames.html) used for the display in UI, e.g. `English (United States)`. It's exposed in all Vue instances via `vm.$language.available` |\n| `defaultLanguage` | `{String}` | optional | The [**local name**](http://www.localeplanet.com/icu/) of the default language, e.g. `en_US`. This will be the current active language. It's exposed in all Vue instances via `vm.$language.current` |\n| `muteLanguages` | `{Array}` | optional | Discard warnings for missing translations for all languages of the list. This is useful to avoid messages from the language used in source code. |\n| `languageVmMixin` | `{Object}` | optional | A [**mixin**](https://vuejs.org/v2/guide/mixins.html#Option-Merging) that will be passed to the main `languageVm` instance (exposed via `$language`) that can be used, for example, to add custom computed properties |\n| `silent` | `{Boolean}` | optional | Enable or disable logs/warnings for missing translations and untranslated keys. Default value is [`Vue.config.silent`](https://vuejs.org/v2/api/#silent). |\n| `translations` | `{Object}` | required | The JSON file of the application's translations (produced by `gettext-compile`). It's exposed as a Vue global property as `Vue.$translations` |\n\nThe key special attribute is primarily used as a hint for Vue's virtual DOM algorithm to identify VNodes when diffing ... Vue uses an algorithm that minimizes element movement and tries to patch/reuse elements of the same type in-place as much as possible.\n\n\n\nExample:\n\n```javascript\n// ES6\nimport Vue from 'vue'\nimport GetTextPlugin from 'vue-gettext'\nimport translations from './path/to/translations.json'\n\nVue.use(GetTextPlugin, {\n  availableLanguages: {\n    en_GB: 'British English',\n    en_US: 'American English',\n    es_US: 'Español',\n    fr_FR: 'Français',\n    it_IT: 'Italiano',\n  },\n  defaultLanguage: 'fr_FR',\n  languageVmMixin: {\n    computed: {\n      currentKebabCase: function () {\n        return this.current.toLowerCase().replace('_', '-')\n      },\n    },\n  },\n  translations: translations,\n  silent: true,\n})\n```\n\n## `vm.$language`\n\nAfter the plugin initialization, a `languageVm` Vue instance is injected\ninto every component as `vm.$language`.\n\nIt exposes the following properties:\n\n- `vm.$language.available`: an object that represents the list of the available languages (defined at configuration time)\n\n- `vm.$language.current`: the current language (defined at configuration time)\n\n- whatever you passed to the plugin mixin\n\nYou can use `vm.$language.current` and `vm.$language.available` to e.g. easily build a language switch component with a single template:\n\n```html\n\u003ctemplate\u003e\n  \u003cdiv\u003e\n    \u003cselect name=\"language\" v-model=\"$language.current\"\u003e\n      \u003coption v-for=\"(language, key) in $language.available\" :value=\"key\"\u003e{{ language }}\u003c/option\u003e\n    \u003c/select\u003e\n  \u003c/div\u003e\n\u003c/template\u003e\n```\n\n## `Vue.config.language`\n\nAfter the plugin initialization, a global and reactive `language` property is added to `Vue.config` that you can use to get or set the current language outside of Vue instances.\n\n```javascript\n\u003e Vue.config.language\n'en_GB'\n\u003e Vue.config.language = 'fr_FR'\n```\n\nYou can use `Vue.config.language` to e.g. configure a third party plugin in a filter:\n\n```javascript\nimport moment from 'moment'\nimport Vue from 'vue'\n\nconst dateFormat = function (value, formatString) {\n  moment.locale(Vue.config.language)\n  return moment(value).format(arguments.length \u003e 1 ? formatString : 'dddd D MMMM HH:mm:ss')\n}\n```\n\n# Workflow\n\n1. Annotate your strings\n\n2. Extract translations (`make makemessages`)\n\n3. Translate message files\n\n4. Compile translations (`make translations`)\n\n```\n   Annotate    |       Extract        |              Translate                 |        Compile\n--------------------------------------------------------------------------------------------------------\ncomponent.js\ncomponent.vue ---\u003e /tmp/template.pot ---\u003e app/locale/fr_FR/LC_MESSAGES/app.po ---\u003e app/translations.json\ntemplate.html\n```\n\n## 1a) Annotating strings in templates (`.html` or `.vue` files)\n\n### Use the component or the directive\n\nStrings are marked as translatable in your templates using either the `translate` component or the `v-translate` directive:\n\n```html\n\u003ctranslate\u003eHello!\u003c/translate\u003e\n\u003cspan v-translate\u003eHello!\u003c/span\u003e\n```\n\nThis will automatically be translated. For instance, in French, it might read *Bonjour !*.\n\n#### Singular\n\n```html\n\u003ctranslate\u003eHello!\u003c/translate\u003e\n```\n\n#### Plural\n\n```html\n\u003ctranslate :translate-n=\"count\" translate-plural=\"%{ count } cars\"\u003e%{ count } car\u003c/translate\u003e\n```\n\n#### Context\n\n```html\n\u003ctranslate translate-context=\"Verb\"\u003eFoo\u003c/translate\u003e\n```\n\n#### Comment\n\n```html\n\u003ctranslate translate-comment=\"My comment for translators\"\u003eFoo\u003c/translate\u003e\n```\n\n#### Custom parameters\n\nYou can set up translation strings that are agnostic to how your app state is structured. This way you can change variable names within your app, it won't break your translation strings.\n\n```html\n\u003ctranslate :translate-params=\"{name: userFullName}\"\u003eFoo %{name}\u003c/translate\u003e\n```\n\n### HTML support: difference between the component and the directive\n\nIt proves to be tricky to support interpolation with HTML content in Vue.js **components** because it's hard to access the raw content of the component itself.\n\nSo if you need to include HTML content in your translations you may use the **directive**.\n\nThe directive has the same set of capabilities as the component, **except for translate-params** which should be passed in as an expression.\n\n```html\n\u003cp\n  v-translate='{count: carNumbers}'\n  :translate-n=\"carNumbers\"\n  translate-plural=\"\u003cstrong\u003e%{ count }\u003c/strong\u003e cars\"\n  translate-comment=\"My comment for translators\"\n  \u003e\n  \u003cstrong\u003e%{ count }\u003c/strong\u003e car\n\u003c/p\u003e\n```\n\n### Custom HTML tag for the `translate` component\n\nWhen rendered, the content of the `translate` component will be wrapped in a `span` element by default. You can also use another tag:\n\n```html\n\u003ctranslate tag=\"h1\"\u003eHello!\u003c/translate\u003e\n```\n\n### Interpolation support\n\nSince [interpolation inside attributes are deprecated](https://vuejs.org/v2/guide/syntax.html#Attributes) in Vue 2, we have to use another set of delimiters. Instead of the \"Mustache\" syntax (double curly braces), we use `%{` and `}`:\n\n```html\n\u003ctranslate\u003eHello %{ name }\u003c/translate\u003e\n```\n\n### Directive, interpolation and raw HTML in data\n\nRaw HTML in data is interpreted as plain text, not HTML. In order to output real HTML, you will need to use the `render-html` attribute and set it to `true`.\n\n```html\n\u003cp\n  v-translate\n  render-html=\"true\"\n  \u003e\n  Hello %{ openingTag }%{ name }%{ closingTag }\n\u003c/p\u003e\n```\n\nDynamically rendering arbitrary HTML on your website can be very dangerous because it can easily lead to XSS vulnerabilities. Only use HTML `render-html=\"true\"` on trusted content and never on user-provided content.\n\n### Caveats\n\n#### Caveat when using `v-translate` with interpolation\n\nIt's not possible (yet) to detect changes on the parent component's data, so you have to add an expression to the directive to provide a changing binding value. This is so that it can do a comparison on old and current value before running the translation in its `update` hook.\n\nIt is described in the [official guide](https://vuejs.org/v2/guide/custom-directive.html#Hook-Functions):\n\n\u003e update: called after the containing component has updated, but possibly before its children have updated. The directive's value may or may not have changed, but you can skip unnecessary updates by comparing the binding's current and old values...\n\n```html\n\u003cp\n  v-translate='{count: count, brand: brand}'\n  :translate-n=\"count\"\n  translate-plural=\"\u003cstrong\u003e%{ count }\u003c/strong\u003e %{brand} cars\"\n  translate-comment=\"My comment for translators\"\n  \u003e\n  \u003cstrong\u003e%{ count }\u003c/strong\u003e %{brand} car\n\u003c/p\u003e\n```\n\n#### Caveat when using either the component `\u003ctranslate\u003e` or directive `v-translate` with interpolation inside `v-for`\n\nIt's not possible (yet) to access the scope within `v-for`, example:\n\n```html\n\u003cp\u003e\n  \u003ctranslate v-for='name in names'\u003eHello %{name}\u003c/translate\u003e\n  \u003cspan v-for='name in names' v-translate\u003eHello %{name}\u003c/span\u003e\n\u003c/p\u003e\n```\n\nWill result in all `Hello %{name}` being rendered as `Hello name`.\n\nYou need to pass in custom parameters for it to work:\n\n```html\n\u003cp\u003e\n  \u003ctranslate v-for='name in names' :translate-params='{name: name}'\u003eHello %{name}\u003c/translate\u003e\n  \u003cspan v-for='name in names' v-translate='{name: name}'\u003eHello %{name}\u003c/span\u003e\n\u003c/p\u003e\n```\n\n#### Caveat when using `v-translate` with Vue components or Vue specific attributes\n\nIt's not possible (yet) to support components or attributes like `v-bind` and `v-on`. So make sure that your HTML translations stay basic for now.\n\nFor example, this is *not supported*:\n\n```html\n\u003cp v-translate\u003e\n  Please \u003cbutton @click='doSomething'\u003eclick\u003c/button\u003e here to view \u003cmy-account\u003e\u003c/my-account\u003e\n\u003c/p\u003e\n```\n\n## 1b) Annotating strings in JavaScript code (`.js` or `.vue` files)\n\nStrings are marked as translatable in your Vue instances JavaScript code using methods attached to `Vue.prototype`.\n\n### Singular\n\n```javascript\nvm.$gettext(msgid)\n```\n\n### Plural\n\n```javascript\nvm.$ngettext(msgid, plural, n)\n```\n\n### Context\n\n```javascript\nvm.$pgettext(context, msgid)\n```\n\n### Context + Plural\n\n```javascript\nvm.$npgettext(context, msgid, plural, n)\n```\n\n### Interpolation support\n\nYou can use interpolation in your JavaScript using another method attached to `Vue.prototype`: `vm.$gettextInterpolate`.\n\n```javascript\n...\nmethods: {\n  alertPlural (n) {\n    let translated = this.$ngettext('%{ n } foo', '%{ n } foos', n)\n    let interpolated = this.$gettextInterpolate(translated, {n: n})\n    return window.alert(interpolated)\n  },\n},\n...\n```\n\n`vm.$gettextInterpolate` dynamically populates a translation string with a given context object.\n\n## 2) Extracting strings\n\nThis should be a step in your build process and this can be done in several ways.\n\nHere are the things we must do:\n\n1. extracting annotated strings from templates (`.html` and/or `.vue` files),\n\n2. extracting annotated strings from JavaScript code (`.js` and/or `.vue` files),\n\n3. creating a main `.pot` template based on the extracted strings,\n\n4. creating editable `.po` files for each available language.\n\nYou'll need to install [`easygettext`](https://github.com/Polyconseil/easygettext) and use `gettext-extract` to extract annotated strings from template files and produce a `.pot` file.\n\nYou'll also need some GNU gettext utilities, namely `msgmerge`, `msginit` and `msgattrib` to generate `.po` files from the `.pot` dictionary file.\n\nWe use a `Makefile` with a `makemessages` target to automate this step. To give you an example, I included a `Makefile` with a `makemessages` target in this project that you can include in your build process.\n\nExtracting strings and generating `.po` files becomes as easy as running:\n\n```shell\nmake makemessages\n```\n\n## 3) Translating message files\n\nThe translator needs to fill out the translations of each generated `.po` files.\n\nThis can be done by you or outsourced to other firms or individuals since `.po` files are the industry standard for multilingual websites.\n\nThere is also a wide range of translation tools available in the gettext ecosystem. Some of them are listed on [Wikipedia](https://en.wikipedia.org/wiki/Gettext#See_also).\n\n## 4) Compiling translations\n\nThis step focuses on making the translated `.po` files usable in your Vue.js app.\n\nOnce translated, install `easygettext` and use [`gettext-compile`](https://github.com/Polyconseil/easygettext#gettext-compile) to merge all translated `.po` files into a unique `.json` translation file.\n\nEmbed the `.json` translation file back into your application. This is done only one time at `vue-gettext` configuration time.\n\nWe use a `Makefile` with a `translations` target to automate this step.\n\nCompiling translations becomes as easy as running:\n\n```shell\nmake translations\n```\n\nLook at the included `Makefile` for an example.\n\n# Usage of `translate` without Vue\n\nFor convenience `translate` can be imported directly in JavaScript files for cases where you need the translations from `translations.json` outside of `vue-gettext` (see [#113](https://github.com/Polyconseil/vue-gettext/pull/113)):\n\n```js\nimport {translate} from 'vue-gettext';\n\nconst {gettext: $gettext, gettextInterpolate} = translate;\n\nconst str = $gettext('Hello, %{name}');\nconst strFR = $gettext('Hello, %{name}', 'fr');\nconst interpolated = gettextInterpolate(str, { name: 'Jerom' })\n```\n\n# Elsewhere\n\n## Support for Pug templates\n\nIf you are using a template language, i.e. [Pug.js](https://pugjs.org/api/getting-started.html) in [Single File Component](https://vuejs.org/v2/guide/single-file-components.html) within a webpack setup (using vue-loader), have a look at [vue-webpack-gettext](https://github.com/kennyki/vue-webpack-gettext).\n\n# Credits\n\nThis plugin was inspired by:\n\n- [`systematic`](https://github.com/Polyconseil/systematic) for Makefile and\n    extraction of translatable strings.\n- [`angular-gettext`](https://angular-gettext.rocketeer.be)\n- [`vue-i18n`](https://github.com/kazupon/vue-i18n)\n\n# License\n\n[MIT](http://opensource.org/licenses/MIT)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPolyconseil%2Fvue-gettext","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FPolyconseil%2Fvue-gettext","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPolyconseil%2Fvue-gettext/lists"}