Skip to content

🎃 Set up i18n in the frontend and translate the sidebar and sign-in form (DE, IT) #1008

Open

Description

@helpcodeai

Part of the October Challenge #997.

Why

The website guides and the README already exist in German and Italian (content/guides/de, content/guides/it, README.de.md), but the admin UI is English only. Every string is hard-coded in JSX, <html lang="en"> is fixed (app/layout.tsx:72), and there is no i18n library. The only translated UI is the cookie banner (components/cookie-consent.tsx:37-391, browser language detection at :424-426), which only renders when GTM is configured. Teams whose staff work in German or Italian have to put up with an English admin UI, and adding a language later gets harder with every new page.

This issue lays the foundation and proves it on two surfaces: the sidebar and the sign-in form. Other pages follow in separate issues, one area at a time.

Self-hosted vs Cloud

  • Self-hosted: same in Community and Business. Frontend only: no backend or database change, no ee/ code.
  • Cloud (DEPLOYMENT_MODE=cloud): same image, same behaviour. The language is a per-browser preference stored in a cookie, not a workspace or instance setting, so members of one workspace can use different languages.
  • Who can use it: everyone, including signed-out visitors on /login.

What to build

  1. Library: next-intl in its "without i18n routing" setup. Reasons: it supports the App Router with server and client components, ICU messages (plurals such as "1 tool" / "3 tools") and typed message keys. Without routing there are no /de/... URL prefixes, so the auth gate in proxy.ts, the backend rewrites in next.config.ts and every ?redirect= link keep working unchanged. Almost every page is a client component, so the messages are passed once through NextIntlClientProvider in the root layout. Before you start, check that the current next-intl release supports the next version in packages/frontend/package.json (16.x) and name the version in the PR. This Next.js version has breaking changes (see packages/frontend/AGENTS.md), so read the docs it ships in node_modules/next/dist/docs/ as well. If next-intl does not fit, comment here before building an alternative.
  2. Locale resolution (server side): the cookie amcp_locale if it holds a supported locale, otherwise the best match from Accept-Language, otherwise en. Supported: en, de, it. Set <html lang> from it in app/layout.tsx:72. The root layout is already force-dynamic (:58), so reading the cookie per request costs nothing extra. app/global-error.tsx:30 can stay en.
  3. Messages: packages/frontend/messages/{en,de,it}.json, nested by area (nav.*, signIn.*). English is the source. A key missing in de or it falls back to English and never shows a raw key.
  4. Sidebar (components/app-sidebar.tsx): the group titles and item labels in NAV (:45-73), "Switch workspace" (:156), "Log out" (:188), "Settings" (:205), the "Workspace" fallback (:216) and the "Star on GitHub" texts (components/github-star-button.tsx:54-60). hrefs and the active-item logic stay as they are.
  5. Sign-in form (app/login/page.tsx:851-1144, sign-in mode only, !isRegister): heading, labels, placeholders, the submit button states, "Forgot password?", the recovery-code texts, the "or" divider, "Don't have an account? Register", "Email verified successfully!…", "Signing you in…", and the client-side messages shown in this mode. The registration and Cloud sign-up variants and the verification and licence steps stay English in this issue.
  6. Language switcher: a select (English, Deutsch, Italiano) in Settings → Profile (app/settings/page.tsx) and a small one under the sign-in card. It writes the cookie (one year, SameSite=Lax, Path=/) and calls router.refresh().
  7. Translations: match the tone of the existing German and Italian guides in content/guides/de and content/guides/it. If you are not a native speaker of one of the languages, say so in the PR so a maintainer can review those strings.
  8. Contributor note: a short "Translating the UI" section in .github/CONTRIBUTING.md: where the messages live, how to add a key, English is the source.

Where to look

  • packages/frontend/src/app/layout.tsx:51-89: root layout (force-dynamic, <html lang>).
  • packages/frontend/src/app/providers.tsx: client providers to wrap.
  • packages/frontend/src/proxy.ts: auth gate and public paths; must keep working unchanged.
  • packages/frontend/src/components/app-sidebar.tsx:45-73, :156, :188, :205, :216.
  • packages/frontend/src/app/login/page.tsx:851-1144: the auth form.
  • packages/frontend/src/components/cookie-consent.tsx:37-391, :424-426: the banner's own translations (leave them as they are).
  • packages/frontend/src/lib/translation-safe-dom.ts: keeps browser page translation from crashing React; keep it.
  • packages/frontend/tests/e2e/: many tests match English text, so English must stay the result for Accept-Language: en-US, Playwright's default.

Acceptance criteria

  • Without the cookie, Accept-Language: de-DE renders /login and the sidebar in German with <html lang="de">; it-IT gives Italian; fr-FR gives English.
  • A language chosen in Settings persists across reloads and sign-out.
  • Playwright tests for the cases above (test.use({ locale: 'de-DE' })), plus a key-parity test that loads the three JSON files and fails when de or it misses or adds a key. All existing tests pass unchanged (cd packages/frontend && npm run test:e2e).
  • URLs are unchanged: login-redirect-query.spec.ts and login-redirect-safe.spec.ts pass.
  • npm run lint, npx tsc --noEmit -p tsconfig.json and npm run build pass in packages/frontend.
  • Screenshots of the sidebar and the sign-in form in German and Italian in the PR.

Out of scope

  • Other pages (follow-up issues), the backend-rendered OAuth sign-in and consent pages (packages/backend/src/auth/auth-page.ts), emails and API error messages.
  • Locale-prefixed URLs, right-to-left languages, languages other than German and Italian.
  • Storing the language on the user account.
  • Changing date or number formatting.

Size

L (several days, may be split: library, locale resolution and sidebar first; sign-in form and switcher second).

How to claim

Comment "I'd like to work on this" and we'll assign you. Rules in #997.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesthacktoberfestGood for Hacktoberfest contributorshelp wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions