feat(i18n): Complete internationalization with timezone fixes and language switching
Completes full internationalization coverage for the webmail application with enhanced language support: - Replace all remaining hardcoded English strings with translation keys - Add timezone auto-detection to prevent hydration mismatches - Enable instant client-side language switching without page reload - Add 60+ new translation keys in English and French locales - Improve language switcher component with proper state management - Add health check endpoint for container orchestration All user-facing text now supports English and French with no hardcoded fallbacks, providing a fully localized experience.
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import { NextIntlClientProvider } from 'next-intl';
|
||||
import { useLocaleStore } from '@/stores/locale-store';
|
||||
import enMessages from '@/locales/en/common.json';
|
||||
import frMessages from '@/locales/fr/common.json';
|
||||
|
||||
// Pre-loaded translations (loaded at build time, not runtime)
|
||||
const ALL_MESSAGES = {
|
||||
en: enMessages,
|
||||
fr: frMessages,
|
||||
};
|
||||
|
||||
interface IntlProviderProps {
|
||||
locale: string;
|
||||
messages: Record<string, unknown>;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export function IntlProvider({ locale: initialLocale, children }: IntlProviderProps) {
|
||||
const currentLocale = useLocaleStore((state) => state.locale);
|
||||
const setLocale = useLocaleStore((state) => state.setLocale);
|
||||
const [activeLocale, setActiveLocale] = useState(currentLocale || initialLocale);
|
||||
const [timeZone, setTimeZone] = useState<string>('UTC');
|
||||
|
||||
// Detect user's timezone on mount
|
||||
useEffect(() => {
|
||||
try {
|
||||
const detectedTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
setTimeZone(detectedTimeZone);
|
||||
} catch (error) {
|
||||
// Fallback to UTC if detection fails
|
||||
console.warn('Failed to detect timezone, using UTC:', error);
|
||||
setTimeZone('UTC');
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Sync initial locale with store on first mount only
|
||||
useEffect(() => {
|
||||
if (!currentLocale) {
|
||||
setLocale(initialLocale);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
// Switch locale immediately when store changes
|
||||
useEffect(() => {
|
||||
if (currentLocale) {
|
||||
setActiveLocale(currentLocale);
|
||||
}
|
||||
}, [currentLocale]);
|
||||
|
||||
return (
|
||||
<NextIntlClientProvider
|
||||
locale={activeLocale}
|
||||
messages={ALL_MESSAGES[activeLocale as keyof typeof ALL_MESSAGES]}
|
||||
timeZone={timeZone}
|
||||
>
|
||||
{children}
|
||||
</NextIntlClientProvider>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user