| | 'use client' |
| |
|
| | import { createContext, useContext, ReactNode, useMemo } from 'react' |
| | import type { JSX } from 'react' |
| | import { languages, languageKeys, type LanguageCode } from '@/languages/lib/languages' |
| |
|
| | interface LocaleContextType { |
| | readonly locale: LanguageCode |
| | readonly isValidLocale: (locale: string) => locale is LanguageCode |
| | readonly getSupportedLocales: () => readonly LanguageCode[] |
| | readonly getLocaleDisplayName: (locale: LanguageCode) => string |
| | readonly getLocaleNativeName: (locale: LanguageCode) => string |
| | } |
| |
|
| | const LocaleContext = createContext<LocaleContextType | null>(null) |
| |
|
| | interface LocaleProviderProps { |
| | readonly children: ReactNode |
| | readonly locale: LanguageCode |
| | } |
| |
|
| | |
| | const SUPPORTED_LOCALES: readonly LanguageCode[] = languageKeys as LanguageCode[] |
| |
|
| | |
| | |
| | |
| | function isValidLocale(locale: string): locale is LanguageCode { |
| | return languageKeys.includes(locale) |
| | } |
| |
|
| | |
| | |
| | |
| | function getLocaleDisplayName(locale: LanguageCode): string { |
| | return languages[locale]?.name || locale |
| | } |
| |
|
| | |
| | |
| | |
| | function getLocaleNativeName(locale: LanguageCode): string { |
| | return languages[locale]?.nativeName || languages[locale]?.name || locale |
| | } |
| |
|
| | |
| | |
| | |
| | function getBrowserLocale(): LanguageCode { |
| | if (typeof window === 'undefined') return 'en' |
| |
|
| | const browserLang = window.navigator.language.split('-')[0] |
| | return isValidLocale(browserLang) ? browserLang : 'en' |
| | } |
| |
|
| | |
| | |
| | |
| | export function LocaleProvider({ children, locale }: LocaleProviderProps): JSX.Element { |
| | const contextValue = useMemo( |
| | () => ({ |
| | locale: isValidLocale(locale) ? locale : 'en', |
| | isValidLocale, |
| | getSupportedLocales: () => SUPPORTED_LOCALES, |
| | getLocaleDisplayName, |
| | getLocaleNativeName, |
| | }), |
| | [locale], |
| | ) |
| |
|
| | return <LocaleContext.Provider value={contextValue}>{children}</LocaleContext.Provider> |
| | } |
| |
|
| | |
| | |
| | |
| | export function useLocale(): LanguageCode { |
| | const context = useContext(LocaleContext) |
| |
|
| | if (context) { |
| | return context.locale |
| | } |
| |
|
| | |
| | |
| | console.warn('useLocale called outside of LocaleProvider, using fallback') |
| | return getBrowserLocale() |
| | } |
| |
|
| | |
| | |
| | |
| | export function useLocaleValidation() { |
| | const context = useContext(LocaleContext) |
| |
|
| | return { |
| | isValidLocale: context?.isValidLocale ?? isValidLocale, |
| | getSupportedLocales: context?.getSupportedLocales ?? (() => SUPPORTED_LOCALES), |
| | getLocaleDisplayName: context?.getLocaleDisplayName ?? getLocaleDisplayName, |
| | getLocaleNativeName: context?.getLocaleNativeName ?? getLocaleNativeName, |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | export function useLocaleContext(): LocaleContextType { |
| | const context = useContext(LocaleContext) |
| |
|
| | if (!context) { |
| | throw new Error('useLocaleContext must be used within a LocaleProvider') |
| | } |
| |
|
| | return context |
| | } |
| |
|
| | export { isValidLocale, getLocaleDisplayName, getLocaleNativeName } |
| | export type { LocaleContextType, LanguageCode } |
| |
|