# Internationalization

Portuguese, English and German UI with request-scoped SSR translation.

## Catalog ownership [#catalog-ownership]

Web catalogs live in `apps/web/src/locales/{pt,en,de}.ts`. `MessageKey` derives from English; the other catalogs must retain key and interpolation parity. Shared error translations come from `packages/errors/src/locales`. Mobile maintains its own app catalogs (`pt-BR`, `en`, `de`).

Use `useTranslation` in components and hooks. Format dates and numbers with Intl. Do not concatenate translated fragments when the sentence needs different word order.

## Server rendering [#server-rendering]

`getSSRLanguage` checks a validated `?lang=` first, then the locale cookie, then the fallback. `getRequestI18n` clones the i18next instance for that request while sharing loaded catalogs. Mutating one global language during SSR would make concurrent requests affect each other.

Each catalog is its own chunk. The Worker loads all three before its first render (`src/server.ts`); the browser fetches only the languages the page was rendered in, the `<html lang>` and any page-scoped `lang` such as a passport's, before it hydrates (`src/client.tsx`). Switching language loads the new catalog first (`loadLanguage`). Never import `@/locales/*` statically from client code: `scripts/assert-locale-chunks.mjs` fails the build when two catalogs share a chunk.

The client keeps its shared instance and updates the document language after a switch. Public localized pages advertise locale alternates. Developer articles are English only: their article region has `lang="en"`, their chrome is translated, and their sitemap entries have no hreflang alternates.

## Extend [#extend]

Add a message to Portuguese, English and German together. Preserve placeholder names and run the locale parity tests. A new language also needs the supported-language definition, formatters, SEO mappings and native catalogs updated. Translate the domain consistently: a Todo's translated label can differ from its code identifier.

## Key files [#key-files]

- [`packages/intl/src/i18n.ts`](https://github.com/CarlosZiegler/autofolio/blob/main/packages/intl/src/i18n.ts)
- [`packages/intl/src/server.ts`](https://github.com/CarlosZiegler/autofolio/blob/main/packages/intl/src/server.ts)
- [`apps/web/src/platform/i18n/intl.ts`](https://github.com/CarlosZiegler/autofolio/blob/main/apps/web/src/platform/i18n/intl.ts)
- [`apps/web/src/client.tsx`](https://github.com/CarlosZiegler/autofolio/blob/main/apps/web/src/client.tsx)
- [`apps/web/src/locales/en.ts`](https://github.com/CarlosZiegler/autofolio/blob/main/apps/web/src/locales/en.ts)
- [`apps/mobile/src/platform/i18n/i18n.ts`](https://github.com/CarlosZiegler/autofolio/blob/main/apps/mobile/src/platform/i18n/i18n.ts)

