Skip to content

Add language auto-detection from browser Accept-Language header #804

Description

@Mystery-CLI

Background

FuTuRe supports multiple display languages and provides a LanguageSelector.jsx component that allows users to manually choose their preferred language. However, on first visit the application always defaults to English regardless of the language configured in the user's browser. This means users whose browsers are set to French, German, Spanish, Portuguese, or any other supported language must manually find and change the language selector before they can use the application comfortably.

Problem

Defaulting to English regardless of browser configuration is a poor experience for non-English speakers:

  • Immediate disorientation. A user whose browser and device are configured for German is presented with a fully English interface the moment they open FuTuRe. This creates an immediate trust barrier, particularly in financial applications where users must read and understand information accurately.
  • Discovery friction. Not all users know to look for a language selector. Users who do not notice it may abandon the application or assume it does not support their language.
  • Inconsistency with browser expectations. Every major web application (Gmail, Stripe, banking portals) auto-detects the browser language on first visit. FuTuRe's failure to do so feels like a bug rather than a design decision.
  • Wasted translation effort. The team invests in translating the application into multiple languages, but the value of this investment is reduced when users never discover that translations exist.
  • Retention risk. Users who find the application difficult to use due to a language barrier in their first session are unlikely to return.

Proposed Solution

Read the browser's preferred language from the Accept-Language-equivalent client-side API on first visit and use it to pre-select the display language in LanguageSelector.jsx.

The implementation should:

  1. On application initialisation (before rendering), check localStorage for a user-saved language preference.
  2. If no preference is saved, read the browser's language preference from navigator.language (and optionally navigator.languages for the full preference list).
  3. Match the browser's preferred language against the list of languages the application supports. Use the primary language subtag if an exact locale match is not available (e.g. map fr-CA to fr if only fr is supported).
  4. Fall back to English if the browser language is not in the supported list.
  5. Set the detected language as the initial i18n locale.
  6. When the user manually changes the language using LanguageSelector.jsx, save the selection to localStorage so it persists across sessions and is used in preference to the auto-detected value on subsequent visits.

Implementation Steps

  1. Create a frontend/src/utils/detectLanguage.js utility that encapsulates the browser language detection and matching logic.
  2. Update the i18n initialisation code to call detectLanguage before setting the default locale.
  3. Update LanguageSelector.jsx to persist the user's manual selection to localStorage.
  4. Add unit tests for detectLanguage covering exact match, subtag match, unsupported language, and stored preference scenarios.

Acceptance Criteria

  • A user whose browser is configured for a supported language sees that language on first visit without any manual configuration.
  • A user whose browser language is not supported sees English.
  • A manually selected language persists across page reloads and new sessions.
  • The manual selection takes precedence over the browser auto-detection on subsequent visits.
  • The auto-detection logic correctly maps language subtags (e.g. es-419es).

Notes

navigator.language reflects the user's primary browser language. navigator.languages returns the full ordered preference list, which may be useful for finding a supported match further down the list. Avoid reading the Accept-Language HTTP header server-side for this feature, as it adds server complexity for a behaviour that can be handled entirely client-side.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions