Concepts
x18n uses one name for each idea, in its code, docs, CLI output and UI. This page explains the names with one small project as the example:
src/
App.vue
locales/
en.json
de.json{
"app": {
"title": "My App",
"greeting": "Hello {name}"
},
"pages": {
"home": { "title": "Welcome" },
"about": { "title": "About us" }
}
}<script setup lang="ts">
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const page = 'home'
</script>
<template>
<h1>{{ t('app.title') }}</h1>
<p>{{ t('app.greeting', { name: 'Ada' }) }}</p>
<p>{{ t(`pages.${page}.title`) }}</p>
</template>The glossary lists every name in one table.
Project
A project is one i18n setup: one root directory, one config and one set of locales. Most repositories have one project. A monorepo can have many. See Monorepos.
Locale
A locale is a locale code, exactly as it is written in paths and files: en, de, zh_CN. x18n never changes the spelling of a code.
The source locale is the locale that is the source of truth. Checks compare the other locales with it, translate prompts translate from it, and go to definition opens its messages. Set it with sourceLocale. The default is en.
The display locale is the locale that the editor shows in annotations and hovers. Each user picks it for themselves. It defaults to the source locale.
Resource
A resource is a file, or a block inside a file, that holds the messages of one locale and one namespace. In the example, src/locales/en.json and src/locales/de.json are resources. A Vue <i18n> block is also a resource.
A format reads and writes one file format, such as JSON or YAML. A locale finder finds the resources. The built-in pattern finder uses the resources patterns of the config. See Configuration.
Key and message
A key is the id of a message. The example has the keys app.title, app.greeting, pages.home.title and pages.about.title. A key with child keys, such as pages, is a parent key. Commands such as x18n rename and x18n delete work on a parent key too: they change every key under it.
A message is the value of one key in one locale. "Hello {name}" is the message of app.greeting in en. {name} is a placeholder. The placeholder-mismatch check makes sure that each translation keeps the placeholders of the source message.
A locale file can store keys nested ({ "app": { "title": "..." } }) or flat ({ "app.title": "..." }). The key is the same in both cases. When x18n writes a file, it keeps the style that the file uses.
Namespace
A namespace is a named group of keys, usually taken from a file name. With the pattern locales/{locale}/{namespace}.json, the file locales/en/common.json holds the namespace common.
How a namespace appears in code depends on the library:
- With the default separator
., the namespace is the first part of the key path. The keysaveincommon.jsoniscommon.save. vue-i18n works this way. - With another separator, the project is namespaced. Keys then have the form
namespace:path, for examplecommon:save. i18next works this way, with:as the separator andtranslationas the default namespace.
Set the separator and the default namespace with the namespace option. The i18next presets set both.
Usage
A usage is one place in source code that uses a key. In the example, t('app.title') is a usage of app.title. A scanner finds usages. The built-in scanners read JS, TS, JSX, Vue and Svelte files. For other file types, such as PHP templates, add a regex scanner in usage.regex.
x18n counts only calls that it knows as translate calls. It follows string constants (const KEY = 'app.title', then t(KEY)) and both branches of a condition (t(ok ? 'a' : 'b')). The callee set of a file is the set of names that count: the names of the presets and of usage.calls, same-file aliases such as const tt = t, functions returned by factories such as useI18n(), and parameters typed as translate functions.
x18n usages <key> lists the usages of a key. x18n keys --unused lists the keys with no usage.
Prefix usage
A prefix usage is a usage with a computed key that starts with a static part. t(`pages.${page}.title`) is a prefix usage with the prefix pages. x18n cannot know the value of page, so every key under pages counts as possibly used. Neither pages.home.title nor pages.about.title is reported as unused.
A fully dynamic usage, such as t(key), has no static part. No check can follow it. The dynamic-key check, off by default, lists such usages. To mark keys as used that only code at runtime builds, add globs to usage.keysInUse. Or mark them in the code with a comment. // @x18n-key before a string marks that string as a key. // @x18n-keys before an expression, such as an array, marks every string in it:
// @x18n-keys
const tabs = ['tabs.overview', 'tabs.settings']Scope
A scope is a region of code with a default namespace or key prefix. In react-i18next, useTranslation('common') makes t('save') mean common:save in the code that uses that t. In next-intl, useTranslations('pages.home') makes t('title') mean pages.home.title. The presets know these factories. A YAML plugin can add scopes with a regular expression.
Hard string
A hard string is text in source code that is probably meant to be a message, such as <button>Save</button>. An extractor finds hard strings and builds the replacement code. x18n extract turns them into keys, and the hard-string check reports them when extract.autoDetect is on.
Plugin and preset
A plugin is an object that adds capabilities through the plugin API. A capability is one kind of contribution: a format, a locale finder, a scanner, an extractor, a check, a reporter or a placeholder syntax. A preset is a group of plugins for one library, with a rule that detects the library. See Writing plugins.
Check and diagnostic
A check reads the project and reports diagnostics. A diagnostic is one reported issue with a code, a severity and optional fixes. x18n check runs every check. See Checks.
Plan and decision
Every command that writes files first makes a plan. A plan is the list of file changes, made without writing anything. --dry-run prints the plan instead of applying it.
A plan can hold decisions. A decision is a question that the command must answer before it writes, for example which file gets a new key. In a terminal, x18n asks you. With --yes, it takes the default answer. With --json, or without a terminal, it stops with X18N4003.
Before x18n writes, it makes sure that no file changed since it made the plan. If a file changed, it writes nothing and stops with X18N4004.