SuperAPI AI Directory

testfx-localization-validation

General & other

View repository

Updated 10-16 06:48

About this skill

TestFx localization validation

Run from the repository root with Python 3.12 or newer; no third-party packages or .NET build are needed for the guard:

python .github\scripts\test_check_localization.py
python .github\scripts\check_localization.py

On Linux/macOS use / in command paths. The standalone check-localization.yml workflow runs the same commands on localization PRs. The guard is read-only. Exit codes are 0 for clean, 1 for catalog findings, and 2 for invocation/discovery errors (including no catalogs).

Runtime choice

Python is a measured exception to the preference for PowerShell when there is no performance, feature or security impact. On Windows with Python 3.12.10 and PowerShell 7.6.6, nine interleaved warm-cache runs (including process startup) gave these medians:

Workload Complete Python guard PowerShell feasibility probe
All 364 catalogs / 19,695 units 1.830 s 3.686 s
Clean 13-locale fixture 0.272 s 0.825 s
Empty runtime startup 0.063 s 0.468 s

The dependency-free probe used .NET XML readers, cached neutral resources and ordinal IDs. It implemented only a subset of validation, not feature parity; it already exceeded the complete guard's runtime. Python is retained rather than accepting that regression or weakening the checks. These measurements are not a claim about every possible PowerShell implementation or other operating systems. A future port must demonstrate no performance regression and pass the committed regression suite, including case-sensitive IDs/tokens and literal/escaped placeholder semantics. Explicit .NET XML-reader security settings and DTD handling were independently exercised in the feasibility probe, not by the Python regression suite. A port must separately verify those settings and compare accepted XML-input profiles; passing the suite alone does not prove XML security parity.

Rules and limits

  • TestFx uses XLIFF 1.2 with the OASIS namespace and a relative file original pointing to the neutral RESX. Resolve it relative to the catalog, not the project or repository. Do not confuse locale cs (Czech) with a C# file.
  • The XLIFF 1.2 transitional schema requires one direct source and permits zero or one direct target per trans-unit. Do not require a target to exist. Targets inside alt-trans are alternatives, not duplicates. Groups are legal. Unit IDs are unique within a file across trans-unit and bin-unit, not globally across files.
  • Generated units must correspond to neutral string resource IDs, and their source text must match the neutral value exactly. When the neutral comment is nonempty, a note must match it exactly. Match XliffTasks' RESX exclusions: typed/binary entries, designer names (>>..., *.LayoutSettings), whole-value {Locked} comments, and empty/whitespace values do not require units. Additional notes are legal. An absent target or empty unfinished target is allowed; unfinished translations are not evidence of a structural defect.
  • Numeric composite-format argument indices must be preserved; reordering, repetition, alignment and format specifier changes are not automatically translation defects. Escaped braces are supported. Named templates such as {tfm} and literal JSON are not assumed to be .NET composite formats. When source text is not unambiguously a composite format, manually check any embedded numeric placeholders. This is not a complete String.Format parser.
  • Every {Locked="..."} token must occur verbatim in the neutral value and in a nonempty/completed target. Matching is case-sensitive and substring-based. The guard checks presence, not grammar or a word's translatability. Manually check for collisions with other words in the same value: const also matches constant. Prefer the longest unambiguous invariant token. Lock punctuation only when invariant or necessary to disambiguate.
  • This is a focused guard, not a full XSD validator or translation-quality review. Inline XLIFF codes require producer-specific rendering and are reported for manual handling instead of silently flattened. Do not invent new bans on otherwise legal XLIFF solely to make the checker pass.

Diagnose and repair at the authoritative source

Catalog-derived findings are grouped by neutral file, resource ID and defect, with every affected catalog path listed. Findings about the neutral RESX itself (XML/root/ID/value/locked-source errors) are emitted once for that file without listing its referencing catalogs. Treat one bad resource copied across 13 locales as one root cause, not 13 independent review requests.

The default command audits the entire current checkout, including tracked and non-ignored new catalogs. A finding is not automatically introduced by the PR. Compare the same check on the PR base before attributing older drift to the author. Do not silently repair old entries, suppress failures with a broad allowlist, or assume removing an orphan from one locale repairs all catalogs. The initial repository baseline was clean; no grandfathered ID list is needed.

For developer-owned values, IDs or comments, edit the neutral RESX only. Regenerate with the owning project's UpdateXlf target, using the pinned repository SDK initialized by the build scripts. For example, on Windows:

.\build.cmd
.\.dotnet\dotnet.exe msbuild src\Platform\Microsoft.Testing.Platform\Microsoft.Testing.Platform.csproj /t:UpdateXlf -bl:artifacts\log\localization-update.binlog
python .github\scripts\check_localization.py

Use the corresponding project for adapter, framework, analyzer or extension resources. If DOTNET_INSTALL_DIR supplies the repo's pinned SDK, use that dotnet instead. Regeneration is authoritative for source text, IDs and notes; it does not prove that a translation is linguistically correct. Inspect the generated diff and run the affected project's normal build when assessing a localization build failure.

Never hand-edit generated XLF. For duplicate targets, bad translations, translated placeholders or locked tokens in a OneLoc submission, route the grouped diagnostics to the OneLoc producer/maintainers and request a corrected generated submission. Regenerate developer-owned source metadata as appropriate; do not fabricate translated text or assume UpdateXlf repairs upstream translation quality. Re-run the guard on the corrected output.