# Translation document contract

<!-- rule: translate.output.json-only class=hard enforced=no tasks=translation -->
- Read and write UTF-8 JSON without Markdown fences or explanatory output. <!-- rule: translate.locale.filename class=hard enforced=no tasks=translation title="The translation document's `Locale` matches the locale tag in its output filename" -->
- Set `Locale` to the locale tag used in the output filename. <!-- rule: translate.locale.syntax class=hard enforced=yes tasks=translation title="Locale tags are 1–128 ASCII alphanumerics in segments separated by one `-` or `_`" -->
- Locale tags are 1–128 ASCII alphanumeric characters grouped into segments
  separated by one `-` or `_`; leading, trailing, or repeated separators are
  invalid. <!-- rule: translate.structure.preserve class=hard enforced=no tasks=translation -->
- Preserve `DocumentVersion`, object structure, arrays, ordering, numeric values,
  and structural identifiers. <!-- rule: translate.keys.untranslated class=hard enforced=no tasks=translation -->
- Do not translate structural keys, native type/function names, string-resource
  keys, or schema IDs. <!-- rule: translate.values.scope class=hard enforced=no tasks=translation -->
- Translate package, function, and type `DisplayName` and `Description`; the
  `Name` and `Description` of every field, List container and item,
  Enumeration member, Union variant, and inline field; package
  `StringResources` values; and custom document-property string values. This
  includes `[DefaultText]` on fields and
  functions, Boolean `[TrueText]`/`[FalseText]`, and nullable-field `[NullText]`
  and `[SetText]`.
  Preserve their keys and translate their values as non-empty single lines.
- Apply the [user-language invariant](documentation.md#universal-user-language-invariant)
  to translated prose: use natural, idiomatic, technology-neutral wording while
  preserving every material meaning. <!-- rule: translate.description.paragraphs class=hard enforced=no tasks=translation -->
- Input `Description` values already have canonical HTML-style flow: source
  wrapping has become spaces, and paragraph boundaries are single LF characters.
  Preserve those paragraph boundaries in the translation and keep each paragraph
  flowing without line wrapping. Do not apply source-line normalization again
  to exported descriptions. This rule does not apply to custom-property or
  `StringResources` values. <!-- rule: translate.empty.preserve class=hard enforced=no tasks=translation -->
- Preserve intentionally empty localized strings. <!-- rule: translate.lmf1.preserve class=hard enforced=no tasks=translation -->
- Package `StringResources` values use Libertas Message Format 1 (LMF1), based on ICU
  MessageFormat 1 with Libertas types. Argument identifiers are zero-based
  positions, never printf placeholders or names. Preserve every position, type,
  style, selector key, plural offset, brace, and apostrophe escape exactly,
  including `LibertasDevice` and the Enumeration type-name style of
  `LibertasEnum`. Translate only literal message text, including literal text
  inside variants. <!-- rule: translate.nodes.unchanged class=hard enforced=no tasks=translation -->
- Do not add, remove, reorder, or duplicate schema nodes.

## Migration guarantees

<!-- rule: translate.migration.signature-match class=hard enforced=no tasks=translation -->
When both signatures are known, functions match by stable native name and types
with the same native name are disambiguated by namespace identity. Fields and
enum entries match by their complete native declaration path. New localized values
receive default-locale text with an explicit review warning; obsolete entries
are removed; translated custom attributes and string resources are retained;
and regenerated numeric IDs are installed.

<!-- rule: translate.migration.shape-fallback class=hard enforced=no tasks=translation -->
When an old signature is unavailable, Studio preserves field-level translation
only if the complete numeric shape is identical. If the shape changed, it copies
the new default fields instead of risking a translation being attached to the
wrong field.


For workspace preparation, locale selection, import, and removal, follow the
[translation guide](../guides/translation.md).
