ek9_organize_localized_text

Moves the `defines text for "<locale>"` blocks between files to the chosen layout - block content preserved verbatim, donors kept as residual stubs, never deleted - and answers the editor envelope: status (applied | ready | conflicts | error), written, edits[] and summary; an already-canonical layout is applied with empty edits[].

Category: Editor · Compare: NEW IDE surface — Build menu → "Organize Localized Text…" wizard (mode picker, preview pane, conflict resolver). Pairs with the Translation Completeness panel.

When to use it

'Re-lay the module's i18n files' is one call: mode split-by-locale (one file per language), split-by-text-type (one per text type) or consolidate (targetFile) - content untouched.

When not to use it

Details

Semantics-preserving by construction: EK9 resolves text types by module-scoped class name, not file path, so no call sites break and no reference sync is needed. Every apply canonicalises ordering (locales then text types, alphabetical), so the FIRST apply on a correctly-shaped but unordered layout is a normalisation pass (non-empty edits); subsequent applies are true no-ops. Donor files are RETAINED with block ranges excised (comments, commented-out code and live constructs survive in the residual); conflict kinds are target-file-exists (mechanical: rename clash or pick different targetFile), module-name-mismatch (fix source typo or scope via `module`), discovery-spans-multiple-directories (caller picks a directory) and no-localized-text-found.

Arguments

ArgumentTypeRequiredWhat it is
modestring: split-by-locale | split-by-text-type | consolidateyesLayout target. split-by-locale -> <locale>.ek9 per language; split-by-text-type -> <TextTypeName>.ek9 per text type; consolidate -> the single targetFile.
modulestringThe module to operate on. Default: the first module that defines any text type; supply it when several modules carry i18n.
targetFilestringDestination: the single output file (workspace-relative), required for consolidate; REJECTED for the split modes, whose outputs are deterministically named.

It also takes the arguments every tool takes.

Recorded calls

Real calls, recorded against small projects and checked on every build - a changed answer fails it. 3 of the 10 recorded are shown.

Idempotent rerun

Request

{
  "mode" : "split-by-locale"
}

Response

{
  "conflicts" : [ ],
  "edits" : [ ],
  "meta" : {
    "serverMs" : "<timing>"
  },
  "risk" : {
    "crossesModuleBoundary" : false,
    "estimatedSeverity" : "trivial",
    "fileCount" : 0,
    "lineCount" : 0,
    "touchesPublicApi" : false,
    "touchesTests" : false
  },
  "status" : "applied",
  "summary" : "Layout already organised per split-by-locale; no changes needed",
  "workspaceHash" : "<workspace-hash>",
  "wouldBeDiagnostics" : [ ],
  "written" : true
}

Conflict target file exists

Request

{
  "mode" : "split-by-locale",
  "module" : "com.example.i18n"
}

Response

{
  "conflicts" : [ {
    "file" : "<workspace-root>/en_GB.ek9",
    "kind" : "target-file-exists",
    "reason" : "target-file-exists",
    "suggestedRepair" : {
      "recommendation" : "Rename the existing non-i18n file out of the way, OR for consolidate mode pick a different `targetFile`, OR for split modes resolve the name clash before retry."
    }
  } ],
  "edits" : [ ],
  "meta" : {
    "serverMs" : "<timing>"
  },
  "risk" : {
    "crossesModuleBoundary" : false,
    "estimatedSeverity" : "trivial",
    "fileCount" : 0,
    "lineCount" : 0,
    "touchesPublicApi" : false,
    "touchesTests" : false
  },
  "status" : "conflicts",
  "summary" : "Cannot apply — 1 conflict(s): target-file-exists",
  "workspaceHash" : "<workspace-hash>",
...

Cut short here: 3 more lines. The whole recorded call.

Consolidate apply

Request

{
  "mode" : "consolidate",
  "targetFile" : "all_text.ek9"
}

Response

{
  "conflicts" : [ ],
  "edits" : [ {
    "after" : "#!ek9\ndefines module com.example.i18n\n\n  defines text for \"de\"\n    WelcomePageText\n      mainWelcome()\n        \"Hallo Welt\"\n\n\n  defines text for \"en_GB\"\n    WelcomePageText\n      mainWelcome()\n        \"Hello World\"\n\n//EOF\n",
    "file" : "all_text.ek9",
    "type" : "create"
  }, {
    "after" : "",
    "before" : "  defines text for \"de\"\n    WelcomePageText\n      mainWelcome()\n        \"Hallo Welt\"\n",
    "endLine" : 8,
    "file" : "de.ek9",
    "startLine" : 4,
    "type" : "replace"
  }, {
    "after" : "",
    "before" : "  defines text for \"en_GB\"\n    WelcomePageText\n      mainWelcome()\n        \"Hello World\"\n",
    "endLine" : 8,
    "file" : "en_GB.ek9",
    "startLine" : 4,
    "type" : "replace"
  } ],
  "meta" : {
    "serverMs" : "<timing>"
  },
...

Cut short here: 14 more lines. The whole recorded call.

See also