Why using i18n sections in vue.js single file components is bad

Andreas Löw
Why using i18n sections in vue.js single file components is bad

When you start using vue-i18n, you have to make a choice whether you want to store your translations:

  • in an <i18n> section inside your Single File Components (SCF)
  • in your JavaScript code
  • in JSON files

For simple demo components and example, it's indeed an option to use one of the first 2 options: Code or the <i18n> section - simply because it does not really matter. And after all, it's easier to explain everything in a single file.

In the SFC file, your translations are exactly where the developer uses them: in the code. And this does not seem to be much of a difference compared to storing your CSS and template sections in the same .vue file:

    export default {
      name: 'App'

    <p>message: {{ $t('hello') }}</p>

<style scoped>
   p {
       color: red;

        "en": {
            "hello": "hello world!"
        "ja": {
            "hello": "こんにちは、世界!"

But what is bad about the <i18n> section?

Developers are (usually) no translators

How many of your developers speak all languages you want to use in your application with perfection? Not all of them?

You'll end up giving the translation job to somebody who is most likely not a developer. This poor person has to wade through code to update the translation messages trying to avoid breaking the code...

Should translators have access to your source code?

Instead of passing a single .json file which is completely isolated from the rest of the application, you have to pass your whole source code to the translators.

Isolating translations in SFC files prevents re-use of translations

Assume you are using dialogs in your application with the usual choices like "Yes", "No", "Cancel" or common texts like "Really delete {item}?" and so on. The same text strings would be part of several components, requiring a new translation for each of them - which increases the cost of translation. It also makes it hard to keep the wording in your application consistent.

Sharing components is hard

If you are sharing your components and somebody wants to change the texts or add new languages, they'll have to edit the code of the component.

Adding new languages requires a new release of the components

To add a language, you have to change the source code - which in the final consequence also requires making a new software for that component - even if nothing else is changed.

Translations increase your code size

The startup time of your application is slower because all languages are compiled into your code. Adding another language increases the download size even more.

What is the better choice?

BabelEdit 3 can help you with some issues. It makes it much easier to edit the translations without the need to edit the source code directly. But it still requires you to share the code with the translators and update the component for each language change.

Create one JSON file for each language

The better choice is to keep the translations isolated in separate files. Vue I18n also supports this in the form of JSON files.

What are the advantages?

Give the translators only what they need to complete the job

Let's assume you have your application in English and want to translate it to French. You give your translator the en.json file and tell him to create the fr.json file based on that file. That's it. Almost every translation software supports JSON files.

Keep changes small

Adding a new language is done by adding the JSON file and adjusting the loader code to support the new language.

Keep the application size small with lazy loading

Load only the languages the user of your application wants to use. You can determine this by checking the language setting of the browser - or by adding some preferences or language switch to your application.

But I've started with the <i18n> sections in my file. What should I do now?

No problem. You can use BabelEdit to copy your translations to JSON files. Adjust your vue.js application to load the JSON file and get rid of the <i18n> sections - that's all.

I've created a tutorial for this: How to convert vue-i18n from single file components to JSON.