Skip to content

Localization Health Scanner

A scanner over the surfaces it can see — a clean report is not proof of complete coverage.

The Localization Health Scanner is an editor-only diagnostic tool that inspects localization tables (CSVs), configuration ScriptableObjects, and localized asset references for syntax errors, missing translations, placeholder mismatches, plural-category gaps, and cyclic fallbacks.

Features

  • Structural table validation: Detects duplicate keys, malformed rows, empty tables, and missing translation cells (absorbing and expanding upon LocValidator).
  • Placeholder mismatch analysis: Validates named tokens ({score}) and indexed tokens ({0}/{1}) across all translation columns against reference templates to ensure runtime substitutions will not fail.
  • Plural category gap analysis: Probes PluralRules directly across integer counts to detect missing CLDR plural categories (e.g. Slavic [few] or [many]) and identifies unused plural definitions.
  • Configuration & fallback verification: Detects cyclic fallback chains (e.g. French -> CanadianFrench -> French), unsupported fallback targets, and mismatches between supportedLanguages and CSV table columns.
  • Deterministic reports: Generates byte-identical JSON and Markdown reports across runs for auditability and CI workflows.
  • Interactive Editor Window: Grouped findings by table, severity filters, count summaries, and click-to-navigate asset pings.

Finding Codes

ID Severity Category Description & Runtime Consequence
LOC001_DUPLICATE_KEY Error Table Duplicate key in table. At runtime the table is loaded into a dictionary, so the last occurrence silently overwrites the earlier ones.
LOC002_MALFORMED_ROW Error Table Row has mismatched column count or an empty key with translation values.
LOC003_MISSING_CELL Warning Table A language column is empty or whitespace-only for a given key.
LOC004_NO_LANGUAGE_COLUMNS Error Table CSV header contains no language columns.
LOC005_EMPTY_TABLE Warning Table Table contains no data rows.
LOC010_PLACEHOLDER_MISSING Warning Placeholder Named placeholder in reference template is missing in translation (token will never be substituted).
LOC011_PLACEHOLDER_EXTRA Warning Placeholder Extra named placeholder in translation that is not present in reference template (renders as literal text).
LOC012_PLACEHOLDER_ARITY Warning Placeholder Indexed placeholder set differs from reference language (e.g. {0}/{1} vs {0}).
LOC020_PLURAL_CATEGORY_MISSING Warning Plural Language requires a CLDR category variant (KEY[few], KEY[many], etc.) that is missing in the table.
LOC021_PLURAL_CATEGORY_UNUSED Info Plural Table defines a plural variant whose category that language never produces at runtime.
LOC030_FALLBACK_CYCLE Error Config Cyclic fallback loop detected in LocalizationConfig.languageFallbacks.
LOC031_FALLBACK_TO_UNSUPPORTED Warning Config Fallback target language is not listed in supportedLanguages.
LOC032_SUPPORTED_LANGUAGE_NO_COLUMN Warning Config Supported language has no column in a scanned table.
LOC033_TABLE_COLUMN_UNSUPPORTED Info Config Table column language is not declared in supportedLanguages.
LOC034_INVALID_LANGUAGE_HEADER Warning Config A table column header is not a recognized SystemLanguage name (usually a typo). Plural analysis skips that column entirely.
LOC035_DEFAULT_LANGUAGE_NOT_SUPPORTED Warning Config defaultLanguage is not listed in supportedLanguages, so the configured fallback language is one the service is not set up to load.
LOC036_EMPTY_SUPPORTED_LANGUAGES Warning Config supportedLanguages is empty — the scanner cannot cross-check table columns against the config, so LOC032/LOC033 are suppressed for it.
LOC040_LOCALIZED_ASSET_MISSING Warning Asset Ref Localized asset not found at Resources path convention (note: edit-time probing is not authoritative for Addressables).

Scope and Limitations

The banner at the top of this page is not boilerplate — the scanner reports on the surfaces it can reach, and a clean report is not proof that your localization is complete. Specifically:

  • Table discovery is by convention. A project scan collects .csv assets under Assets/ whose path contains /Localization/ or whose filename contains StringTable. A table stored outside that convention is never scanned; an unrelated CSV that happens to match it is scanned, and will produce structural findings.
  • Config cross-checks are scoped by ownership. A table belongs to a LocalizationConfig when it sits under .../Resources/<localizationTablesPath>/. Tables outside every config's path still get structural, placeholder, and plural analysis, but no config cross-checks (LOC030-LOC036), and their placeholder reference column is the table's first language column rather than a configured defaultLanguage.
  • LOC040 is evaluated against every config. Localized asset references found on LocalizedImage / LocalizedAudio components are checked against each LocalizationConfig's language set and localizationTablesPath. Findings are deduplicated across configs by expected path, key, and type: two configs sharing a tables path report a missing asset once, while two configs with different tables paths each report it - those are genuinely different expected locations. With no LocalizationConfig asset in the project, LOC040 is not evaluated at all.
  • Resources probing is edit-time only. An asset served through Addressables at runtime will look missing here. Treat LOC040 as a prompt to check, not a verdict.
  • Runtime-composed keys are invisible. Keys built at runtime ("item_" + id) cannot be seen by a static scan; only literal keys on components and rows in tables are covered.

Using the Scanner Window

Open Tools ▸ OxHeart ▸ Localization ▸ Localization Health Scanner:

  1. Click Run Health Scan to scan all CSV tables and LocalizationConfig assets in the project.
  2. Filter findings using the search bar or severity dropdown (All, Errors & Warnings, Errors Only, Warnings Only, Info Only).
  3. Expand table sections to inspect findings with line numbers and column locations.
  4. Click Ping to highlight the source CSV or Config asset in the Project window.
  5. Export reports via Export JSON... or Export Markdown....

CI & Build Script Integration

LocValidator delegates directly to the health scanner core:

  • Run via menu: Tools ▸ OxHeart ▸ Localization ▸ Validate Localization Tables
  • Call via code: LocValidator.ValidateAll() or LocValidator.ValidateFile(assetPath)
  • Programmatic headless scan:
    var report = OxHeart.Editor.Localization.Health.LocHealthScanner.ScanProject();
    if (!report.IsClean)
    {
        string json = OxHeart.Editor.Localization.Health.LocHealthReportWriter.ToJson(report);
        // Process or write report
    }