YAML plugins
A YAML plugin is a data file that holds the declarative part of the plugin API. Name it <name>.x18n-plugin.yml, and list its path in plugins:
plugins:
- ./x18n/acme.x18n-plugin.ymlA full example
This plugin supports a made-up library, @acme/i18n, with YAML locale files, a translate function, a useTranslate factory and Handlebars templates:
# yaml-language-server: $schema=https://x18n.antfu.dev/schema/plugin.json
name: acme-i18n
config:
sourceLocale: en
resources:
- pattern: 'src/i18n/{locale}.yml'
scanners:
calls:
- callee: [translate, i18n.translate]
- callee: useTranslate
factory: true
returns: [translate]
keyPrefix: {arg: 0}
regex:
- extensions: [hbs]
patterns:
- '\{\{t "({key})"'
placeholders:
- '%{name}'
derivedKeys:
- '{key}.zero'
- '{key}.other'
extract:
templates:
- template: "translate('{key}'{args})"
kinds: [js-string, js-template]
imports:
- "import { translate } from '@acme/i18n'"The first line points the YAML language server at the JSON Schema. With the Red Hat YAML extension, VS Code then validates the file and completes the keys. x18n schema plugin prints the same schema. A file that does not match the schema stops the load with X18N1004.
Sections
name
The name of the plugin. It is required and must be unique.
config
Defaults for the config of the project: sourceLocale, locales, resources, namespace and keyStyle. The config file of the project wins over them. resources applies only when the config sets none.
Scanners
scanners.calls lists translate calls for the AST scanners of JS, TS, JSX, Vue and Svelte files. Each entry has the shape of an item of usage.calls:
| Field | Meaning |
|---|---|
callee | A name or member path, or a list of them: t, i18n.t, intl.formatMessage. |
key | Which argument holds the key: an index (default 0), or { arg, property } for a property of an object argument. |
namespace | Where the namespace comes from: { arg, property }. |
keyPrefix | Where a key prefix comes from: { arg, property }. |
factory | The callee returns translate functions, as useI18n() does. |
returns | For a factory: the names of the returned functions. Default [t]. |
types | Type names that make a parameter a translate function, such as TFunction. |
kind | call (default), selector for t($ => $.a.b), or accessor for a member chain on a root. |
scanners.regex lists regex scanners for other file types. Each entry has extensions (without the dot) and patterns. A pattern is a regular expression whose first group is the key. Write {key} inside the group, as in ({key}): x18n replaces {key} with a pattern for key characters. This is the same format as usageMatchRegex of i18n-ally.
In YAML, write regular expressions in single quotes, so that backslashes stay as they are.
scopes
scopes.regex is a regular expression whose first group is a namespace. The code after each match, up to the next match, uses that namespace. This is the same as scopeRangeRegex of i18n-ally.
derivedKeys
Rules such as {key}_plural. When a key is used, the keys that a rule derives from it count as used too. A * matches any text: {key}_*.
normalizeKey
Rules that rewrite the raw key text of a usage before x18n looks it up. This rule turns t('pages/home/title') into the key pages.home.title:
normalizeKey:
- replace:
pattern: /
with: .pattern is a regular expression. Every match is replaced.
Placeholders
placeholders lists placeholder shapes. Each shape holds the word name where the placeholder name goes: {name}, {{name}}, %{name} or :name.
localeInfo
The display name and flag of locale codes, for the UI and the editor:
localeInfo:
zh_Hant:
displayName: Traditional Chinese
flag: 🇹🇼extract
extract.templates adds extraction templates. An entry is a template string, or an object with template, kinds, files and imports.
detect and exclusive
detect and exclusive turn the plugin into a preset:
detect:
dependencies:
any: ['@acme/i18n']
files: ['src/i18n/*.yml']
exclusive: trueThe preset applies when the project depends on any package of dependencies.any, on every package of dependencies.all, and has a file for each glob of files. With exclusive: true, x18n tests no preset after it.
x18n runs detect only for a preset inside the plugins of another preset. A preset that you list in plugins or presets always applies.
Move to TypeScript
x18n plugin eject prints the TypeScript version of a YAML plugin. It uses the same built-in functions, so the result behaves the same:
x18n plugin eject x18n/acme.x18n-plugin.yml > x18n/acme.tsThen list ./x18n/acme.ts in plugins instead of the YAML file. See TypeScript plugins.
The schema
The plugin file has this shape:
/** A YAML plugin (`*.x18n-plugin.yml`): the declarative subset of the plugin API. */
export interface PluginFile {
readonly $schema?: string | undefined
readonly name: string
readonly detect?: {
readonly dependencies?: { readonly any?: readonly string[] | undefined, readonly all?: readonly string[] | undefined } | undefined
readonly files?: readonly string[] | undefined
} | undefined
readonly exclusive?: boolean | undefined
readonly config?: {
readonly sourceLocale?: string | undefined
readonly locales?: readonly string[] | undefined
readonly resources?: readonly ResourceSpec[] | undefined
readonly namespace?: NamespaceOptions | undefined
readonly keyStyle?: 'auto' | 'nested' | 'flat' | undefined
} | undefined
readonly scanners?: {
readonly calls?: readonly CallSpec[] | undefined
readonly regex?: readonly RegexScannerSpec[] | undefined
} | undefined
readonly scopes?: {
/** Regex whose first group is the namespace of the code after it (i18n-ally `scopeRangeRegex`). */
readonly regex: string
} | undefined
readonly derivedKeys?: readonly string[] | undefined
readonly normalizeKey?: readonly { readonly replace: { readonly pattern: string, readonly with: string } }[] | undefined
/** Placeholder shapes with `name` as the name: `{name}`, `{{name}}`, `%{name}`. */
readonly placeholders?: readonly string[] | undefined
readonly localeInfo?: { readonly [code: string]: { readonly flag?: string | undefined, readonly displayName?: string | undefined } } | undefined
readonly extract?: { readonly templates?: readonly (string | ExtractTemplate)[] | undefined } | undefined
}