Vue · vue-i18n

The JSON your build imports, reviewed and merged like code.

vue-i18n takes a plain object of messages per locale, which in practice is a JSON file you import — or several of them, once one file has more owners than it can hold. Mergua reads and writes those files in place, so your app keeps the setup it has and gains a branch, a review step and a pipeline that fills them in.

Vue + vue-i18n

/for/vue-i18n

Supported

locale files

src/locales

json shape

nested

01

The files you already have

Mergua reads what is in your repo. Nothing is renamed, nothing moves, and no package is added to your project — the sync script is fetched with curl when the pipeline runs.

src/locales/
├── en.json      ← source locale
├── de.json
└── fr.json
src/locales/en.json
{
  "cart": {
    "summary": {
      "title": "Your cart",
      "items": "{count} items",
      "checkout": "Checkout"
    }
  }
}
02

How vue-i18n reads them

This is vue-i18n's own setup, not Mergua's — if you already have it, skip the panel. It is here so the page is a working path from empty project to translated screen rather than a page about a product.

src/cart/CartSummary.vue
<script setup lang="ts">
import { useI18n } from 'vue-i18n';

defineProps<{ count: number }>();

const { t } = useI18n();
</script>

<template>
  <section>
    <h1>{{ t('cart.summary.title') }}</h1>
    <p>{{ t('cart.summary.items', { count }) }}</p>
  </section>
</template>

src/i18n.ts

import { createI18n } from 'vue-i18n';

import en from './locales/en.json';
import de from './locales/de.json';
import fr from './locales/fr.json';

export const i18n = createI18n({
  legacy: false,
  locale: 'en',
  fallbackLocale: 'en',
  messages: { en, de, fr },
});
03

Back into the build

One job, and the locale files in src/locales are the ones your build imports. Keys you added in code go up, finished translations come back down as a commit on the branch the job is running on.

The job runs on the branch it is already on, so a feature branch syncs against the matching Mergua branch and main against main. That is the part no other translation tool does.

And you do not have to run it on a timer: a project can POST to a URL of yours when translations change or a branch is merged, so the job above starts on the change. The delivery is signed, it is filtered to the branch you name, and an import of four hundred keys arrives as one call.

# --path, because the CLI defaults to Angular's src/assets/i18n.
# --format stays nested, which is the shape createI18n expects.
curl -sf https://api.mergua.com/v1/mergua.sh | sh -s -- sync --path src/locales
04

Placeholders

vue-i18n writes a variable as {count}. Mergua treats it as part of the string: if a translation comes back without it, the validator says so on the way out, and the AI translator is told to carry it through.

the source string
"items": "{count} items"
what fills it in
t('cart.summary.items', { count: 3 })

Worth knowing on Vue

Single braces, and that matters

vue-i18n names a variable {count}. Transloco and i18next both write {{count}}. A file copied from one to the other renders the braces as text, which is exactly the class of mistake Mergua's placeholder check catches on the way out.

Bundle the messages, do not fetch them

createI18n takes the messages up front, so the JSON is imported and bundled rather than requested at runtime. Nothing in the sync changes — the CLI writes the files before the build reads them, which is why the job belongs in an early stage.

Several files per language, whenever you want them

A Mergua project holds more than one file per language, and vue-i18n has no opinion about it — you build the messages object, so a second file is a second import. It reads a folder per language with the files inside, src/locales/en/checkout.json, and the file name is what the keys are filed under: checkout.json becomes checkout, while a plain en.json is read as the language. The "split" tab above is that setup.

Splitting a language across several files

Vue I18n messages can be functions — those do not sync

A message compiled to a function in a .ts file is code, not data, and Mergua reads JSON. Keep the strings that need translating in the locale files and reserve functions for formatting you do not want a translator editing.

A different stack?

It is JSON in and JSON out, so anything that reads a locale file works. These are the three with a page of their own.

Run it on one branch.

Upload the src/locales/en.json you already have and see the whole loop on the free tier.

Create your account