Toolingcom.zoa.localization.authoring · v0.1.0

ZOA Localization Authoring

The optional Workbench surfaces for localization production: table wizard, key browser, coverage report, and source extraction review.

This package exists to be left out. A game that needs localized text installs com.zoa.localization and nothing else: runtime service, table assets, UI Toolkit bindings, exchange codecs, validation, and the extraction and inventory APIs all live there. This package adds only the producer-facing Workbench module on top, and it is the only half that depends on Workbench.

Tests enforce the split. The base package's asmdef and manifest are asserted to contain no reference to Workbench, and the base package is asserted to have no Editor/Workbench directory at all. A matching test on this side asserts that both authoring surfaces sit in the ZOA.Localization.Authoring.Editor.Workbench namespace.

Installing it adds no capability. It adds a place to do the work: the module wraps APIs that already exist in the base package, giving them a browsable, searchable home inside the Workbench alongside every other Foundry authoring surface.

Depended on by (0)

Nothing yet. This is a leaf.

How it works

Concepts

An optional layer over an owned API

Everything this package renders is computed by the base package. The string browser and coverage report are views over LocalizationKeyInventoryBuilder.BuildFromProject. The source extraction panel is a button over LocalizationHardcodedStringExtractor. The table wizard emits through LocalizationTableAssetEmitter.

The reusable logic stays where a game can call it from a build step or a CI job, and only the presentation lives here. Uninstalling this package removes UI, never functionality.

The inventory is the shared data source

LocalizationKeyInventoryBuilder walks every LocalizationTableAsset in the project and produces one row per key and locale, carrying the value, the table name, the asset path, the translator context and notes, the screenshot path, the character limit, and the review status, plus placeholder and duplicate flags.

Both the string browser and the coverage report read that same inventory. The browser lists the rows with duplicates and placeholders flagged inline and filters them by key, locale, value, or table name. The report asks the inventory for Coverage and MissingRows against English as the reference locale and prints a line per locale with coverage, missing count, placeholder count, and duplicate count.

Because the source is the asset files rather than a running service, both work in the editor without entering play mode and without any scene being installed.

The table wizard is a guided draft

LocalizationTableWizard runs on FoundryWizardShell with a step rail and an issue tray, in three steps: Locale Selection, Import Keys, and Review. Locale Selection takes a BCP 47 code with buttons for five common locales, and rejects an unparseable code by reverting the field rather than throwing.

Import Keys either loads a named template or accepts keys typed one at a time into a growing list. Review shows the locale, the key count, the template in use, and the key list before anything is written.

Completing the wizard captures a LocalizationTableDraft and hands it to LocalizationTableAssetEmitter, which writes a LocalizationTableAsset under Assets/ZOA/Generated/Localization. Each step has a validator, so a missing locale or an empty key set surfaces in the issue tray rather than producing a broken asset.

Extraction review is a scan you can act on

The source extraction capability walks every C# and UXML file under Assets and runs LocalizationHardcodedStringExtractor over them, reporting the candidate count and listing the first twenty with their proposed key, the literal text, and the file and line where it was found.

Suppression is a comment token. Writing ZOA_LOCALIZATION_IGNORE next to an intentional literal takes it out of the scan, which keeps the report on strings that need a key instead of on debug logs and asset paths.

In the editor

Screens

Screenshot pending

/screenshots/localization-authoring-coverage-report.png

The Workbench with the Localization module selected and Coverage Report active, showing the reference locale and key and locale totals at the top, then several per-locale lines with coverage percentages, missing counts, placeholder counts, and duplicate counts.

The Coverage Report capability inside the Workbench.

Screenshot pending

/screenshots/localization-authoring-table-wizard.png

The wizard embedded in the Workbench with the three-step rail visible, the Use Template toggle on with a template name field, the growing key list below it, and the New Key field with its Add button at the bottom.

The Localization Table Wizard on its Import Keys step.

Screenshot pending

/screenshots/localization-authoring-string-browser.png

The String Browser capability with a search term entered, the filtered list showing rows in the locale, key, table, value format, and at least one row carrying a DUPLICATE flag and one carrying PLACEHOLDER.

The String Browser with duplicates and placeholders flagged.

Setup

Workflow

  1. 01

    Decide whether you need it at all

    A game that only ships localized text does not. Install com.zoa.localization alone and drive extraction, inventory, validation, and emission from your own build steps. Install this package when people are doing localization production inside the editor and want a home for it.

  2. 02

    Open the module

    The Localization module appears in the Workbench under the workflow.environment lane at order 51, with five capabilities across the strip: Localization Tables, String Browser, Coverage Report, Source Extraction, and Overview.

  3. 03

    Create a table with the wizard

    Pick or type a BCP 47 locale code, choose a template or add keys one by one, review the summary, and finish. The asset lands under Assets/ZOA/Generated/Localization; from there it is an ordinary LocalizationTableAsset that the base package's scene installer can register.

  4. 04

    Read coverage before committing to a locale

    The Coverage Report scans every table asset in the project and prints coverage, missing count, placeholder count, and duplicate count per locale against English. Duplicates are as important as gaps: a duplicated key is a composition conflict waiting to happen at runtime.

  5. 05

    Sweep for hardcoded strings

    Run Source Extraction over Assets and work down the candidate list. Give a real string a key and a table row; mark an intentional literal with ZOA_LOCALIZATION_IGNORE so it stops appearing.

  6. 06

    Gate the build from the base package

    Build gating stays in com.zoa.localization. Call LocalizationValidator.ValidateBuildReadiness from a build step so the gate runs on a machine that never installed the authoring package.

Surface

Key types

LocalizationWorkbenchModule

class

The Workbench module itself, registered as "localization" in the workflow.environment lane. Builds a capability strip over table definitions, the string browser, the coverage report, source extraction, and an architecture overview.

  • string Id => "localization"
  • string Title => "Localization"
  • string Subtitle => "Manage translations, preview localized content, and validate coverage"
  • int Order => 51
  • VisualElement Build(ZOAWorkbenchContext context)

LocalizationTableWizard

component

The three-step guided table creator. Each step carries a validator feeding the issue tray, and completion emits a LocalizationTableAsset from the captured draft.

  • static void ShowWindow()
  • LocalizationTableDraft CaptureDraft()

LocalizationKeyInventoryBuilder

class

Owned by the base package and consumed here. Builds the project-wide inventory that both the string browser and the coverage report render.

  • static LocalizationKeyInventory BuildFromProject()
  • static LocalizationKeyInventory BuildFromAssets(IEnumerable<LocalizationTableAsset> assets)

LocalizationKeyInventory

class

The inventory the Workbench views read: every row, the distinct locales and keys, and the two questions the coverage report asks per locale.

  • IReadOnlyList<LocalizationKeyInventoryRow> Rows { get; }
  • IReadOnlyList<LocaleId> Locales { get; } IReadOnlyList<LocalizationKey> Keys { get; }
  • IReadOnlyList<LocalizationKeyInventoryRow> MissingRows(LocaleId referenceLocale, LocaleId targetLocale)
  • float Coverage(LocaleId referenceLocale, LocaleId targetLocale)

LocalizationKeyInventoryRow

class

One key in one locale, with everything the browser and report need: the value, its table and asset path, the translator metadata, the review status, and the placeholder and duplicate flags.

  • LocalizationKey Key { get; } LocaleId Locale { get; } string Value { get; }
  • string TableName { get; } string AssetPath { get; }
  • LocalizationReviewStatus ReviewStatus { get; }
  • bool IsPlaceholder { get; } bool IsDuplicate { get; }

LocalizationHardcodedStringExtractor

class

The scanner behind the source extraction capability, owned by the base package. Returns candidates with a proposed key, the literal, and the file and line; a ZOA_LOCALIZATION_IGNORE token suppresses a literal.

  • LocalizationExtractionReport ExtractFromFiles(IEnumerable<string> paths)

LocalizationExtractionCandidate

class

One extraction finding: the proposed key, the source text, the file path and line, a context string, and the name of the detector that matched.

  • LocalizationKey Key { get; } string SourceText { get; }
  • string SourcePath { get; } int Line { get; }
  • string Context { get; } string Detector { get; }

LocalizationTableAssetEmitter

class

Writes the wizard's draft to disk, defaulting to Assets/ZOA/Generated/Localization. Also the path an imported translator document takes back into the project.

  • const string DefaultSaveFolder = "Assets/ZOA/Generated/Localization"
  • static LocalizationTableAsset EmitFromDraft(LocalizationTableDraft draft, string savePath)
  • static LocalizationTableAsset EmitFromDocument(...)

LocalizationTableDraft

class

The in-flight shape the wizard captures before emission: a locale code, a table name, and the draft entries with their values and metadata.

  • string LocaleCode; string TableName;
  • List<LocalizationTableDraftEntry> Entries;
  • static LocalizationTableDraft FromPairs(...)

Usage

Examples

Running the same coverage analysis without the Workbenchcsharp
using ZOA.Localization.Core;
using ZOA.Localization.Unity.Editor.Inventory;

// This is exactly what the Coverage Report capability renders.
var inventory = LocalizationKeyInventoryBuilder.BuildFromProject();
var reference = DefaultLocales.English;

foreach (var locale in inventory.Locales)
{
    float coverage = inventory.Coverage(reference, locale);
    int missing = inventory.MissingRows(reference, locale).Count;

    UnityEngine.Debug.Log(locale.Value + ": " + coverage + "% coverage, " + missing + " missing");
}
The builder and the inventory live in com.zoa.localization, so a CI job gets the same numbers without this package installed.
Scanning for hardcoded strings from a scriptcsharp
using System.IO;
using System.Linq;
using ZOA.Localization.Unity.Editor.Extraction;

var paths = Directory.GetFiles("Assets", "*.cs", SearchOption.AllDirectories)
    .Concat(Directory.GetFiles("Assets", "*.uxml", SearchOption.AllDirectories));

var report = new LocalizationHardcodedStringExtractor().ExtractFromFiles(paths);

foreach (var candidate in report.Candidates)
{
    UnityEngine.Debug.Log(
        candidate.Key.Value + " -> " + candidate.SourceText +
        " (" + candidate.SourcePath + ":" + candidate.Line + ")");
}

// A row that should stay hardcoded gets a ZOA_LOCALIZATION_IGNORE
// comment token next to it and drops out of the next scan.
Emitting a table asset from a draftcsharp
using ZOA.Localization.Unity.Editor.Assets;

// The wizard's completion step does exactly this.
var draft = new LocalizationTableDraft
{
    LocaleCode = "fr-FR",
    TableName = "UI Strings",
};

draft.Entries.Add(new LocalizationTableDraftEntry
{
    Key = "ui.menu.start",
    Value = "Commencer",
    Context = "Main menu, primary button",
    CharacterLimit = 16,
    ReviewStatus = ZOA.Localization.Core.LocalizationReviewStatus.InReview,
});

// savePath null falls back to Assets/ZOA/Generated/Localization.
var asset = LocalizationTableAssetEmitter.EmitFromDraft(draft, savePath: null);

Tooling

Editor tools

Localization Table Wizard

Tools > ZOA > Advanced > Define > Localization > Table Wizard

Three steps on FoundryWizardShell: Locale Selection with a BCP 47 field and preset buttons for English, French, German, Spanish, and Japanese; Import Keys with an optional template and an add-key field; and Review showing the locale, key count, template, and key list. Each step has a validator feeding the issue tray. The menu item routes into the Workbench rather than opening a floating window.

Localization Workbench module

ZOA Workbench > Localization

Registered as "localization" in the workflow.environment lane at order 51. Five capabilities: Localization Tables (a definition editor over LocalizationTableAsset that browses, edits, validates, duplicates, and deletes, grouped by locale code), String Browser, Coverage Report, Source Extraction, and an Overview of the fallback chain and core types.

String Browser

ZOA Workbench > Localization > String Browser

A searchable list over the project inventory, one row per key and locale showing the locale, key, table name, value, and a DUPLICATE or PLACEHOLDER flag. The search filters on key, locale, value, and table name at once.

Coverage Report

ZOA Workbench > Localization > Coverage Report

Reports the reference locale, total key and locale counts, then one line per locale with coverage percentage, missing count, placeholder count, and duplicate-row count, computed from the table assets rather than from a running service.

Source Extraction

ZOA Workbench > Localization > Source Extraction

Scans every C# and UXML file under Assets on demand and reports the candidate count with the first twenty listed as proposed key, literal text, and file and line. Literals marked with ZOA_LOCALIZATION_IGNORE are suppressed.

Read this

Notes and caveats

See also