Repository navigation
Localization: client-supplied stat names, German translation, locale linter - #13
Conversation
The audit checked enchants, sockets and item level. Add three more
of the questions worth asking before a raid, all from unprotected
item data:
- Tier set count via C_Item.GetSetBonusesForSpecializationByItemID
across the five tier slots -- there is no "N of 5" API, so we tally
the slots whose item grants a set bonus for the current spec, which
also counts Catalyst-made pieces.
- Upgrade track and progress per slot ("Champion 6/8"). No API
returns this for an equipped item, so it is scanned from the item
tooltip via C_TooltipInfo; best-effort and English-only by nature,
guarded so a bad read never takes the audit down, and simply
omitted when it doesn't match.
- Below-Epic gems, flagged like a missing enchant.
Surfaced in /sp gear, the Gear options page, and (tier count) the
chat announce. Enchant rank and embellishment were left out: both
need a per-season table or fragile matching and would rot silently.
API surface verified against warcraft.wiki.gg and a reference addon
before building. Not verified in-game -- the tooltip scan for the
upgrade track is the part most worth confirming live.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
# Conflicts: # CHANGELOG.md # StatPanel.toc
StatPanel had no localization at all -- every user-facing string was an inline English literal. Add a tiny hand-rolled locale table (no embedded library, in keeping with the rest of the addon): - Locale.lua creates SP.L, whose __index returns the key itself, so the English string IS the key and any untranslated or missing string falls back to readable English. A matching non-English client locale file overlays it; other locales' files load into a throwaway table. - Locales/README.md documents how to contribute a translation. - Loaded first in the .toc, before anything that reads SP.L. Route the slash-command output (SPMain) and the right-click menu (Menu) through SP.L as the first tranche, converting the concatenated messages to format strings so translators can reorder. The remaining files -- Options, Config, Presets, Gear, Announce and the rest -- are the next tranches. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Locale.lua reads GetLocale() to pick the client locale; it wasn't in the declared API list. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The bulk of the sweep. Every option label, tooltip, header, note, dropdown display name and button caption in Options.lua now looks up SP.L; Config.lua's profile/import error messages and the preset descriptions in Presets.lua do too. Concatenated messages became format strings so translators can reorder. Config keys (path=), dropdown data values (value=), page ids, value-format templates, media/font names, preset names and section titles are deliberately left untouched -- they are identifiers and lookup keys, not display text. Because SP.L falls back to the key itself, every wrap is a no-op on an English client and only takes effect once a translation provides the string. The mechanical wrapping was done by script over the unambiguous patterns (label/tooltip/text/name/UI:Header/UI:Note) and reviewed as a whole; the concatenated and escaped strings were done by hand. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Content-context rule names, the broker tooltip lines, the announce channel names and every announce status/error message now look up SP.L. The "N values left out" plural was simplified to "N value(s)" so it needs no English-specific plural fragment. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Completes the sweep: stat display names (STAT_DEFS, PRIMARY_NAME, SHORT_NAME), the panel row tooltip and the Rebuild error in StatPanel; the whole /sp gear report and warning summary in Gear; and the item-level / priority / gear lines the announce assembles. Plural counts became "%d thing(s)" so no language needs English plural rules. Every user-facing string in the addon now looks up SP.L. Document the feature and bump to 2.3.0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The first localization pass routed strings through SP.L but left several gaps that only show up once someone actually translates. Stat and gear-slot names now come from Blizzard's own GlobalStrings via a new SP.Global helper, which falls back to SP.L when a global is missing. Those read correctly in all twelve locales with no translator effort. The abbreviated priority-chain labels (Crit, Mast, Vers) stay in SP.L, since the Blizzard names are the full ones and would not fit. Strings the first pass missed are routed too: the font-outline dropdown, the live preview window, the Gear page's slot list and summary, and the LDB broker text. The last three were reaching the UI through string.format and assignment rather than SetText, which is why a grep for SetText did not find them. Sentences built with .. become format strings so translations can reorder them, and Locales/deDE.lua is a complete German translation (452 keys). SP.L never fails at runtime, so the two mistakes translators actually make are silent: a mistyped key renders English forever, and a dropped format specifier only errors at the far-away :format() call. tools/locale-lint.ps1 reports both, plus duplicates, empty translations, a mismatched SP.Locale argument and a file missing from the TOC. -Export emits a stub. CI runs it on every pull request. Also fixes the CI TOC check, which anchored on [A-Za-z0-9_/-]+ and so stopped at the backslash in a Windows-style path. Every subdirectory entry was skipped silently, meaning a broken Locales\ path would have passed. Separators are normalized before matching and the check now walks subdirectories.
2.2.0 keeps its 2026-07-23 date: that is when its work landed, and it never had a release of its own -- it ships as part of this one.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5d1863c048
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if ($positional) { | ||
| # %1$s style: the translator has explicitly reordered, which is | ||
| # the supported way to do it. Only the count matters. |
There was a problem hiding this comment.
Reject unsupported positional format specifiers
When a translator follows the documented reordering advice and writes a value such as %2$d ... %1$s, this branch accepts it, but the addon's Lua 5.1 string.format implementation does not support the $ positional syntax and raises an invalid-format-option error at the affected UI call. The linter should reject these specifiers, or argument reordering must be implemented outside string.format, rather than certifying a translation that will fail at runtime.
Useful? React with 👍 / 👎.
| local priority = SP:GetCurrentPriority() | ||
| parts[#parts + 1] = "priority " .. table.concat(priority, " > ") | ||
| parts[#parts + 1] = L["priority %s"]:format(table.concat(priority, " > ")) |
There was a problem hiding this comment.
Localize priority entries before joining them
On a German client with includePriority enabled, this produces a mixed-language announcement such as Priorität Haste > Crit > Mastery > Versatility: GetCurrentPriority() returns the canonical English identifiers, while only the surrounding format string is translated. Convert each entry through the localized stat display names before concatenating it; the same raw-list formatting also occurs in the pasted-priority confirmation in Options.lua.
Useful? React with 👍 / 👎.
Continues the locale framework from the earlier commits on this branch, closing the gaps that only surface once someone actually translates the addon.
Stat and slot names come from the client
New
SP.Global(globalName, englishKey)inLocale.luaprefers Blizzard's ownGlobalStringsand falls back toSP.Lwhen a global is missing. The 16 gear slots (HEADSLOT,FINGER0SLOT, …) and 14 stat names (STAT_HASTE,SPELL_STAT1_NAME, …) are already correct in all twelve client locales with no translator effort.PrimaryandArmor DRstay inSP.L— neither is a Blizzard concept. So do the abbreviated priority-chain labels (Crit,Mast,Vers), since the Blizzard names are the full ones and the point of that line is that it fits.Strings the first pass missed
The font-outline dropdown, the live-preview window, the Gear page's slot list and summary, and the LDB broker text. The last three reach the UI through
string.formatand assignment rather thanSetText, which is why the original sweep didn't find them — the broker one is visible in Titan Panel and ElvUI datatexts.Sentences assembled with
..are now format strings so translations can reorder them.German translation
Locales/deDE.lua, complete at 452/452 keys. Terminology checked against the German client's own wording; a native-speaker pass on tone would still be welcome.Locale linter
SP.Lnever fails at runtime, which is right — but it means the two mistakes translators actually make are silent. A mistyped key renders English forever and nobody notices; a dropped or reordered format specifier only errors at the far-away:format()call.tools/locale-lint.ps1reports both, plus duplicate keys, empty translations, a locale file whoseSP.Localeargument doesn't match its filename, and one missing from the TOC.-Export <locale>emits a ready-to-fill stub. CI runs it on every PR.Verified by seeding a throwaway locale file with six deliberate faults: all six fired, plus the TOC check, exit 1 — and the positional
%1$dcase correctly did not error.Fixes the CI TOC check
It anchored on
[A-Za-z0-9_/-]+\.lua, which stops dead at the backslash inLocales\deDE.lua. Every subdirectory entry was invisible to it, so a broken locale path would have passed green. Separators are normalized before matching and the check now walks subdirectories.Also in this release
## Notes-<locale>headers for the ten translated locales, read by the in-game addon list and the CurseForge/Wago pages.Known, not addressed here
Fonts\FRIZQT__.TTFis hardcoded in ten places. Blizzard ships locale-specific fonts for zhCN/koKR/ruRU, so a CJK translation would likely render tofu boxes. Unverified without those clients — worth resolving before adding those locales.string.format("%.2f")always emits10.65; German convention is10,65.%-12sin the gear report pads by bytes, not characters, so multi-byte slot names skew that column.