Build TM from existing translations¶
中文 | English
Why an unknown structure cannot be guessed safely¶
For arbitrary files, the framework cannot reliably infer the stable key, source field, translation field, or whether a coordinate should remain identical after files move. A wrong guess is worse than a missed import because a translation can be attached to another key and reused in later releases.
There are two ingestion paths:
- A configured adapter already supports the structure: inspect and import the translated resources directly.
- The structure is unknown or unsupported: explicitly map it to neutral TM Seed JSON first.
Both commands are dry-run by default. Only --apply --accepted-by <operator> writes validated translations as reviewed + formal + human rows.
Path 1: bootstrap supported resources directly¶
Supported cases¶
| Structure | Existing translation can be read when |
|---|---|
| Gettext PO/MO | layout: standard; msgid is source and msgstr is translation |
| ParaTranz JSON | Each item contains the configured key/source/translation fields |
| Paradox YAML | Source- and target-locale files coexist according to adapter directory rules |
Gettext keyed_source treats msgstr as source text and contains no target translation by itself, so it cannot bootstrap from that file alone.
1. Configure the resource¶
Example for standard PO:
paths:
source: ./existing-localization
resources:
adapters:
- type: gettext
include: ["**/*.po"]
options:
layout: standard
empty_source: skip
source_filter: all
2. Scan and dry-run¶
localizer validate-config projects/my-project/project.yaml
localizer scan projects/my-project/project.yaml
localizer tm-bootstrap-resources projects/my-project/project.yaml
The last command does not write TM. Its report is:
<workspace>/reports/tm-bootstrap-resources.json
Key fields:
total: every unit extracted by adapters;accepted: non-empty translations that passed placeholder, language-rule, and glossary checks;rejected: input coordinates with at least one blocking issue;issue_counts/issues: grouped and coordinate-level details.
If rejected is nonzero, apply refuses the whole batch instead of leaving a partial, hard-to-explain baseline.
3. Attest and write¶
localizer tm-bootstrap-resources projects/my-project/project.yaml `
--apply `
--accepted-by localization-owner
An existing database is first copied with the SQLite backup API into a sibling backups directory. A new project gets a new database and schema. The report records operator, backup, and final counts.
For source variants:
localizer tm-bootstrap-resources projects/my-project/project.yaml `
--variant stable `
--apply `
--accepted-by localization-owner
Path 2: convert an unknown structure to TM Seed¶
Coordinate semantics¶
Every record must map these fields:
| Field | Meaning | Requirement |
|---|---|---|
adapter_id |
Adapter that will read the real resource | Must equal a configured resources.adapters[].type |
relative_path |
Resource path relative to paths.source |
Must match adapter scan output; use / separators |
logical_key |
Stable key within the file | Must match what the adapter extracts |
source_text |
Original source-language text | Used to compute the source fingerprint |
translation |
Existing target-language translation | Must be non-empty and passes QA |
project_id and locales come only from project.yaml; a Seed cannot override them.
If the old structure has no stable key, generate a deterministic key from a business ID. Do not use an order-dependent array index unless the production adapter will use exactly the same index forever.
Single-file example¶
Use top-level defaults when all entries belong to one adapter/path:
{
"schema_version": 1,
"defaults": {
"adapter_id": "paratranz_json",
"relative_path": "ui/menu.json"
},
"entries": [
{
"logical_key": "menu.start",
"source_text": "Start Game",
"translation": "开始游戏",
"context": "main menu button"
},
{
"logical_key": "menu.exit",
"source_text": "Exit",
"translation": "退出"
}
]
}
Copy ../examples/tm-seed-single.json.
One Seed containing several resource files¶
Omit defaults and put full coordinates on each entry:
{
"schema_version": 1,
"entries": [
{
"adapter_id": "gettext",
"relative_path": "ui/menu.po",
"logical_key": "Start Game",
"source_text": "Start Game",
"translation": "开始游戏"
},
{
"adapter_id": "gettext",
"relative_path": "items/names.po",
"logical_key": "Mana Potion",
"source_text": "Mana Potion",
"translation": "法力药水"
}
]
}
Multiple Seed files in one import¶
Large projects should generate one Seed per original resource:
tm-seed/
├── ui-menu.json
└── item-names.json
Pass all files to one command:
localizer tm-import-seed projects/my-project/project.yaml `
docs/examples/tm-seed-multi/ui-menu.json `
docs/examples/tm-seed-multi/item-names.json
Copy the shared examples/tm-seed-multi examples. Inputs are merged before validation. A repeated adapter_id + relative_path + logical_key, including across files, produces duplicate_coordinate.
Dry-run and apply¶
localizer tm-import-seed projects/my-project/project.yaml path/to/seed.json
Default report:
<workspace>/reports/tm-seed-import.json
After review:
localizer tm-import-seed projects/my-project/project.yaml path/to/seed.json `
--apply `
--accepted-by localization-owner
--report and --backup select explicit locations. When a database exists, the backup destination must not already exist.
Mapping an unknown structure¶
Answer five questions before writing a read-only converter:
- What defines one translation record?
- Which field or combination identifies it permanently?
- Where are source and translation stored?
- Which adapter will read the production resource?
- What
relative_pathandlogical_keywill that adapter produce?
Map those answers to Seed. The converter must not edit input files and should report input count, output count, and skip reasons. Validate a small sample before converting everything.
If questions 4 and 5 cannot be answered, the missing component is a production resource adapter, not merely an import format. Implement the adapter first; otherwise imported coordinates will never match future builds.
Verify after import¶
localizer build projects/my-project/project.yaml --mode preview --run-id tm-check
Check that tm_hits is close to the number of valid imported coordinates, machine_successes covers only new/changed source, QA shows no coordinate mismatch, and sampled path/key/source triples match the original resources. Row count alone does not prove a useful TM; production adapter coordinates and source fingerprints must match.