UmaTools currently provides English and Japanese interfaces. The selected site language is stored in localStorage under umatoolsSiteLanguage; English is the fallback when a translated key is unavailable.
Translation modules
The browser translation files live in public/js/:
| File | Responsibility |
|---|---|
public/js/i18n-core.js | Shared terms, navigation, language state, lookup, interpolation, and DOM updates. |
public/js/i18n-pages.js | Page-specific strings for the tool suite. It must load after i18n-core.js. |
public/js/i18n.js | Compatibility build used by the landing, event, and 404 pages while those pages are migrated to the split modules. |
When changing a shared or page-specific string, keep the equivalent compatibility entry in i18n.js synchronized until every page uses the split modules.
How lookup works
Settings selection
-> localStorage
-> i18n-core language state
-> t('section.key', variables)
-> English fallback if necessary
-> applyI18n() updates marked DOM elements
Translation keys use section.camelCase names. Common sections include:
| Prefix | Scope |
|---|---|
common.* | Shared stats, controls, race terms, and status labels. |
nav.* | Navigation, settings, social links, and footer. |
optimizer.* | Skill Optimizer and its tutorial. |
calculator.* | Rating Calculator. |
deck.* | Deck Builder and scenario templates. |
stamina.* | Stamina Calculator. |
hints.* | Support Hint Finder. |
tokenPlanner.* | Grand Live Token Planner. |
skills.* | Skill Library. |
skillPopup.* | Shared skill detail dialog. |
ratingShared.* | Shared rating and rank components. |
Adding or updating a string
- Decide whether the string is shared or page-specific.
- Add the English and Japanese values to the matching objects in
i18n-core.jsori18n-pages.js. - Mirror the entry in
i18n.jswhen a compatibility page can use it. - Reference the key from HTML or JavaScript.
- Test both languages and the English fallback.
English remains the canonical key set. Keep placeholder names identical between languages.
'stamina.needMore': 'Need about {amount} more stamina.'
t('stamina.needMore', { amount: 150 });
HTML attributes
Static markup uses data-i18n* attributes:
| Attribute | Updates |
|---|---|
data-i18n | textContent |
data-i18n-html | Sanitized/controlled innerHTML content |
data-i18n-placeholder | Form placeholder |
data-i18n-aria | aria-label |
data-i18n-title | Tooltip/title |
Keep readable English fallback text inside the HTML so the page remains understandable before JavaScript runs.
Adding a language
- Add the locale object to both split translation modules.
- Update language normalization and
setLang()inpublic/js/i18n-core.js. - Add the language option to the settings UI generated by
public/js/nav.js. - Update
public/js/i18n.jsfor compatibility pages. - Verify key coverage, interpolation, persistence, mobile settings, and fallback behavior.
Testing
Run the standard checks:
npm run lint
npm test
Then preview with npx vercel dev and verify:
- The language changes immediately from Settings.
- The choice persists across every tool.
- Dynamically rendered results and dialogs are translated.
- Placeholders, titles, and accessible labels update.
- Missing non-English keys fall back to English rather than showing a key name.
In the browser console, compare key sets when diagnosing coverage:
Object.keys(I18n.TRANSLATIONS.en).filter((key) => !(key in I18n.TRANSLATIONS.ja));