Skip to content

Add i18n locale support with 81 translations#421

Draft
cat5inthecradle wants to merge 1 commit intomainfrom
claude/priceless-dubinsky
Draft

Add i18n locale support with 81 translations#421
cat5inthecradle wants to merge 1 commit intomainfrom
claude/priceless-dubinsky

Conversation

@cat5inthecradle
Copy link

@cat5inthecradle cat5inthecradle commented Mar 10, 2026

This is a Claude written PR. I was curious what it would look like to pull in translations. - Darin

Summary

  • Copies 81 non-English translation files from code-dot-org/code-dot-org apps/i18n/fish/ into i18n/locales/
  • Adds runtime locale selection via ?locale=xx_xx query parameter for the standalone demo
  • Extends the initAll() API to accept raw translation JSON alongside the existing pre-compiled function override path
  • Adds bin/syncTranslations.js script for keeping translations in sync with the monorepo

Motivation

We are interested in hosting this activity in an iframe and needs localization support. The translations already exist in the main code-dot-org monorepo but weren't accessible to standalone consumers of this repo.

Technical decisions

Runtime fetch vs. build-time bundling for locale files

Locale JSON files are fetched at runtime (fetch('locales/es_es.json')) rather than bundled into the main JS bundle. Bundling all 81 locales (~587KB of JSON) would bloat oceans.js for every user when only one locale is needed per session. Runtime fetch means a single small (7-20KB) request for just the locale needed, and English users pay nothing.

Tradeoff: There's a brief async gap before translations load. In practice the JSON files are tiny and same-origin so this is negligible.

Raw strings vs. pre-compiled function detection in initI18n

The original initI18n assumed overrides were pre-compiled MessageFormat functions (as the main code-dot-org host app provides). A type check was added — typeof values[0] === 'string' — to auto-compile raw JSON strings when detected.

This preserves backward compatibility: the host app integration path (passing pre-compiled functions) still works unchanged, while the standalone demo and new iframe embedders can pass raw JSON translation objects directly.

Locale code extraction: es_eses

Translation files use xx_xx naming (e.g. es_es, pt_br) but MessageFormat v2.3.0's constructor expects a BCP 47 language code like es to select pluralization rules. The language portion is split from the locale and passed to MessageFormat.

Regional variants (pt_br vs pt_pt) share pluralization rules, so this is correct — the actual translated strings remain distinct per file.

Locale files as CopyPlugin static assets

Locale files are added to the existing CopyPlugin config rather than processed as webpack modules. They need to be individually addressable by URL at runtime for the fetch. CopyPlugin copies them verbatim to dist/locales/, which is exactly what's needed — webpack module processing would either bundle them all or create content-hashed chunk filenames that runtime fetch couldn't predict.

?locale= query parameter

Follows the existing convention of the standalone demo page, which already uses query parameters for configuration (?mode=, ?guides=, ?tts=). This is the standard approach for passing config into iframe-embedded apps — stateless, visible, and controlled entirely by the embedder via the src attribute.

Graceful fallback on fetch failure

If a locale file doesn't exist or fetch fails, the app logs a warning and initializes in English. The ?locale= param comes from URL input that could be a typo or unsupported locale — crashing the activity over it would be a poor experience.

Usage

  • Default (English): localhost:8080
  • With locale: localhost:8080?locale=es_es
  • In an iframe: <iframe src="https://host/index.html?locale=fr_fr">
  • Via the API: initAll({i18n: translationJSON, locale: 'fr'})
  • Re-sync translations: yarn sync-i18n (GitHub) or yarn sync-i18n:local ~/code/code-dot-org

Test plan

  • yarn dev — app loads at localhost:8080 in English (no regression)
  • localhost:8080?locale=es_es — Spanish strings appear
  • localhost:8080?locale=fr_fr — French strings appear
  • localhost:8080?locale=bogus — falls back to English with console warning
  • No ?locale param — English works as before (backward compat)
  • yarn build — production build succeeds, locale files appear in dist/locales/

🤖 Generated with Claude Code

Load non-English translation files from code-dot-org/code-dot-org
apps/i18n/fish/ into this repo and wire up runtime locale selection
via ?locale=xx_xx query parameter.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@cat5inthecradle cat5inthecradle marked this pull request as draft March 10, 2026 22:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant