4 Difficulties You Might Encounter When Using Vue-i18n

Written by demivan | Published 2021/08/27
Tech Story Tags: vue | internationalization | localization | i18n | project-fluent | fluent-vue | programming | vue-i18n

TLDR Vue-i18n is the most used Vue.js internationalization library. It has a complex API for developers and a complicated language grammar. Fluent syntax allows translators to call custom functions in translation messages. The language's grammar limits what features translators can use and leaks into app code and translations messages of other languages. fluent-vue has only 2 methods and one of them is rarely used. The library has a fixed number of developer-predefined date formats and the developer decides what format to use in each case.via the TL;DR App


After few months of frustration with trying to use the "de-facto" internationalization library for Vue.js - vue-i18n, I've decided it is time to replace it. And that is why I have created fluent-vue. I will write more about it and Fluent syntax it uses in my following blog posts.

In this post, I try to explain what problems I have encountered when trying to use the vue-i18n library in my app, and how fluent-vue and Fluent syntax solve them.

vue-i18n’s good parts:

Firstly, this is what I liked in vue-i18n:

1. Component interpolation

Component interpolation allows using components inside translation messages. Nice way of reducing v-html directive usages.

2. SFC custom blocks

Keeping translations for the component in the same file as template and js code is really convenient.

3. Tooling

Being the most used Vue.js internationalization library, it has a heap of useful packages and extensions.

vue-i18n’s issues:

And this is what I didn't like in vue-i18n or what didn't work for my project:

1. Complicated API for developers

vue-i18n has 5 different methods: ($t, $tc, $te, $d, $n). It has separate methods for formatting simple text, pluralized text, date, and numbers.

fluent-vue has only 2 methods and one of them is rarely used.

2. "Leaky" localizations

The grammar of the source language limits what features translators can use and leaks into app code and translations messages of other languages.

Example (pluralization):

If you want translators to be able to use pluralization, you need to use $tc method. Even if you don't need it for your source language. You cannot just write:

const messages = {
  en: {
    'copy-n-files': 'Copy {count} files'
  }
}

$t('copy-n-files', { count: filesCount })

You need to use $tc method with additional parameters:

$tc('copy-n-files', filesCount, { count: filesCount })

And translators still have no way of knowing, without checking application code, whether translation that uses the following format would be pluralized.

const messages = {
  en: {
    'copy-n-files': 'Copy {count} file | Copy {count} files'
  }
}

On top of that, if the translator tries to use this syntax and the developer did not use $tc method, it will not be pluralized and you will see both choice variants displayed in your app.

fluent-vue solution:

copy-n-files = { $count -> 
    [one] Copy file
   *[other] Copy {$count} files
}
$t('copy-n-files', { count: 5 })

This syntax can be used in any translation message to choose an option based on plural category, or even a concrete value.

3. Translators do not have control over translations

Developers are forced to make choices that translators should make: should the translation message be pluralized, and which date and number format should be used?

Example (date format):

vue-i18n has a fixed number of developer-predefined date formats, and the developer decides what format to use in each case.

const dateTimeFormats = {
  'en': {
    short: {
      year: 'numeric',
      month: 'short',
      day: 'numeric'
    },
    long: {
      ...
    }
  }
}

const messages = {
  'en': {
    'last-online': 'User was last online at {date}'
  }
}

$t('last-online', { date: $d(new Date(), 'short') })

Translators cannot change date formatting for a particular translation, for example, if it does not fit into the UI in some languages.

fluent-vue solution:

The fluent syntax allows translators to call custom functions in translation messages. There is the built-in DATETIME function:

last-online = User was last online at { DATETIME($date, year: "numeric", month: "short", month: "short") }
$t('last-online', { date: new Date() })

If you want to have predefined date formats, it can easily be implemented using a custom function. But translators will still be able to choose what format to use in each case.

4. Syntax is not powerful enough

Even with the $tc method there is no way to have pluralization that depends on counts of 2 or more objects:

$tc('apples-and-bananas', /* what should go here? */, { appleCount: 1, bananaCount: 5 })

const messages = {
  en: {
    'apples-and-bananas': '{appleCount} apples and {bananaCount} bananas'
  }
}

One possible solution for this issue is splitting translation into three different ones. But it does not look particularly good:

$t('apples-and-bananas', {
  appleCountText: $tc('apples', 1, { appleCount: 1 })
  bananaCountText: $tc('banana', 5, { bananaCount: 5 }
})

const messages = {
  en: {
    'apples-and-bananas': '{appleCountText} and {bananaCountText}'
    'apples': '{appleCount} apple | {appleCount} apples'
    'bananas': '{bananaCount} banana | {bananaCount} bananas'
  }
}

fluent-vue solution:

Thanks to Fluent syntax you can write translation, without splitting it, like this:

$t('apples-and-bananas', { appleCount: 1, bananaCount: 5 })
apples-and-bananas = {$appleCount -> 
    [1] An apple
   *[other] {$appleCount} apples
} and {$bananaCount -> 
    [1] a banana
   *[other] {$bananaCount} bananas
}

Also published on https://demivan.me/posts/2021-08-08-vue-i18n-in-real-world-application.


Written by demivan | Tech Lead, Full-Stack Developer working in Lviv, Ukraine. Currently working on Vue.js i18n plugin - fluent-vue
Published by HackerNoon on 2021/08/27