77 lines
2.3 KiB
TypeScript
77 lines
2.3 KiB
TypeScript
import { createContext, useContext } from 'react';
|
|
import en from '@/i18n/en';
|
|
import es from '@/i18n/es';
|
|
import th from '@/i18n/th';
|
|
import ja from '@/i18n/ja';
|
|
|
|
/**
|
|
* Language context + types + hooks. Split from the `LanguageProvider` component
|
|
* so the component file exports only a component (React Fast Refresh), per the
|
|
* `react-refresh/only-export-components` rule.
|
|
*/
|
|
|
|
export type Language = 'en' | 'es' | 'th' | 'ja';
|
|
|
|
type TranslationKey = string;
|
|
type TranslationValue = string | { [key: string]: TranslationValue };
|
|
|
|
export type Translations = {
|
|
[key: string]: TranslationValue;
|
|
};
|
|
|
|
export interface LanguageContextType {
|
|
/** Current language */
|
|
language: Language;
|
|
/** Set the current language */
|
|
setLanguage: (lang: Language) => void;
|
|
/** Translate a key - supports dot notation for nested keys */
|
|
t: (key: TranslationKey, params?: Record<string, string | number>) => string;
|
|
/** Check if current language is RTL (for future Arabic support, etc.) */
|
|
isRTL: boolean;
|
|
}
|
|
|
|
export const LanguageContext = createContext<LanguageContextType | undefined>(undefined);
|
|
|
|
export const translations: Record<Language, Translations> = { en, es, th, ja };
|
|
|
|
/** Get a nested value from an object using dot notation (`nav.home`). */
|
|
export function getNestedValue(obj: Translations, path: string): string | undefined {
|
|
const keys = path.split('.');
|
|
let current: TranslationValue = obj;
|
|
|
|
for (const key of keys) {
|
|
if (current && typeof current === 'object' && key in current) {
|
|
current = current[key];
|
|
} else {
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
return typeof current === 'string' ? current : undefined;
|
|
}
|
|
|
|
/** Replace `{{param}}` placeholders in a translation string. */
|
|
export function interpolate(str: string, params?: Record<string, string | number>): string {
|
|
if (!params) return str;
|
|
|
|
return str.replace(/\{\{(\w+)\}\}/g, (_, key) => {
|
|
return params[key]?.toString() ?? `{{${key}}}`;
|
|
});
|
|
}
|
|
|
|
/** Hook to access translation functions and language state. */
|
|
export function useTranslation() {
|
|
const context = useContext(LanguageContext);
|
|
|
|
if (context === undefined) {
|
|
throw new Error('useTranslation must be used within a LanguageProvider');
|
|
}
|
|
|
|
return context;
|
|
}
|
|
|
|
/** Hook to get just the translation function (convenience). */
|
|
export function useT() {
|
|
const { t } = useTranslation();
|
|
return t;
|
|
}
|