Internationalization
Use the saved English/French dashboard language and extend its messages, or enable the separate public-page showcase.
Was this page helpful?
Choose Français from the actual dashboard's language menu to translate its
interface. The language survives dashboard navigation and reloads without
changing /dashboard/** URLs. English is the default when this browser has
no saved choice. The shared demo at /demo/dashboard has the same menu and
uses sample data.
To keep the dashboard English-only, retain only en in dashboardLocales
and its matching name in src/i18n/config.ts. The existing provider and
English catalog can stay in place.
The translation setup is already connected:
src/i18n/config.ts lists languages and their menu names.src/i18n/messages/en.json and fr.json contain the interface text.src/i18n/request.ts reads the validated browser preference and loads its
language's messages for server rendering.src/routes/dashboard/route.tsx supplies the same language and messages to
DashboardI18nProvider, so interactive components can read them too.For components inside the dashboard provider, import useTranslations and
useLocale from use-intl. For example, after adding YourFeature.title to
every catalog, render it in your own component:
import { useTranslations } from 'use-intl';
export function FeatureHeading() {
const t = useTranslations('YourFeature');
return <h1>{t('title')}</h1>;
}For text computed on the server, load getDashboardLocale() from
src/i18n/request.ts inside the server boundary, then pass its locale and
messages to createTranslator from use-intl/core. The existing
src/lib/dashboard.server.ts shows that pattern. Keep the request-cookie
reader out of browser imports; route components receive the safe locale and
catalog through the native loader. See the
use-intl APIs.
The language menu calls the validated POST server function in src/i18n/actions.ts. It saves
coremvp_dashboard_locale as a validated, HttpOnly browser cookie for one year,
with SameSite=Lax and Secure in production. Server rendering reads that
cookie; client components read the provider instead of document.cookie.
Changing language invalidates the current route so server and browser text update together. Another browser
or device starts in English; the preference is not a database account field.
For Spanish, copy the complete existing catalog from the template root:
cp src/i18n/messages/en.json src/i18n/messages/es.jsonTranslate the string values in es.json, retaining every key, interpolation
placeholder, plural branch, and rich-text tag. Then add "es" to
dashboardLocales and es: "Español" to dashboardLocaleNames in
src/i18n/config.ts. Keep English as the default. The selector, validation,
and request loader read that shared list and matching file name; no new URL
prefix, environment variable, provider, or database column is needed.
Run the normal unit checks after catalog edits, then the focused local dashboard browser check:
bun run test
./coremvp e2e dashboard:i18nKeep your normal local app and Supabase running for the browser check. It uses a temporary local account and checks saved English/French selection in the actual dashboard and the shared demo pages. New languages need your own translation review and browser checks; passing catalog syntax checks does not prove their wording or every screen state.
The saved preference translates the dashboard interface. Public landing, pricing, Auth, Docs, and Blog pages retain their current language. The landing page's embedded dashboard preview also stays English. Database content, user names, provider messages, Stripe amounts/currencies, permissions, and access state retain their existing values.
For a new public page with a distinct URL per language, use the optional showcase below as the routing example: it keeps separate catalogs and explicit URL locales. Translating existing MDX articles requires translated source files as well as interface messages.
The separate examples/i18n showcase demonstrates translated Overview,
Landing, Pricing, Dashboard, and Documentation previews. It is disabled by
default. Its activation switch enables only /i18n/**; the actual dashboard
language menu works independently.
Start from a template checkout with dependencies installed and Docker running.
./coremvp feature enable i18nThis command changes only examples/i18n/config.json. Run ./coremvp feature status i18n at any time to inspect the feature state.
bunx supabase start
./coremvp env syncThe showcase uses the same supported local runtime as the rest of the template. It does not add another app or deployment.
bun run devOpen http://localhost:3000/i18n. Use the language select to switch between English and French while staying on the same preview page.
Keep the app running, then use another terminal:
./coremvp e2e i18nThe focused browser test checks the English-default routes, French content, locale-aware formatting, invalid-route boundaries, and unchanged sibling routes.
All editable example code stays together:
Edit the message catalogs for interface copy. Edit the two MDX files for the documentation preview. The example components and pages show how a route-local use-intl translator, native locale-preserving Router links, and Intl formatting fit together.
The default English URLs do not include a locale segment:
| Preview | English | French |
|---|---|---|
| Overview | /i18n | /i18n/fr |
| Landing | /i18n/landing | /i18n/fr/landing |
| Pricing | /i18n/pricing | /i18n/fr/pricing |
| Dashboard | /i18n/dashboard | /i18n/fr/dashboard |
| Documentation preview | /i18n/documentation | /i18n/fr/documentation |
This optional showcase reads explicit URL locales, rather than the saved dashboard preference. It has a fixed English/French pair, separate message catalogs, and separate MDX sources. Dashboard catalog edits do not add showcase routes. Its pages emit noindex, have no canonical or hreflang links, and stay out of the sitemap.
Neither the showcase nor a translated dashboard changes Supabase Auth, Stripe prices, billing, tax, or access state. Use the showcase to inspect public-page and MDX patterns; define the languages, content, routing, and search metadata separately for public pages you add.