Bridge Training
i18n

Components

Ready-to-use React components for language selection and suggestion.

Import from @workspace/i18n/components.

LanguageSelect

A dropdown for selecting a language, built on the shared Select component from @workspace/ui.

import { LanguageSelect } from '@workspace/i18n/components';
import { getLanguageSelectorOptions } from '@workspace/i18n/validation';

const SUPPORTED = ['fr', 'en'] as const;
const languages = getLanguageSelectorOptions(SUPPORTED);

<LanguageSelect
  languages={languages}
  value={currentLang}
  onValueChange={setLanguage}
/>

Demo

Display Modes

The display prop controls what appears in the trigger button:

// Default — shows language name
<LanguageSelect display="label" ... />

// Globe icon only (label is sr-only for accessibility)
<LanguageSelect display="icon" ... />

// Both icon and language name
<LanguageSelect display="icon-and-label" ... />

Props

PropTypeDefaultDescription
languagesreadonly LanguageSelectorOption<T>[]Available languages. Use getLanguageSelectorOptions() to generate
valueTCurrently selected language code
onValueChange(value: T) => voidCallback when language changes
display"label" | "icon" | "icon-and-label""label"What to display in the trigger
placeholderstringPlaceholder text when no value
disabledbooleanDisables the select
classNamestringAdditional class for the trigger
idstringID for form labels
aria-labelstring"Select language"Accessible label

LanguageBanner

A banner that suggests switching to the user's preferred language, detected via detectPreferredLanguage.

import { LanguageBanner } from '@workspace/i18n/components';
import { ALL_LANGUAGE_CODES } from '@workspace/i18n/constants';

// URL-based routing (apps/web)
<LanguageBanner
  currentLanguage={locale}
  supportedLanguages={ALL_LANGUAGE_CODES}
  onSwitchLanguage={(lang) => router.push(`/${lang}${pathname.slice(3)}`)}
/>

// i18next-based (apps/app)
<LanguageBanner
  currentLanguage={i18n.language as 'fr' | 'en'}
  supportedLanguages={['fr', 'en']}
  onSwitchLanguage={(lang) => i18n.changeLanguage(lang)}
/>

Behavior

  1. Compares currentLanguage with detectPreferredLanguage(supportedLanguages, currentLanguage)
  2. If different, displays the banner suggesting the detected language
  3. Switch button — calls onSwitchLanguage(detectedLanguage), label is shown in the suggested language
  4. Stay button — saves preference to localStorage (won't show again), calls onStayInCurrentLanguage
  5. Dismiss (X) button — closes without saving (banner reappears on next visit)

Demo

Current: English — The banner suggests switching to French.

Custom Labels

<LanguageBanner
  currentLanguage="en"
  supportedLanguages={['fr', 'en']}
  onSwitchLanguage={handleSwitch}
  labels={{
    message: (langName) => `We detected you prefer ${langName}`,
    stayIn: (langName) => `Continue in ${langName}`,
  }}
/>

The "Switch" button always displays in the suggested language using built-in translations (not customizable via labels).

Props

Prop

Type

On this page