testfx-localization-validation

$npx mdskill add microsoft/testfx/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:

SKILL.md

.github/skills/testfx-localization-validationView on GitHub ↗
---
name: testfx-localization-validation
description: Validate generated TestFx localization catalogs, resource IDs, placeholders and locked tokens. Use for RESX/XLF changes, OneLoc PRs, localization build failures, duplicate targets or units, and orphaned translation entries.
---

# 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:

```powershell
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](https://docs.oasis-open.org/xliff/v1.2/os/xliff-core-1.2-transitional.xsd)
  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](https://github.com/dotnet/xliff-tasks/blob/main/src/Microsoft.DotNet.XliffTasks/Model/ResxDocument.cs):
  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:

```powershell
.\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.

More from microsoft/testfx

SkillDescription
assertion-qualityAnalyze assertion quality, depth, variety, and false confidence in existing tests. ALWAYS USE when asked about weak, shallow, trivial, always-true, self-referential, assertion-free, presence/truthiness-only, or insufficiently diverse assertions, including MSTest, Jest, pytest, and Go. DO NOT USE for direct fixes: writing-mstest-tests owns supplied MSTest assertions; code-testing owns new cases. Use test-gap-analysis when asked whether tests would catch a production change, and test-anti-patterns for general severity-ranked audits.
behavior-preserving-refactorPreserve observable behavior when splitting files, moving members, consolidating helpers, or simplifying TestFx code. Use for structural refactors and file-diet implementation; inventory baseline semantics and consumers, then run focused equivalence checks.
binlog-failure-analysisDiagnose existing MSBuild .binlog failures with MCP/replay; not log capture or non-MSBuild failures.
binlog-generationCapture and verify unique MSBuild binlogs, quoting '-bl:{}' in PowerShell; not analysis of existing logs.
build-parallelismAnalyze an MSBuild solution, solution filter, or Build.proj that schedules multiple project files. USE FOR: measured idle worker nodes, `-m` that does not scale, a serial ProjectReference critical path, graph builds, or an MSBuild task that builds a Projects list. Requires at least two distinct project files whose scheduling or throughput must be analyzed. DO NOT USE for non-MSBuild build systems.
build-perf-baselineMeasure repeatable cold/changed-input/no-op MSBuild baselines for caching, output layout and graph tuning; not task diagnosis or non-MSBuild builds.
build-perf-diagnosticsDiagnose MSBuild target/task/analyzer bottlenecks from binlogs after baselining; not baseline setup, incremental correctness or parallelism tuning.
check-bin-obj-clashDetects MSBuild projects with conflicting OutputPath or IntermediateOutputPath. USE FOR: builds failing with 'Cannot create a file when that file already exists', 'The process cannot access the file because it is being used by another process', intermittent build failures that succeed on retry, or missing/overwritten outputs in multi-project or multi-targeting builds where bin/obj (or project.assets.json) collide. Common causes: shared OutputPath, missing AppendTargetFrameworkToOutputPath, extra global properties (e.g. PublishReadyToRun), or SetTargetFramework on a ProjectReference to a single-targeting project. DO NOT USE FOR: file access errors unrelated to MSBuild (OS-level locking), single-project single-TFM builds, non-MSBuild build systems.
code-testing>-
code-testing-agent>-