import { create } from 'zustand'; import { persist } from 'zustand/middleware'; import { en, type TranslationKey } from './locales/en'; import { ptBR } from './locales/pt-BR'; export const LOCALES = ['en', 'pt-BR'] as const; export type Locale = (typeof LOCALES)[number]; const DICTIONARIES: Record>> = { en, 'pt-BR': ptBR, }; /** * First-run guess from the browser. Persisted afterwards, so an explicit * choice always wins over the browser's setting on later visits. */ function detectLocale(): Locale { if (typeof navigator === 'undefined') return 'en'; return navigator.language?.toLowerCase().startsWith('pt') ? 'pt-BR' : 'en'; } interface LocaleState { locale: Locale; setLocale: (locale: Locale) => void; } export const useLocaleStore = create()( persist( (set) => ({ locale: detectLocale(), setLocale: (locale) => set({ locale }), }), { name: 'backspace-locale' }, ), ); // Keep in sync: screen readers, spellcheck and hyphenation all read // it, and persisted state rehydrates after the first paint — hence the // subscription rather than a one-off assignment. if (typeof document !== 'undefined') { document.documentElement.lang = useLocaleStore.getState().locale; useLocaleStore.subscribe((state) => { document.documentElement.lang = state.locale; }); } /** * Resolves a key, substituting `{name}` placeholders. * * Falls back to English, then to the key itself. The key is a deliberate last * resort: it is ugly on screen, which makes a missing entry obvious in review * instead of silently rendering an empty string. */ export function translate( locale: Locale, key: TranslationKey, params?: Record, ): string { const template = DICTIONARIES[locale]?.[key] ?? en[key] ?? key; if (!params) return template; return template.replace(/\{(\w+)\}/g, (match, name: string) => name in params ? String(params[name]) : match, ); } /** * Subscribes the calling component to the active locale, so switching language * re-renders it. Components that only need the string once (outside React) can * call `translate` with `useLocaleStore.getState().locale` instead. */ export function useT() { const locale = useLocaleStore((s) => s.locale); return (key: TranslationKey, params?: Record) => translate(locale, key, params); } export type { TranslationKey };