initial checkin

This commit is contained in:
tim
2025-10-12 19:17:51 -04:00
commit bb2f7c9ce8
44 changed files with 10741 additions and 0 deletions

46
src/lib/i18n.ts Normal file
View File

@@ -0,0 +1,46 @@
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import enTranslations from '@/locales/en.json';
import esTranslations from '@/locales/es.json';
import frTranslations from '@/locales/fr.json';
import deTranslations from '@/locales/de.json';
import zhTranslations from '@/locales/zh.json';
import jaTranslations from '@/locales/ja.json';
export const languages = {
en: { name: 'English', flag: '🇬🇧' },
es: { name: 'Español', flag: '🇪🇸' },
fr: { name: 'Français', flag: '🇫🇷' },
de: { name: 'Deutsch', flag: '🇩🇪' },
zh: { name: '中文', flag: '🇨🇳' },
ja: { name: '日本語', flag: '🇯🇵' },
} as const;
export type Language = keyof typeof languages;
const resources = {
en: { translation: enTranslations },
es: { translation: esTranslations },
fr: { translation: frTranslations },
de: { translation: deTranslations },
zh: { translation: zhTranslations },
ja: { translation: jaTranslations },
};
// Initialize i18next
i18n
.use(initReactI18next)
.init({
resources,
lng: typeof window !== 'undefined' ? localStorage.getItem('language') || 'en' : 'en',
fallbackLng: 'en',
interpolation: {
escapeValue: false, // React already escapes values
},
react: {
useSuspense: false, // Disable suspense for client-side only
},
});
export default i18n;

6
src/lib/utils.ts Normal file
View File

@@ -0,0 +1,6 @@
import { type ClassValue, clsx } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}