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>
9.8 KiB
Feature Specification: Multi-Language Support
Feature Branch: 001-multi-language
Created: 2026-03-09
Status: Draft
Input: User description: "Implement multi-language support for the site"
User Scenarios & Testing (mandatory)
User Story 1 - Browse Site in Ukrainian (Priority: P1)
A Ukrainian-speaking visitor arrives at the AImpress website. They see a language toggle in the header (which already exists visually but is non-functional) and switch from English to Ukrainian. All static page content — headings, descriptions, navigation labels, button text, form labels, and footer — immediately updates to Ukrainian. The visitor can browse the full site in their preferred language without any page reload.
Why this priority: The language toggle already exists in the UI ("Eng"/"Ukr"), so users already expect this functionality. Delivering Ukrainian translations for static content is the foundational slice that enables the entire multi-language experience.
Independent Test: Can be fully tested by clicking the language toggle in the header and verifying all visible text on every page section changes to Ukrainian. Delivers immediate value to Ukrainian-speaking visitors.
Acceptance Scenarios:
- Given a visitor on the English site, When they click the language toggle to "Ukr", Then all static text on the current page displays in Ukrainian without a page reload.
- Given a visitor browsing in Ukrainian, When they navigate to a different page section, Then the new section also displays in Ukrainian.
- Given a visitor browsing in Ukrainian, When they switch back to "Eng", Then all text reverts to English.
User Story 2 - Submit Forms in Preferred Language (Priority: P2)
A visitor browsing in Ukrainian wants to submit the contact form or interact with the chatbot lead form. All form labels, placeholders, validation messages, and success/error messages appear in Ukrainian. The submitted form data is stored as-is (in whichever language the user typed), but system-generated labels and messages display in the selected language.
Why this priority: Forms are the primary conversion point. If a Ukrainian visitor sees a translated page but English-only forms, the experience feels incomplete and may reduce conversions.
Independent Test: Can be tested by switching to Ukrainian, opening the contact form, verifying all labels/placeholders are in Ukrainian, submitting with invalid data to check validation messages, and submitting successfully to verify the success message is in Ukrainian.
Acceptance Scenarios:
- Given a visitor browsing in Ukrainian, When they open the contact form, Then all form labels, placeholders, and the submit button display in Ukrainian.
- Given a visitor submitting a form in Ukrainian, When validation fails, Then error messages appear in Ukrainian.
- Given a visitor submitting a form in Ukrainian, When submission succeeds, Then the success confirmation message appears in Ukrainian.
- Given a visitor using the chatbot lead form in Ukrainian, When they see the lead capture form, Then all labels, placeholders, and consent text display in Ukrainian.
User Story 3 - Language Preference Persistence (Priority: P3)
A visitor selects Ukrainian as their language. When they return to the site later or refresh the page, the site remembers their preference and displays in Ukrainian automatically. New visitors see the site in a default language based on reasonable defaults (English as fallback).
Why this priority: Without persistence, users must re-select their language on every visit, creating friction. This is important for repeat visitors but not as critical as the initial translation itself.
Independent Test: Can be tested by selecting Ukrainian, closing the browser tab, reopening the site, and verifying the language is still set to Ukrainian.
Acceptance Scenarios:
- Given a visitor who previously selected Ukrainian, When they return to the site, Then the site loads in Ukrainian automatically.
- Given a first-time visitor, When they load the site, Then the site displays in English by default.
- Given a visitor who clears their browser data, When they return to the site, Then the site displays in English (default).
User Story 4 - Chatbot Conversations in Preferred Language (Priority: P4)
A visitor browsing in Ukrainian opens the AI chatbot. The chatbot greeting, system messages, and AI responses are in Ukrainian. The chatbot understands and responds in the language the visitor is using.
Why this priority: The chatbot is a key engagement tool but involves backend AI integration. The static UI elements (greeting, status text, input placeholder) should match the selected language, and the AI should respond in the same language the user writes in.
Independent Test: Can be tested by switching to Ukrainian, opening the chatbot, verifying the greeting and UI elements are in Ukrainian, and sending a message in Ukrainian to verify the AI responds in Ukrainian.
Acceptance Scenarios:
- Given a visitor browsing in Ukrainian, When they open the chatbot, Then the greeting message, status text, and input placeholder display in Ukrainian.
- Given a visitor chatting in Ukrainian, When they send a message in Ukrainian, Then the AI responds in Ukrainian.
- Given a visitor who switches language mid-conversation, When they switch from Ukrainian to English, Then new chatbot UI elements update to English (existing messages remain as-sent).
Edge Cases
- What happens when a translation is missing for a specific string? The system falls back to English for that string.
- What happens when a visitor's browser language is Ukrainian but they haven't explicitly chosen a language? The site defaults to English (explicit selection required via toggle).
- How does the system handle right-to-left languages? Out of scope for this feature — only English and Ukrainian are supported.
- What happens to the cookie consent banner when language changes? It updates to the selected language like all other static content.
- What happens to blog post content when language is switched? Blog article titles and body content remain in English. Only the surrounding blog UI (section title, "View All Posts" link, date formatting) translates to the selected language.
- What happens to date formatting when language changes? Dates display in the locale matching the selected language (e.g., "March 9, 2026" vs "9 березня 2026").
Requirements (mandatory)
Functional Requirements
- FR-001: System MUST provide a functional language toggle in the header that switches between English and Ukrainian.
- FR-002: System MUST translate all static UI text (navigation, headings, descriptions, button labels, footer text) to the selected language.
- FR-003: System MUST translate all form labels, placeholders, validation messages, and success/error messages to the selected language.
- FR-004: System MUST translate chatbot UI elements (greeting, status, placeholder, system messages) to the selected language.
- FR-005: System MUST persist the visitor's language preference across browser sessions.
- FR-006: System MUST default to English for first-time visitors.
- FR-007: System MUST fall back to English for any missing translation string.
- FR-008: System MUST update all visible text instantly when the language is toggled, without requiring a page reload.
- FR-009: System MUST format dates according to the selected language's locale conventions.
- FR-010: System MUST pass the selected language context to the chatbot so AI responses match the visitor's language.
- FR-011: System MUST translate the cookie consent banner text when language changes.
- FR-012: System MUST translate page titles, meta descriptions, and OpenGraph tags to the selected language for proper search engine indexing.
Key Entities
- Language: A supported language with a code (e.g., "en", "uk"), display name, and flag/label for the toggle.
- Translation: A key-value mapping of translation keys to translated strings, organized by language.
- Language Preference: The visitor's stored language selection, persisted locally in the browser.
Success Criteria (mandatory)
Measurable Outcomes
- SC-001: 100% of static UI text across all page sections displays correctly in both English and Ukrainian.
- SC-002: Visitors can switch languages in under 1 second with no visible page reload or layout shift.
- SC-003: Language preference persists across at least 5 consecutive return visits.
- SC-004: 100% of form labels, placeholders, and messages display in the selected language.
- SC-005: The chatbot greets users and displays UI elements in the selected language on first open.
- SC-006: Missing translations gracefully fall back to English with no visible errors or broken UI.
Assumptions
- Only two languages are in scope: English (default) and Ukrainian. Additional languages may be added in the future but are not part of this feature.
- The existing language toggle UI in the Header component ("Eng"/"Ukr") will be reused and made functional.
- Blog post body content stays in English. Only the surrounding blog UI (section titles, navigation, dates) will be translated.
- The chatbot AI (Claude Sonnet) already supports Ukrainian — no backend model changes are needed to respond in Ukrainian. The system prompt may need a language hint.
- URL structure will not change for different languages (no
/en/or/uk/path prefixes). Language is client-side state only. - Analytics event names remain in English regardless of UI language.
- SEO meta tags and page titles should also be translated for proper indexing in Ukrainian search engines.