rc 1.0
This commit is contained in:
109
lib/i18n.tsx
Normal file
109
lib/i18n.tsx
Normal file
@@ -0,0 +1,109 @@
|
||||
'use client'
|
||||
|
||||
import React, { createContext, useContext, useState, useEffect, ReactNode } from 'react'
|
||||
import enTranslations from './translations/en.json'
|
||||
import deTranslations from './translations/de.json'
|
||||
|
||||
type Language = 'en' | 'de'
|
||||
|
||||
type TranslationKey = string
|
||||
type Translations = typeof enTranslations
|
||||
|
||||
interface I18nContextType {
|
||||
language: Language
|
||||
setLanguage: (lang: Language) => void
|
||||
t: (key: TranslationKey, params?: Record<string, string | number>) => string
|
||||
}
|
||||
|
||||
const I18nContext = createContext<I18nContextType | undefined>(undefined)
|
||||
|
||||
const translations: Record<Language, Translations> = {
|
||||
en: enTranslations,
|
||||
de: deTranslations,
|
||||
}
|
||||
|
||||
export function I18nProvider({ children }: { children: ReactNode }) {
|
||||
const [language, setLanguageState] = useState<Language>('en')
|
||||
|
||||
// Load language from localStorage on mount
|
||||
useEffect(() => {
|
||||
const savedLanguage = localStorage.getItem('language') as Language
|
||||
if (savedLanguage && (savedLanguage === 'en' || savedLanguage === 'de')) {
|
||||
setLanguageState(savedLanguage)
|
||||
} else {
|
||||
// Detect browser language
|
||||
const browserLang = navigator.language.split('-')[0]
|
||||
if (browserLang === 'de') {
|
||||
setLanguageState('de')
|
||||
} else {
|
||||
setLanguageState('en')
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
const setLanguage = (lang: Language) => {
|
||||
setLanguageState(lang)
|
||||
localStorage.setItem('language', lang)
|
||||
// Update HTML lang attribute
|
||||
if (typeof document !== 'undefined') {
|
||||
document.documentElement.lang = lang
|
||||
}
|
||||
}
|
||||
|
||||
const t = (key: TranslationKey, params?: Record<string, string | number>): string => {
|
||||
const keys = key.split('.')
|
||||
let value: any = translations[language]
|
||||
|
||||
for (const k of keys) {
|
||||
if (value && typeof value === 'object' && k in value) {
|
||||
value = value[k]
|
||||
} else {
|
||||
// Fallback to English if key not found
|
||||
value = translations.en
|
||||
for (const fallbackKey of keys) {
|
||||
if (value && typeof value === 'object' && fallbackKey in value) {
|
||||
value = value[fallbackKey]
|
||||
} else {
|
||||
return key // Return key if translation not found
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof value !== 'string') {
|
||||
return key
|
||||
}
|
||||
|
||||
// Replace parameters in the translation string
|
||||
if (params) {
|
||||
return value.replace(/\{(\w+)\}/g, (match, paramKey) => {
|
||||
return params[paramKey]?.toString() || match
|
||||
})
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
// Update HTML lang attribute when language changes
|
||||
useEffect(() => {
|
||||
if (typeof document !== 'undefined') {
|
||||
document.documentElement.lang = language
|
||||
}
|
||||
}, [language])
|
||||
|
||||
return (
|
||||
<I18nContext.Provider value={{ language, setLanguage, t }}>
|
||||
{children}
|
||||
</I18nContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export function useI18n() {
|
||||
const context = useContext(I18nContext)
|
||||
if (context === undefined) {
|
||||
throw new Error('useI18n must be used within an I18nProvider')
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user