Skip to main content
Glama
fabkho
by fabkho

Write Translations

write_translations
DestructiveIdempotent

Write i18n translation key-value pairs to a layer using upsert, add, or update modes. Preview changes with dry run before writing files.

Instructions

Write translation key-value pairs to a layer. Keys are inserted in alphabetical order. Mode "upsert" adds new keys and updates existing ones (default, most common). Mode "add" only creates new keys, skipping existing ones. Mode "update" only modifies existing keys, skipping missing ones. Use dryRun to preview without writing.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
modeNoWrite mode. "upsert": add-or-update (never fails). "add": only new keys. "update": only existing keys. Default: "upsert".
layerYesLayer name from discover (e.g., "root", "app-admin").
dryRunNoReturn a preview of what would be written without writing any files. Default: false.
projectDirNoAbsolute path to the project root. Defaults to I18N_PROJECT_DIR, then server cwd. Example: "/home/user/my-app".
translationsYesMap of dot-path keys to locale-value pairs. IMPORTANT: values must be locale maps, NOT plain strings. Locale refs may be a code ("en-us"), a language ("en-US") or a file ("en-US.json"). Wrong: { "auth.failed": "Login failed" }. Correct: { "auth.failed": { "en-US": "Login failed", "de-DE": "Anmeldung fehlgeschlagen" } }

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
dryRunNoTrue when nothing was written because a preview was asked for. Absent otherwise.
messageNoThe step to take next, as the surface the call ran on phrases it. Present only when there is no summary to carry it.
skippedYesKeys the write mode left alone — existing keys under mode "add", missing ones under mode "update".
summaryNoCounts of what the run did. Absent on a dry run.
writtenNoDot-path keys that were written. Absent on a dry run.
warningsNoNon-fatal problems, e.g. a value written over a nested object. Absent when there are none.
wouldWriteNoThe writes a dry run would make. Present only with dryRun.
skippedKeysNoThe keys behind keysSkipped, when the mode skipped any. Absent when nothing was skipped.
filesWrittenNoNumber of locale files changed on disk. Absent on a dry run.
ambiguousLocalesNoLocale refs that matched several locales, with the one precedence picked. Absent when every ref was unambiguous.
unresolvedLocalesNoLocale refs that matched no known locale; their values were dropped while other locales were still written. Absent when every ref resolved.
placeholderValidationNoPlaceholder comparison of the written values against the reference locale. Absent when nothing was comparable.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed5 schema fields changedv1.0.6
    • changedInput schema / properties / dryRun / description
      Previous value: -"When true, returns a preview of what would be written without writing any files. Default: false."New value: +"Return a preview of what would be written without writing any files. Default: false."
    • changedInput schema / properties / layer / description
      Previous value: -"Layer name (e.g., \"root\", \"app-admin\"). Discover layers via the discover tool."New value: +"Layer name from discover (e.g., \"root\", \"app-admin\")."
    • changedInput schema / properties / projectDir / description
      Previous value: -"Absolute path to the Nuxt project root. Defaults to I18N_PROJECT_DIR, then server cwd. Example: \"/home/user/my-app\"."New value: +"Absolute path to the project root. Defaults to I18N_PROJECT_DIR, then server cwd. Example: \"/home/user/my-app\"."
    • changedInput schema / properties / translations / description
      Previous value: -"Map of dot-path keys to locale-value pairs. IMPORTANT: values must be locale maps, NOT plain strings. Locale refs may be code (\"en-us\"), language (\"en-US\"), or file (\"en-US.json\"). Wrong: { \"auth.failed\": \"Login failed\" }. Correct: { \"auth.failed\": { \"en-US\": \"Login failed\", \"de-DE\": \"Anmeldung fehlgeschlagen\" } }"New value: +"Map of dot-path keys to locale-value pairs. IMPORTANT: values must be locale maps, NOT plain strings. Locale refs may be a code (\"en-us\"), a language (\"en-US\") or a file (\"en-US.json\"). Wrong: { \"auth.failed\": \"Login failed\" }. Correct: { \"auth.failed\": { \"en-US\": \"Login failed\", \"de-DE\": \"Anmeldung fehlgeschlagen\" } }"
    • changedOutput schema / (root)
      Previous value: -nullNew value: +{
      +  "$schema": "https://json-schema.org/draft/2020-12/schema",
      +  "additionalProperties": false,
      +  "properties": {
      +    "ambiguousLocales": {
      +      "description": "Locale refs that matched several locales, with the one precedence picked. Absent when every ref was unambiguous.",
      +      "items": {
      +        "additionalProperties": false,
      +        "properties": {
      +          "candidates": {
      +            "description": "Codes of every locale the ref matched, in config order.",
      +            "items": {
      +              "type": "string"
      +            },
      +            "type": "array"
      +          },
      +          "matchedBy": {
      +            "description": "Which field of the locale the ref matched on, in resolution precedence order.",
      +            "enum": [
      +              "code",
      +              "language",
      +              "file"
      +            ],
      +            "type": "string"
      +          },
      +          "ref": {
      +            "description": "The locale ref as the caller wrote it.",
      +            "type": "string"
      +          },
      +          "resolvedTo": {
      +            "description": "The code that was used — the first candidate.",
      +            "type": "string"
      +          }
      +        },
      +        "required": [
      +          "ref",
      +          "matchedBy",
      +          "candidates",
      +          "resolvedTo"
      +        ],
      +        "type": "object"
      +      },
      +      "type": "array"
      +    },
      +    "dryRun": {
      +      "description": "True when nothing was written because a preview was asked for. Absent otherwise.",
      +      "type": "boolean"
      +    },
      +    "filesWritten": {
      +      "description": "Number of locale files changed on disk. Absent on a dry run.",
      +      "maximum": 9007199254740991,
      +      "minimum": -9007199254740991,
      +      "type": "integer"
      +    },
      +    "message": {
      +      "description": "The step to take next, as the surface the call ran on phrases it. Present only when there is no summary to carry it.",
      +      "type": "string"
      +    },
      +    "placeholderValidation": {
      +      "additionalProperties": false,
      +      "description": "Placeholder comparison of the written values against the reference locale. Absent when nothing was comparable.",
      +      "properties": {
      +        "errors": {
      +          "description": "One entry per translation that did not match. Empty when ok is true.",
      +          "items": {
      +            "additionalProperties": false,
      +            "properties": {
      +              "extra": {
      +                "description": "Placeholders the translation invented and the source does not have.",
      +                "items": {
      +                  "type": "string"
      +                },
      +                "type": "array"
      +              },
      +              "key": {
      +                "description": "Dot-path key of the mismatching translation.",
      +                "type": "string"
      +              },
      +              "kind": {
      +                "description": "What failed: a placeholder set mismatch (the default) or a vue-i18n plural variant-count mismatch.",
      +                "enum": [
      +                  "placeholder",
      +                  "plural-count"
      +                ],
      +                "type": "string"
      +              },
      +              "locale": {
      +                "description": "Locale code the mismatch was found in.",
      +                "type": "string"
      +              },
      +              "missing": {
      +                "description": "Placeholders the source has and the translation dropped.",
      +                "items": {
      +                  "type": "string"
      +                },
      +                "type": "array"
      +              },
      +              "sourceVariants": {
      +                "description": "Plural variants in the source value. Present only for kind \"plural-count\".",
      +                "maximum": 9007199254740991,
      +                "minimum": -9007199254740991,
      +                "type": "integer"
      +              },
      +              "targetVariants": {
      +                "description": "Plural variants in the translated value. Present only for kind \"plural-count\".",
      +                "maximum": 9007199254740991,
      +                "minimum": -9007199254740991,
      +                "type": "integer"
      +              }
      +            },
      +            "required": [
      +              "locale",
      +              "key",
      +              "missing",
      +              "extra"
      +            ],
      +            "type": "object"
      +          },
      +          "type": "array"
      +        },
      +        "ok": {
      +          "description": "True when every checked translation carries the same placeholders as its source.",
      +          "type": "boolean"
      +        },
      +        "placeholders": {
      +          "description": "Placeholder names found in the source values, e.g. [\"{name}\"].",
      +          "items": {
      +            "type": "string"
      +          },
      +          "type": "array"
      +        }
      +      },
      +      "required": [
      +        "ok",
      +        "placeholders",
      +        "errors"
      +      ],
      +      "type": "object"
      +    },
      +    "skipped": {
      +      "description": "Keys the write mode left alone — existing keys under mode \"add\", missing ones under mode \"update\".",
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    "skippedKeys": {
      +      "description": "The keys behind keysSkipped, when the mode skipped any. Absent when nothing was skipped.",
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    "summary": {
      +      "additionalProperties": false,
      +      "description": "Counts of what the run did. Absent on a dry run.",
      +      "properties": {
      +        "keysSkipped": {
      +          "description": "Number of keys the write mode left alone.",
      +          "maximum": 9007199254740991,
      +          "minimum": -9007199254740991,
      +          "type": "integer"
      +        },
      +        "keysWritten": {
      +          "description": "Number of keys written across every locale.",
      +          "maximum": 9007199254740991,
      +          "minimum": -9007199254740991,
      +          "type": "integer"
      +        },
      +        "message": {
      +          "description": "One sentence stating what the run did.",
      +          "type": "string"
      +        }
      +      },
      +      "required": [
      +        "keysWritten",
      +        "keysSkipped",
      +        "message"
      +      ],
      +      "type": "object"
      +    },
      +    "unresolvedLocales": {
      +      "description": "Locale refs that matched no known locale; their values were dropped while other locales were still written. Absent when every ref resolved.",
      +      "items": {
      +        "additionalProperties": false,
      +        "properties": {
      +          "keys": {
      +            "description": "Dot-path keys whose value for this ref was dropped.",
      +            "items": {
      +              "type": "string"
      +            },
      +            "type": "array"
      +          },
      +          "ref": {
      +            "description": "The locale ref that matched no known locale. Nothing was written for it.",
      +            "type": "string"
      +          },
      +          "suggestion": {
      +            "description": "\"Did you mean …?\", when a near match exists.",
      +            "type": "string"
      +          }
      +        },
      +        "required": [
      +          "ref",
      +          "keys"
      +        ],
      +        "type": "object"
      +      },
      +      "type": "array"
      +    },
      +    "warnings": {
      +      "description": "Non-fatal problems, e.g. a value written over a nested object. Absent when there are none.",
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    "wouldWrite": {
      +      "description": "The writes a dry run would make. Present only with dryRun.",
      +      "items": {
      +        "additionalProperties": false,
      +        "properties": {
      +          "key": {
      +            "description": "Dot-path key that would be written.",
      +            "type": "string"
      +          },
      +          "locale": {
      +            "description": "Locale code the value would be written to.",
      +            "type": "string"
      +          },
      +          "value": {
      +            "description": "The value that would be written.",
      +            "type": "string"
      +          }
      +        },
      +        "required": [
      +          "locale",
      +          "key",
      +          "value"
      +        ],
      +        "type": "object"
      +      },
      +      "type": "array"
      +    },
      +    "written": {
      +      "description": "Dot-path keys that were written. Absent on a dry run.",
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    }
      +  },
      +  "required": [
      +    "skipped"
      +  ],
      +  "type": "object"
      +}
  2. Changed2 schema fields changedv1.0.3
    • changedInput schema / $schema
      Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • changedInput schema / properties / projectDir / description
      Previous value: -"Absolute path to the Nuxt project root. Defaults to server cwd. Example: \"/home/user/my-app\"."New value: +"Absolute path to the Nuxt project root. Defaults to I18N_PROJECT_DIR, then server cwd. Example: \"/home/user/my-app\"."
  3. First observedv1.0.0

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true, idempotentHint=true and readOnlyHint=false, so the write profile is partly covered. The description adds real behavioral value beyond that: keys are inserted in alphabetical order, upsert 'never fails', add/update skip disjoint key sets, and dryRun previews without touching files. It stops short of stating that existing values are overwritten by upsert, which is the key destructive consequence.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The leading sentence front-loads the action and the alphabetical-ordering constraint, and each following sentence covers one mode or dryRun with no filler. Mild redundancy exists because the three mode sentences duplicate the enum descriptions in the schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return values need not be explained, and the annotations carry the safety profile. The description covers modes, ordering, and dryRun adequately for a 5-parameter mutation tool, though it omits what upsert does to pre-existing values and any scope/permission constraints on the layer.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the enum values, defaults, and the locale-map value shape are already fully documented in the schema. The description largely restates the mode semantics and confirms upsert as the default; it adds no format or syntax detail beyond the structured fields. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Write translation key-value pairs to a layer') and immediately describes the operation's semantics. It is distinguishable from remove_translations by contrast, though it never names a sibling explicitly. Clear but lacks direct sibling differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The mode semantics amount to strong in-tool guidance (upsert is flagged as default and 'most common', add/update are described with their skip behavior) and dryRun is recommended for previewing. However, there is no guidance on when to choose this tool over siblings such as translate_missing, translate_key, or scaffold_locale, which also create translations. Usage is implied rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.