Repository navigation
Roadmap
📄 Mirrors
ROADMAP.mdin the main repo — the repo version is canonical.
Status: pre-alpha. Dates are not promised. Each milestone ships when its acceptance criteria are met. Tracked in GitHub milestones and issues. Reordered on 2026-10-14 after the critical review: the differentiator is proven first, behind a go/no-go gate.
Scope freeze (2026-10-14): no new features are added to any milestone before v0.1 ships. New ideas go to issues labelled for triage after v0.1.
Constraint for every milestone: zero dependencies beyond the next and react peers, enforced in CI (ADR 0012, #28).
Goal: a usable alpha that shows a Turbopack-compatible compiler with message-level client tree-shaking on Next 16, measured against the best configs of the alternatives.
-
defineConfig+ config loader with validation (BCP 47 locales,defaultLocale ∈ locales,{locale}inmessages). - Own ICU MessageFormat parser and compiler with a documented subset (ADR 0010, #3, #27).
- Codegen (
tongue buildandwithTongueatnext.configload): per-key exports, lazy formatters, fallback chains resolved (ADR 0001). - CLDR plural-category validation per locale (built-in
Intl.PluralRules). - Type generator: per-namespace
TongueRegisterinterfaces (ADR 0004). -
getT,TongueProvider/useT, coreTruntime (t,t.rich,t.has, declaredt.dynamic/t.ns) andFormat. - Per-file call-site loader for Turbopack and webpack (ADR 0009).
-
examples/cache-components. - Published bundle benchmark vs next-intl (with
precompile) and Paraglide (#25). - Repo tooling: pnpm workspace, TS, Vitest, lint, CI, changesets, dependency budget check, nightly
next@canaryrun (ADR 0011, #29).
Acceptance criteria
- The parser passes the vendored ICU conformance corpus (test fixtures only) covering every construct in the supported subset in ICU messages; unsupported constructs fail the build (#27).
- Invalid ICU reports
file:key:line:col. - Compiling a fixture with 3 locales produces modules where unused keys are removed by esbuild/Rollup tree-shaking (asserted in tests).
-
tsd/expect-typetests cover every row of the "What is checked" table in Type safety. - With a 10k-key registry, cold
tsc --noEmitis ≤ 15% slower than the same app without i18n; incremental and tsserver completion latency measured and published. - A client component using 2 of 500 keys ships only those 2 (all locales below the threshold) with no extra round trip before interactivity.
- The loader uses no
emitFile/loadModule/importModuleand works withnext dev/next build(Turbopack) and--webpack. -
examples/cache-componentsbuilds; all localized routes are reported as prerendered (static or PPR) bynext build. - No catalog JSON appears in the RSC payload or HTML of any example route (#20, research A4).
- Default fallback follows CLDR parent locales and never crosses scripts (
zh-Hant-HK → zh-Hant, neverzh-Hans); explicitfallbackoverrides (research A7). - Generated date formatters always pass the configured
timeZone(default'UTC') (ADR 0008). - Dev watcher: memory stays flat (< 10% growth) over a 30-minute soak with 1,000 message edits; one watcher across workers; no child process outlives
next dev(research A9). - Early check:
cacheComponents: true+output: 'export'builds on the current 16.x (#15). - Published package.json has no dependencies beyond
next/reactpeers (CI) (#28). - Benchmark published with reproducible scripts (#25).
- CI green on Node 20 and 22.
Go/no-go gate: if the benchmark does not show a clear client-bundle win over next-intl (precompile + pick) and Paraglide, stop and reconsider before building v0.2+ (options: change the delivery strategy, contribute upstream, or offer Paraglide-compatible output).
-
createProxyforproxy.ts:prefix: 'always' | 'as-needed', detection, cookie,/en/*canonical redirect (#30). -
next-tongue/navigation:Link,redirect,permanentRedirect,useRouter,usePathname,getPathname(thin wrappers overnext/linkandnext/navigation). -
generateAlternates,getDir,getOgLocale; time zone per request (#17). - Server actions locale passing (#26);
next-tongue/testing. -
examples/basic,examples/static-export(prefix: 'always'only). - Request-time
formatMessage(locale, icu, values)for database/CMS strings #34 (ADR 0013). - Typed
Formathelpers: list, relative time, units, display names viaIntl#45. - Security hardening: XSS corpus, locale validation, threat model in SECURITY.md #46.
- Docs recipe: per-user preferred language (helper ships in v1.1).
- Pseudo-localisation:
en-XA#36.
Acceptance criteria
- No next-tongue code path calls
headers(),cookies()ordraftMode()(lint rule + test). -
examples/static-exportbuilds withoutput: 'export',prefix: 'always'anddynamicParams = false. - Playwright e2e for
alwaysandas-needed, detection, cookie and the canonical redirect. -
generateAlternatesoutput validated against Google hreflang rules (reciprocal,x-default). - Client runtime ≤ 2 kB min+gz enforced by
size-limit. -
createProxylocale resolution: p50 < 1 ms and p99 < 3 ms with 150 locales (benchmark in CI); noIntl.*construction per request; LRU on the header string (research A3). - Locale cookie is
SameSite=Laxby default and is sent on a cross-site navigation in Playwright (research A5). - Hydration test: a date formatted in the static shell and a client component shows no hydration warning when the server
TZdiffers from the browser (ADR 0008). -
getTworks ingenerateMetadataand a server action on a freshly started worker (research A8). -
formatMessageuses the own parser with a bounded LRU, works inside'use cache', and passes an XSS corpus for rich-text tags #34. -
Format.list,relativeTime(explicitnow),unitanddisplayNameare typed and tested in en, de, ar, ja #45. - XSS corpus passes for
t.richandformatMessage; locale inputs reject path traversal and CRLF/header injection; threat model published #46. -
en-XApreserves ICU structure, expands and accents text, and is excluded from production by default #36.
- Dev overlay #35; translated validation errors (
translateIssues) #38; accessible headlessLocaleSwitcher#44; translated OG images and emails #39.
The CLI uses only Node built-ins (util.parseArgs, readline, fs, global fetch).
Acceptance criteria
-
tongue checkimplements all six checks in CLI withpretty|json|githubreporters and documented exit codes, reusing the codegen AST. -
tongue checkon a 10k-key, 500-file repo completes in < 5 s. -
tongue extractfinds keys in.ts/.tsx/.js/.jsx/.mdx, adds missing source keys,--pruneremoves unused. - Dev overlay shows locale, missing keys and client-sent messages with click-to-key; no overlay code or key ids in production builds #35.
-
translateIssuestranslates Standard Schema-shaped issues with typed keys and no validator dependency #38. -
getTworks inopengraph-image.tsx(incl. RTL) and in an email rendering example; examples type-checked #39. -
LocaleSwitcherkeeps the page, persists the choice, works without JS and passes axe in Playwright #44. -
tongue initoncreate-next-app@16output yields a building app (--yes), writesgenerateStaticParams = localeParams, idempotent on second run.
- Build-time database/CMS
sourcesintongue.config.ts#33;tongue export/import(XLIFF 2.0, CSV) #37; a11y/bidi checks intongue check#40; stale-translation detection #42; translator context ($meta) #43;tongue report#41.
Acceptance criteria
-
routing.pathnames,routing.domainsandprefix: 'never'with Playwright e2e (#32). - A pnpm-workspace fixture (shared messages package + 2 apps,
declaration: true) builds and type-checks with no TS2742 (#21, research A6). -
sourcesare awaited bytongue build, merged after files, compiled and typed; failures fail the build unlesssourcesOnError: 'use-cache'#33. - XLIFF 2.0 / CSV export → import round-trip is lossless; invalid imports are rejected with
file:line#37. -
tongue checkreports missinglang/dirand bidi issues on ar/he/fa fixtures #40. -
tongue checkflags targets whose source hash intongue.lockchanged #42. -
$metadescription, screenshot andmaxLengthreachtranslateandexport;tongue checkreports over-length targets #43. -
tongue reportprints keys and bytes sent to the client per route, with a--max-bytesbudget #41.
Acceptance criteria
- Works against OpenAI and a local Ollama endpoint in CI (recorded fixtures for OpenAI), via global
fetchonly. - Glossary enforcement and lockfile semantics exactly as in AI translation.
- Placeholders and tags are masked before sending and restored after; max-cost/token budget;
--reviewis the default in CI. - 100% of written outputs pass ICU parse + arg/tag/plural parity; invalid outputs never written.
-
--dry-runmakes zero network calls (test). - API key never appears in logs, lockfile or error output (test).
- API freeze; docs site; security review of CLI; benchmarks re-run and published.
Acceptance criteria
- Decision recorded on an opt-in
getT(ns)vianext/root-params(ADR 0007, #24), with tests for two root layouts and locale switch under"use cache". - No breaking changes for 4 weeks; 3+ external production-like apps report success.
- All docs pages verified against real code (doc examples are type-checked in CI).
Acceptance criteria
- Semver guarantees documented; deprecation policy; support policy per ADR 0011.
- Zero open
priority: criticalbugs.
- VS Code extension in
packages/vscode(VS Code API only): inline previews, missing-key diagnostics, go-to-message, hover with all locales #47. - Per-user preferred language:
setLocalePreferenceaction helper, signed cookie,createProxy({ resolveLocale })#48. No DB call in the proxy; no headers in cached scopes.
Acceptance criteria
- Extension published (Marketplace + Open VSX) with no runtime dependency beyond the VS Code API.
- Preference recipe e2e: save → signed cookie → proxy resolves locale; tampered cookie ignored.
-
tongue migrate next-intl(#31): before 1.0 only message-file migration and theuseTranslations→useTclient mapping are documented; the full codemod (locale threading withTODO(tongue)comments + a report) comes after 1.0, measured on 3 real OSS apps. - The next-international codemod is dropped (no upstream release since Oct 2024).
MessageFormat 2; MDX/content localization; Vite/React Router adapter on the same compiler; VS Code extension (inline previews, go-to-message); TMS sync (XLIFF/PO export); opt-in per-locale client splitting once measured (ADR 0009).
Guides
- Getting Started
- Configuration
- Routing and Proxy
- Server Components
- Client Components
- Server Actions
- ICU Messages
- Type Safety
- Cache Components and PPR
- Static Export
- Metadata SEO and hreflang
- Database and CMS Messages
- Dev Tools
- Translator Workflow
- Per-user Preferred Language
- CLI
- AI Translation
- Testing
- VS Code Extension
- Migration from next intl
- Migration from next international (deferred)
Reference