JavaScript/TypeScript internationalization

const foo = 'Hello world!';

const foo = $t('helloWorld');
// locales/en.js: 'helloWorld' => 'Hello world!'

const foo = `Welcome, ${name}`;
const foo = 'Welcome, ' + name;

const foo = $t('welcome', {name: name});
// locales/en.js: 'welcome' => 'Welcome, {user}!'

Features supported

Configure hardcoded strings extraction from PHP source

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

JavaScript Source Code Preferences screenshot

Scope

i18n Ally is applying inspections for files that have .js/.ts 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 .js/.ts files in your project.

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%).

It could be any callable JavaScript structure that wraps arguments into parentheses:

  • function: $t(…), __(…),
  • object method: this.$t(…), parent.$t(…).

%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

i18n Ally finds hardcoded user-facing strings and template literals:

'Welcome, John'     // $t('welcome') simple strings
`Welcome, {name}`  // $t('welcome', {name: name}) template literals
'Welcome, ' + name // $t('welcome', {name: name}) concatenated strings

Placeholder names are determined automatically.

What strings are skipped

  • All arguments passed to functions or methods (except constructors), but avaialbe to unignore case by case
  • Array keys,
  • Indexed array,
  • Class property definitions,
  • Default parameter values,
  • 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:

const foo = `Webhook <strong>${isSuccess ? 'succeeded' : 'failed'}</strong>.`;

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

const foo = isSuccess
  ? 'Webhook <strong>succeeded</strong>.'
  : 'Webhook <strong>failed</strong>.';

2nd step: replace simple messages with i18n Ally

const foo = isSuccess
  ? $t('webhookSucceeded')
  : $t('webhookFailed');