Contributing

Contributing Uma Musume Translations to UmaTools

Contribute interface translations using the shared modules, fallback rules, placeholders, HTML attributes, and validation workflow.

Updated September 1, 20263 min read

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/:

FileResponsibility
public/js/i18n-core.jsShared terms, navigation, language state, lookup, interpolation, and DOM updates.
public/js/i18n-pages.jsPage-specific strings for the tool suite. It must load after i18n-core.js.
public/js/i18n.jsCompatibility 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:

PrefixScope
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

  1. Decide whether the string is shared or page-specific.
  2. Add the English and Japanese values to the matching objects in i18n-core.js or i18n-pages.js.
  3. Mirror the entry in i18n.js when a compatibility page can use it.
  4. Reference the key from HTML or JavaScript.
  5. 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:

AttributeUpdates
data-i18ntextContent
data-i18n-htmlSanitized/controlled innerHTML content
data-i18n-placeholderForm placeholder
data-i18n-ariaaria-label
data-i18n-titleTooltip/title

Keep readable English fallback text inside the HTML so the page remains understandable before JavaScript runs.

Adding a language

  1. Add the locale object to both split translation modules.
  2. Update language normalization and setLang() in public/js/i18n-core.js.
  3. Add the language option to the settings UI generated by public/js/nav.js.
  4. Update public/js/i18n.js for compatibility pages.
  5. 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:

  1. The language changes immediately from Settings.
  2. The choice persists across every tool.
  3. Dynamically rendered results and dialogs are translated.
  4. Placeholders, titles, and accessible labels update.
  5. 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));