Aimpress_site/specs/001-multi-language/tasks.md
Vadym Samoilenko 6e932d76e4 Add multi-language support (EN/UK) across entire site
Custom i18n system with typed translation dictionaries (~570 keys),
LanguageProvider context, and useTranslation hook. All 31 components
and pages wired with t() calls. Chatbot backend passes language hint
to Claude for Ukrainian responses. Language preference persists via
localStorage. SEO meta tags and html lang attribute update dynamically.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 13:32:04 +00:00

13 KiB
Raw Blame History

Tasks: Multi-Language Support (EN/UK)

Input: Design documents from /specs/001-multi-language/ Prerequisites: plan.md, spec.md, research.md, data-model.md, quickstart.md

Tests: Not requested — no test tasks included.

Organization: Tasks are grouped by user story to enable independent implementation and testing of each story.

Format: [ID] [P?] [Story] Description

  • [P]: Can run in parallel (different files, no dependencies)
  • [Story]: Which user story this task belongs to (e.g., US1, US2, US3)
  • Include exact file paths in descriptions

Phase 1: Setup (Shared Infrastructure)

Purpose: Create the i18n module and translation files

  • T001 Create Translations interface with all translation keys in src/i18n/types.ts
  • T002 Create English translations object (source of truth) in src/i18n/en.ts — extract all ~200 hardcoded strings from every component into dot-separated keys (e.g., header.nav.home, hero.title, contact.form.fullName). Must satisfies Translations.
  • T003 Create Ukrainian translations object in src/i18n/uk.ts — translate all keys from en.ts into Ukrainian. Must satisfies Translations.
  • T004 Create LanguageProvider context and useTranslation hook in src/i18n/LanguageContext.tsx — state initialized from localStorage.getItem('aimpress_lang') || 'en', setLang updates state + localStorage + document.documentElement.lang, t(key) resolves against current language dict with English fallback.
  • T005 Create barrel export in src/i18n/index.ts

Phase 2: Foundational (Blocking Prerequisites)

Purpose: Wire LanguageProvider into the app and connect the Header toggle

CRITICAL: No user story work can begin until this phase is complete

  • T006 Wrap <App> with <LanguageProvider> inside the existing <HelmetProvider> in src/main.tsx
  • T007 Wire the existing Header language toggle to the i18n context in src/components/Header.tsx — remove local currentLang state, import useTranslation, map setLang('en')/setLang('uk') to toggle clicks, derive display label ("Eng"/"Ukr") from context lang value

Checkpoint: Language toggle is functional — clicking Eng/Ukr updates lang in context and localStorage. No visible text changes yet.


Phase 3: User Story 1 — Browse Site in Ukrainian (Priority: P1) MVP

Goal: All static homepage text displays in the selected language when the toggle is clicked.

Independent Test: Click the language toggle in the header → verify all visible text on every homepage section changes to Ukrainian without page reload. Click back to English → verify all text reverts.

Implementation for User Story 1

  • T008 [US1] Replace hardcoded nav item names with t() calls in src/components/Header.tsx — move navItems array inside component body to use hook, translate login form strings
  • T009 [P] [US1] Replace hardcoded title and CTA button text with t() calls in src/components/Hero.tsx
  • T010 [P] [US1] Replace flip card titles/subtitles/back text, "Built for" section, and static card titles/descriptions with t() calls in src/components/Benefits.tsx — move data arrays inside component body
  • T011 [P] [US1] Replace questions array and CTA button text with t() calls in src/components/Banner1.tsx
  • T012 [P] [US1] Replace section title and result descriptions with t() calls in src/components/RealResults.tsx
  • T013 [P] [US1] Replace section title, step titles, durations, descriptions, and details with t() calls in src/components/Timeline.tsx — move timeline steps array inside component body
  • T014 [P] [US1] Replace questions and CTA button text with t() calls in src/components/Banner2.tsx
  • T015 [P] [US1] Replace section title, metric labels/values, alternative names, and footer text with t() calls in src/components/ComparisonTable.tsx — move comparison data inside component body
  • T016 [P] [US1] Replace "Recent Updates" title, "View All Posts" link text with t() calls, and update date locale from hardcoded 'en-US' to lang === 'uk' ? 'uk-UA' : 'en-GB' in src/components/BlogSection.tsx
  • T017 [P] [US1] Replace section title and UI text with t() calls in src/components/ResourcesSection.tsx
  • T018 [P] [US1] Replace heading and subtitle with t() calls in src/components/ContactSection.tsx
  • T019 [P] [US1] Replace copyright text and link labels with t() calls in src/components/Footer.tsx
  • T020 [P] [US1] Replace banner text and button labels with t() calls in src/components/CookieConsent.tsx

Checkpoint: All homepage static text switches between English and Ukrainian via the Header toggle. MVP deliverable.


Phase 4: User Story 2 — Submit Forms in Preferred Language (Priority: P2)

Goal: Contact form, chatbot lead form — all labels, placeholders, validation messages, and success/error messages display in the selected language.

Independent Test: Switch to Ukrainian → open contact form → verify all labels/placeholders are in Ukrainian → submit with invalid data → verify validation messages in Ukrainian → submit successfully → verify success message in Ukrainian. Repeat for chatbot lead form.

Implementation for User Story 2

  • T021 [P] [US2] Replace form title, labels ("Full Name", "Job Title / Role", "Work Email", etc.), placeholders, submit button text ("Submit a request" / "Sending..."), success message, and validation error messages with t() calls in src/components/ContactForm.tsx
  • T022 [P] [US2] Replace chatbot lead form labels ("Your name *", "Email *", "Company (optional)"), placeholders, consent text ("I agree to the processing..."), and button text with t() calls in src/components/ChatLeadForm.tsx
  • T023 [P] [US2] Replace quote form labels and placeholders with t() calls in src/components/QuoteForm.tsx

Checkpoint: All forms display labels, placeholders, validation, and success messages in the selected language.


Phase 5: User Story 3 — Language Preference Persistence (Priority: P3)

Goal: Selected language persists across browser sessions via localStorage.

Independent Test: Select Ukrainian → close tab → reopen site → verify it loads in Ukrainian. Clear browser data → reopen → verify English default.

Implementation for User Story 3

  • T024 [US3] Verify and ensure LanguageContext.tsx reads from localStorage on initialization in src/i18n/LanguageContext.tsx — confirm useState initializer reads localStorage.getItem('aimpress_lang'), confirm setLang writes to localStorage, confirm document.documentElement.lang is set on mount
  • T025 [US3] Verify the Header toggle correctly reflects the persisted language on page load in src/components/Header.tsx — ensure the toggle display ("Eng"/"Ukr") matches the stored preference, not a hardcoded default

Checkpoint: Language preference persists across page refreshes and browser sessions.


Phase 6: User Story 4 — Chatbot Conversations in Preferred Language (Priority: P4)

Goal: Chatbot UI displays in the selected language and AI responds in the matching language.

Independent Test: Switch to Ukrainian → open chatbot → verify greeting, status text ("Online"), and input placeholder are in Ukrainian → send a message → verify AI responds in Ukrainian.

Implementation for User Story 4

  • T026 [P] [US4] Replace greeting text with t() call in src/components/ChatBubble.tsx
  • T027 [P] [US4] Replace "Online" status text, welcome message with t() calls in src/components/ChatWindow.tsx
  • T028 [P] [US4] Replace "Type a message..." placeholder with t() call in src/components/ChatInput.tsx
  • T029 [US4] Pass lang from useTranslation() context to the useChat hook in src/components/ChatWidget.tsx — pass as parameter to useChat
  • T030 [US4] Add language field to the request body sent to /api/chat in src/hooks/useChat.ts — accept lang parameter, include language: lang in fetch body
  • T031 [US4] Add language: str = "en" field to ChatRequest model in chatbot-api/models.py
  • T032 [US4] Prepend language hint to messages when req.language == "uk" in chatbot-api/main.py — add synthetic user/assistant message pair before the conversation to guide Claude to respond in Ukrainian

Checkpoint: Chatbot UI is fully translated and AI responds in the selected language.


Phase 7: Polish & Cross-Cutting Concerns

Purpose: SEO, subpage translations, and final verification

  • T033 [P] [US1] Replace all hardcoded text (hero, story, differentiators, values, founder bio, industries, CTA) with t() calls in src/pages/AboutPage.tsx — move data arrays (differentiators, values, industries) inside component body
  • T034 [P] [US1] Replace service titles, descriptions, includes list, and CTA with t() calls in src/pages/ServicesPage.tsx
  • T035 [P] [US1] Replace pricing labels, tier names, feature lists, and CTA with t() calls in src/pages/PricingPage.tsx
  • T036 [P] [US1] Replace page title and UI chrome with t() calls in src/pages/BlogPage.tsx — update date locale
  • T037 [P] [US1] Replace "Back to blog" link text with t() call and update date formatting locale in src/pages/BlogPostPage.tsx
  • T038 Add <html lang={lang}> via Helmet and pass translated SEO title/description to each page's <SEO> component — update SEO component to accept lang, add seo.* translation keys for all pages
  • T039 Visual review of all pages in Ukrainian — check for text overflow, broken layouts, or missing translations. Fix any CSS issues caused by longer Ukrainian text (buttons, nav items, cards).
  • T040 Run quickstart.md validation — verify the developer workflow (adding a new key, using t() in a component, date formatting) works as documented

Dependencies & Execution Order

Phase Dependencies

  • Setup (Phase 1): No dependencies — can start immediately
  • Foundational (Phase 2): Depends on Phase 1 completion — BLOCKS all user stories
  • User Stories (Phases 3-6): All depend on Phase 2 completion
    • US1 (Phase 3): No dependencies on other stories
    • US2 (Phase 4): No dependencies on other stories (forms are separate components)
    • US3 (Phase 5): Largely verification — persistence is built into Phase 2's LanguageContext
    • US4 (Phase 6): No dependencies on other stories (chatbot is separate component tree)
  • Polish (Phase 7): Depends on Phase 2 completion (can run in parallel with user stories, but best after US1)

User Story Dependencies

  • US1 (P1): After Phase 2 — no cross-story dependencies
  • US2 (P2): After Phase 2 — no cross-story dependencies
  • US3 (P3): After Phase 2 — verification only (persistence built into LanguageContext)
  • US4 (P4): After Phase 2 — no cross-story dependencies, but includes backend changes

Parallel Opportunities

  • T009T020 (US1 homepage components): ALL parallelizable — different files, no dependencies
  • T021T023 (US2 forms): ALL parallelizable — different files
  • T026T028 (US4 chat UI): ALL parallelizable — different files
  • T033T037 (Polish subpages): ALL parallelizable — different files
  • US1, US2, US4 can all proceed in parallel after Phase 2

Parallel Example: User Story 1

# After Phase 2 is complete, launch all homepage component translations in parallel:
Task: "T009 — Replace text in Hero.tsx"
Task: "T010 — Replace text in Benefits.tsx"
Task: "T011 — Replace text in Banner1.tsx"
Task: "T012 — Replace text in RealResults.tsx"
Task: "T013 — Replace text in Timeline.tsx"
Task: "T014 — Replace text in Banner2.tsx"
Task: "T015 — Replace text in ComparisonTable.tsx"
Task: "T016 — Replace text in BlogSection.tsx"
Task: "T017 — Replace text in ResourcesSection.tsx"
Task: "T018 — Replace text in ContactSection.tsx"
Task: "T019 — Replace text in Footer.tsx"
Task: "T020 — Replace text in CookieConsent.tsx"

Implementation Strategy

MVP First (User Story 1 Only)

  1. Complete Phase 1: Create i18n module + translation files (T001T005)
  2. Complete Phase 2: Wire provider + Header toggle (T006T007)
  3. Complete Phase 3: Translate all homepage components (T008T020)
  4. STOP and VALIDATE: Toggle language, verify all homepage text switches
  5. Deploy/demo if ready

Incremental Delivery

  1. Phase 1 + 2 → Foundation ready
  2. Add US1 (homepage) → Test → Deploy (MVP!)
  3. Add US2 (forms) → Test → Deploy
  4. Add US3 (persistence verification) → Test → Deploy
  5. Add US4 (chatbot) → Test → Deploy
  6. Polish (subpages + SEO) → Final deploy

Notes

  • [P] tasks = different files, no dependencies
  • [Story] label maps task to specific user story for traceability
  • Translation files (T002, T003) are the most labor-intensive tasks — ~200 keys each
  • Ukrainian translations should be reviewed by a native speaker before final deploy
  • Privacy Policy and Terms of Use pages remain English-only (legal review needed for translation)
  • Analytics event names stay in English regardless of UI language