# gt: General Translation CLI tool: Keyed metadata URL: https://generaltranslation.com/en-GB/docs/cli/reference/keyed-metadata.mdx --- title: Keyed metadata description: Attach per-key translation instructions to General Translation JSON and YAML files. API reference for keyed metadata. --- You provide a companion metadata file that mirrors the source file's key structure, with a metadata object at each leaf. Each object holds instructions for translating that one key. The CLI detects companion metadata files automatically, validates them against the source structure, and sends them to the translation engine. ## Fields [#fields] | Field | Description | Type | Optional | Default | | ---------------------------- | ---------------------------------------------------- | -------- | -------- | ------- | | [`context`](#context) | Translation instructions for a specific string. | `string` | Yes | — | | [`maxChars`](#max-chars) | Maximum character count for the translated output. | `number` | Yes | — | | [`sourceCode`](#source-code) | Surrounding source code context, keyed by file path. | `object` | Yes | — | ## File structure [#structure] A companion metadata file must be in the same directory as the source file, follow the naming convention `{name}.metadata.{ext}`, and mirror the source file's key structure with a metadata object at each leaf. ```text translations.json # source strings translations.metadata.json # per-key metadata ``` Only provide entries for keys that need instructions. Keys with no entry translate normally. ```json title="translations.json" { "nav": { "home": "Home", "bank": "Bank", "save": "Save" } } ``` ```json title="translations.metadata.json" { "nav": { "bank": { "context": "Riverbank — the side of a river. NOT a financial institution." }, "save": { "context": "Sports term — a goalkeeper preventing a goal. NOT saving data.", "maxChars": 12 } } } ``` ## `context` [#context] **Type** `string` · **Optional** · **Default** — Translation instructions applied to a specific string. Use it to disambiguate words with multiple meanings, specify domain terminology, or clarify the intended interpretation. ```json { "bank": { "context": "Riverbank. The side of a river where land meets water, NOT a financial institution." } } ``` ## `maxChars` [#max-chars] **Type** `number` · **Optional** · **Default** — A maximum character limit on the translated output. The engine uses shorter synonyms, abbreviations or concise phrasing to fit within the limit. This is best-effort: if the limit is unfeasible for the source content, the full translation is returned. ```json { "save": { "maxChars": 10 } } ``` ## `sourceCode` [#source-code] **Type** `object` · **Optional** · **Default** — Surrounding source code context for a string, keyed by file path. Each entry contains `before` (lines above the target line), `target` (the line with the string), and `after` (lines below). Multiple entries per file are supported when the same string appears in different locations. ```json { "new_lead": { "sourceCode": { "components/Dashboard.tsx": [ { "before": "function NotificationBanner({ type }) {\n const gt = useGT();", "target": " const msg = gt('You have a new lead!');", "after": " return {msg};\n}" } ] } } } ``` ### Combined example All three fields on a single key: ```json { "save_button": { "context": "Sports term. A goalkeeper's save — preventing a goal from being scored. NOT saving data.", "maxChars": 12, "sourceCode": { "components/MatchStats.tsx": [ { "before": "const stats = useMatchStats();\nconst gt = useGT();", "target": "const label = gt('Save');", "after": "return }>{label}: {stats.saves};" } ] } } } ``` ## YAML [#yaml] Metadata works in the same way with `.metadata.yaml` or `.metadata.yml` companion files. ```yaml title="translations.metadata.yaml" ui: buttons: save: context: "Sports term. A goalkeeper's save, NOT saving data." maxChars: 12 labels: date: context: "The edible fruit of the date palm. NOT a calendar date." ``` ## Validation [#validation] The CLI validates the metadata file against the source structure and exits with an error if a metadata key does not exist in the source, a value type does not match the source (primitive vs. object, array vs. object), the root type does not match, or the file cannot be parsed. ## Schema and matching [#schema] Keyed metadata works with JSON schemas (`include` and `composite`) and YAML schemas (`include`); metadata is transformed through the same schema pipeline so key paths align at translation time. Companion files are matched to their source file and are not translated on their own — a `.metadata.json` file with no matching source is treated as a regular file. Changing metadata alone does not trigger re-translation; the source content must also change.