Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 121 additions & 0 deletions .contrib/.tools/Lua/normalize.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
const fs = require("fs");

/**
* Normalize ATT localization tables into the canonical locale order.
*
* This script is intentionally limited to the simple, one-locale-per-line
* tables used by the parser data. It updates the supplied file in place, so
* callers should review the resulting Git diff before committing it.
*/

// Keep this order aligned with the locale order used by ATT data files.
const expectedKeys = [
"en","de","es","mx",
"fr","it","ko","pt",
"ru","cn","tw"
];

const file = process.argv[2];
if (!file) {
console.error("Please provide the path of the file to process");
process.exit(1);
}

let content = fs.readFileSync(file, "utf8");

// Match only localization-bearing fields. The non-greedy body stops at the
// first closing brace on its own line, which is valid for the flat tables this
// tool supports. The final group preserves an optional Lua comma or semicolon.
const tableRegex =
/(^[ \t]*(text|description|lore)\s*=\s*\{)([\s\S]*?)(^\s*\})([ \t]*[,;]?)/gm;

content = content.replace(
tableRegex,
(fullMatch, tableHeader, tableName, body, closingBraceLine, afterBrace) => {

// Reuse the table header's indentation for the closing brace so running
// the tool does not disturb the surrounding Lua structure.
const headerIndent = tableHeader.match(/^(\s*)/)[1];

// Empty lines are removed during normalization. Only recognized locale
// assignments are retained; other content inside a matched table is out
// of scope for this deliberately narrow formatter.
const lines = body.split(/\r?\n/).filter((l) => l.trim() !== "");

const presentKeys = [];
const valueLines = [];

for (const line of lines) {
// A translated locale, for example: en = "Example",
const normal = line.match(/^\s*(\w+)\s*=/);

// Commented translations and TODO placeholders both count as present;
// otherwise a second placeholder for the same locale would be created.
const commented = line.match(/^\s*--\s*(?:TODO:\s*)?(\w+)\s*=/);

if (normal) {
presentKeys.push(normal[1]);
valueLines.push(line); // Preserve as-is
} else if (commented) {
presentKeys.push(commented[1]); // Commented fields count as present
valueLines.push(line); // Preserve as-is
}
}

// English-only entries are intentionally compact. TODO placeholders become
// useful only after an entry has started receiving additional translations.
if (presentKeys.length === 1 && presentKeys[0] === "en") {
return (
`${tableHeader}\n` +
valueLines.join("\n") +
`\n${headerIndent}}${afterBrace}`
);
}

// Match generated TODO entries to the indentation of the first locale.
let firstIndent = "";
if (valueLines.length > 0) {
const m = valueLines[0].match(/^(\s*)/);
firstIndent = m ? m[1] : "";
}

// Rebuild the table in canonical order. Values are reused verbatim so this
// step changes position and completeness, but never translation content.
const finalLines = [];

for (const k of expectedKeys) {
// Prefer an active translation when both active and commented variants
// somehow exist for the same locale.
const existing = valueLines.find((l) =>
l.trimStart().startsWith(k + " =")
);

const commented = valueLines.find((l) =>
l.trimStart().startsWith("-- " + k + " =") ||
l.trimStart().startsWith("-- TODO: " + k + " =")
);

if (existing) {
finalLines.push(existing);
} else if (commented) {
finalLines.push(commented); // Preserve commented line
} else {
// Make missing translations visible without creating executable Lua
// fields whose empty values might be mistaken for real translations.
finalLines.push(`${firstIndent}-- TODO: ${k} = "",`);
}
}

return (
`${tableHeader}\n` +
finalLines.join("\n") +
`\n${headerIndent}}${afterBrace}`
);
}
);

// Write once after all matching tables have been normalized. No backup file is
// created because Git is expected to provide review and recovery for this tool.
fs.writeFileSync(file, content, "utf8");

console.log("✅ Done: Commented fields are treated as existing, format fully preserved and keys reordered");
95 changes: 95 additions & 0 deletions .contrib/.tools/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Contributor Tools

## Normalize Lua localization tables

[`Lua/normalize.js`](Lua/normalize.js) normalizes localization tables in a Lua data file. It is intended for contributors who edit `text`, `description`, or `lore` tables in the parser data.

The tool:

- processes every `text`, `description`, and `lore` table in the selected file;
- orders locale keys as `en`, `de`, `es`, `mx`, `fr`, `it`, `ko`, `pt`, `ru`, `cn`, and `tw`;
- adds a commented `TODO` entry for each missing locale;
- preserves existing locale values and existing commented locale entries; and
- leaves an English-only table English-only instead of adding `TODO` entries.

### Requirements

- [Node.js](https://nodejs.org/) must be installed and available as `node`.
- To use the included task, open the repository in Visual Studio Code.

### Run from Visual Studio Code

1. Open the Lua file that you want to normalize and make sure it is the active editor.
2. Open the Command Palette.
3. Select **Tasks: Run Task**.
4. Select **Normalize Lua Table**.
5. Wait for the terminal to report that the operation is complete.
6. Review the file's Git diff before keeping the result.

The task uses the active editor's file. Save or switch to the intended file before running it.

### Run from a terminal

From the repository root, run:

```sh
node .contrib/.tools/Lua/normalize.js "path/to/data-file.lua"
```

For example:

```sh
node .contrib/.tools/Lua/normalize.js ".contrib/Parser/DATAS/00 - DB/ObjectDB.lua"
```

### Example

Input:

```lua
text = {
en = "Example",
fr = "Exemple",
}
```

Output:

```lua
text = {
en = "Example",
-- TODO: de = "",
-- TODO: es = "",
-- TODO: mx = "",
fr = "Exemple",
-- TODO: it = "",
-- TODO: ko = "",
-- TODO: pt = "",
-- TODO: ru = "",
-- TODO: cn = "",
-- TODO: tw = "",
}
```

An English-only table remains compact:

```lua
text = {
en = "English only",
}
```

### Safety and limitations

The tool edits the selected file in place and does not create a backup. Commit or stash unrelated work first, then review the complete diff after it runs.

Use it only on localization tables containing one locale assignment per line, for example `de = "..."`, `-- de = "..."`, or `-- TODO: de = "..."`. Blank lines and content that is not recognized as a locale assignment are not retained inside a matched table.

To inspect the result:

```sh
git diff -- "path/to/data-file.lua"
git diff --check
```

If the result is not expected, restore it with your normal Git workflow before making additional edits.
15 changes: 15 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Normalize Lua Table",
"type": "shell",
"command": "node",
// Run against the file in the active editor, rather than a fixed data file.
// Explicit quoting keeps paths containing spaces as one shell argument.
"args": ["${workspaceFolder}/.contrib/.tools/Lua/normalize.js", "\"${file}\""],
"problemMatcher": [],
"group": "none"
}
]
}