---
id: w5/m3/t004
title: Extract app strings into feature locales
worker: worker5
status: done
estimate: 75m
depends_on: [w5/m3/t001]
---

## Objective

Replace the dashboard's hardcoded English strings with `t()` calls backed by
namespaced feature locale files. This is the "make bex's own UI localizable"
half of the milestone (Ory's forms are t005).

## Context

- The scaffold "ships hardcoded English strings" (`dashboard/CLAUDE.md`). The
  string surface is small and enumerable:
  - `src/common/components/dashboard-layout/{index.tsx,dashboard-sidebar.tsx}` — nav labels, header.
  - `src/routes/index.tsx` — sample "Services" page copy.
  - `src/features/auth/pages/*/index.tsx` + `auth-page-shell` — hero titles/subtitles
    ("Welcome back", "Sign in to your account", feature bullets). NOTE: only the
    **bex-authored** copy around the Ory card; the Ory card's own fields are t005.
  - `src/features/metrics/**` — metrics page labels.
  - `src/common/root-route/{not-found-page,error-page}.tsx` — 404 / error copy.
  - `src/routes/settings.tsx` page heading.
- Follow the reference's namespacing: `common.*`, `auth.*`, `metrics.*`,
  `services.*` (or `dashboard.*`). Each key is a `TranslationEntry`
  (`message` + `description`) in `src/features/<feature>/locales/en.ts` (or
  `src/common/locales/en.ts` for shared), aggregated per t001.

## Steps

1. Walk the files above; for each user-visible literal, add a namespaced key to
   the appropriate `locales/en.ts` and replace the literal with `t("...")`.
2. Create `locales/en.ts` under `src/features/{auth,metrics}/` and any new
   `common` keys; register them in the aggregation layer (t001's `index.ts`).
3. Keep interpolation values (counts, names) as `t(key, { ... })` params, not
   string concatenation.
4. Grep for remaining bare literals in the touched files to confirm coverage.

## Files

- `dashboard/src/common/locales/en.ts`
- `dashboard/src/features/auth/locales/en.ts`
- `dashboard/src/features/metrics/locales/en.ts`
- `dashboard/src/i18n/index.ts` (register new namespaces)
- `dashboard/src/common/components/dashboard-layout/*`, `src/routes/index.tsx`,
  `src/features/auth/pages/*`, `src/features/auth/components/auth-page-shell/*`,
  `src/features/metrics/*`, `src/common/root-route/{not-found,error}-page.tsx`,
  `src/routes/settings.tsx`

## Acceptance criteria

- [ ] No user-visible hardcoded English literal remains in the listed files
      (spot-checked by grep); all render via `t()`.
- [ ] Keys are namespace-prefixed and present in the `en` resources.
- [ ] UI is visually unchanged in English (behavior-preserving extraction).
- [ ] `yarn typecheck` / `yarn lint` / `yarn test` pass.

## Out of scope

- Non-English translations (t006 seeds `zh`).
- Strings rendered by `@ory/elements-react` itself (t005).
</content>
