Vue templates internationalization

<p>Hello world!</p><p>{{ $t('helloWorld') }}</p>
<!-- locales/en.js: helloWorld: 'Hello world!' -->

<p>Hello, {{ user }}!</p><p>{{ $t('hello', {user: user}) }}</p>
<!-- locales/en.js: helloWorld: 'Hello, {user}!' -->

<p>Hello, {{ user }}!</p><p>{{ $t('hello', [user]) }}</p>
<!-- locales/en.js: helloWorld: 'Hello, {0}!' -->

Features supported

Configure hardcoded strings extraction from Vue templates

The plugin should automatically configure itself for project with dependencies on vue-i18n and nuxt-i18n, but adjustments could be needed for custom setup.

Vue Templates Preferences screenshot

Scope

i18n Ally is applying inspections for files that have .vue extension and are included into a PhpStorm’s scope.

Create a new scope or adjust existing by clicking on button and handpicking only the meaningful directories and files.

Select Project files to include all .vue files in your project.

Inline tags

Extraction of strings with a special treatment of inline tags is not currently supported.

Translatable attribute names

Translatable attributes are also checked for the translatable text:

<img src="…"
     alt="Checked by default"
     title="Checked by default"
     data-content="Requires configuration" />

You can add custom attributes, like data-content, by appending a new attribute to the comma-separated list.

Replacement template

The “Replacement template” reflects the result of the hardcoded string extraction.function name and arguments template.

Recommended value for vue-i18n and nuxt-i18n packages: $t('%key%', %map%).

%key%

Short key or a natural language string that defines a translation.

%namespace%

Namespace (called ‘domain’ in Symfony) usually means a part of language file path from where translations would be searched for. The default namespace is usually messages, but could be changed by putting a namespace in first position in “Namespaces” field.

%map%

If there are no variables in the string, then nothing would be added.

Map will be replaced with an object if there are any placeholders detected: $t('key', {foo: fooVariable, bar: barVariable}).

Placeholder names will be determined automatically based on a respective variable, function or method name.

In language files placeholder syntax will be determined based on the Placeholder format setting of the language file.

%list%

If there are no variables in the string, then nothing would be added.

List will be replaced with an array if there are any placeholders detected: $t('key', [fooVariable, barVariable]).

In language files the ordered placeholder syntax {0}, {1} will be enforced.

%varargs%

If there are no variables in the string, then nothing would be added.

Varargs will be replaced with placeholder passed directly to the translation function if there are any placeholders detected: $t('key', fooVariable, barVariable).

In language files the ordered placeholder syntax {0}, {1} will be enforced.

Supported language constructs

All strings inside tags and translatable attributes are checked.

What’s not supported

  • Extracting strings from expressions, like {{ someFunc('Hello world!') }}
  • Reading and extracting keys from a <i18n> tag within single-file components
  • Renaming key names from language files

What strings are skipped

  • All attributes except ones listed in “Translatable attribute names” preference.
  • Strings that looks like code: without letters, multiple words without spaces or camelCased ones.

Best practice: dealing with branching in messages

It’s common to have small and simple branching for presentation purposes:

Webhook {{ isSuccess ? 'succeeded' : 'failed' }}.

The best practice it to separate this message into two different ones so translators would have a full context and would be able to adjust word order according the target language grammar.

1st step: manually extract the condition out of the message to get two messages without condition

<template v-if="isSuccess">Webhook succeeded.</template>
<template v-else>Webhook failed.</template>

2nd step: replace simple messages with i18n Ally

<template v-if="isSuccess">{{ $t('webhookSucceeded') }}</template>
<template v-else>{{ $t('webhookFailed') }}</template>