Enhance i18n configuration with synchronous loading and enable suspense for improved rendering

Refactor App component to include loading fallback for i18next suspense
This commit is contained in:
Reece Browne 2025-08-14 20:36:19 +01:00
parent b1fd8d9bea
commit fdb564b929
3 changed files with 35 additions and 21 deletions

View File

@ -1,4 +1,4 @@
import React from 'react'; import React, { Suspense } from 'react';
import { RainbowThemeProvider } from './components/shared/RainbowThemeProvider'; import { RainbowThemeProvider } from './components/shared/RainbowThemeProvider';
import { FileContextProvider } from './contexts/FileContext'; import { FileContextProvider } from './contexts/FileContext';
import { FilesModalProvider } from './contexts/FilesModalContext'; import { FilesModalProvider } from './contexts/FilesModalContext';
@ -8,14 +8,30 @@ import HomePage from './pages/HomePage';
import './styles/tailwind.css'; import './styles/tailwind.css';
import './index.css'; import './index.css';
// Loading component for i18next suspense
const LoadingFallback = () => (
<div style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '100vh',
fontSize: '18px',
color: '#666'
}}>
Loading...
</div>
);
export default function App() { export default function App() {
return ( return (
<RainbowThemeProvider> <Suspense fallback={<LoadingFallback />}>
<FileContextProvider enableUrlSync={true} enablePersistence={true}> <RainbowThemeProvider>
<FilesModalProvider> <FileContextProvider enableUrlSync={true} enablePersistence={true}>
<HomePage /> <FilesModalProvider>
</FilesModalProvider> <HomePage />
</FileContextProvider> </FilesModalProvider>
</RainbowThemeProvider> </FileContextProvider>
</RainbowThemeProvider>
</Suspense>
); );
} }

View File

@ -118,7 +118,7 @@ interface ToolManagementResult {
} }
export const useToolManagement = (): ToolManagementResult => { export const useToolManagement = (): ToolManagementResult => {
const { t, ready } = useTranslation(); const { t } = useTranslation();
const [selectedToolKey, setSelectedToolKey] = useState<string | null>(null); const [selectedToolKey, setSelectedToolKey] = useState<string | null>(null);
const [toolSelectedFileIds, setToolSelectedFileIds] = useState<string[]>([]); const [toolSelectedFileIds, setToolSelectedFileIds] = useState<string[]>([]);
@ -136,10 +136,6 @@ export const useToolManagement = (): ToolManagementResult => {
}, [endpointsLoading, endpointStatus]); }, [endpointsLoading, endpointStatus]);
const toolRegistry: ToolRegistry = useMemo(() => { const toolRegistry: ToolRegistry = useMemo(() => {
if (!ready) {
return {};
}
const availableTools: ToolRegistry = {}; const availableTools: ToolRegistry = {};
Object.keys(toolDefinitions).forEach(toolKey => { Object.keys(toolDefinitions).forEach(toolKey => {
if (isToolAvailable(toolKey)) { if (isToolAvailable(toolKey)) {
@ -151,7 +147,7 @@ export const useToolManagement = (): ToolManagementResult => {
} }
}); });
return availableTools; return availableTools;
}, [t, isToolAvailable, ready]); }, [t, isToolAvailable]);
useEffect(() => { useEffect(() => {
if (!endpointsLoading && selectedToolKey && !toolRegistry[selectedToolKey]) { if (!endpointsLoading && selectedToolKey && !toolRegistry[selectedToolKey]) {

View File

@ -61,6 +61,9 @@ i18n
nonExplicitSupportedLngs: false, nonExplicitSupportedLngs: false,
debug: process.env.NODE_ENV === 'development', debug: process.env.NODE_ENV === 'development',
// Ensure synchronous loading to prevent timing issues
initImmediate: false,
interpolation: { interpolation: {
escapeValue: false, // React already escapes values escapeValue: false, // React already escapes values
}, },
@ -75,16 +78,15 @@ i18n
}, },
react: { react: {
useSuspense: false, // Set to false to avoid suspense issues with SSR useSuspense: true, // Enable suspense to prevent premature rendering
bindI18n: 'languageChanged loaded',
bindI18nStore: 'added removed',
transEmptyNodeValue: '', // Return empty string for missing keys instead of key name
transSupportBasicHtmlNodes: true,
transKeepBasicHtmlNodesFor: ['br', 'strong', 'i', 'p'],
}, },
}); });
// Map base language codes to specific locales
i18n.services.languageUtils.formatLanguageCode = (lng) => {
if (lng === 'en') return 'en-GB';
return lng;
};
// Set document direction based on language // Set document direction based on language
i18n.on('languageChanged', (lng) => { i18n.on('languageChanged', (lng) => {
const isRTL = rtlLanguages.includes(lng); const isRTL = rtlLanguages.includes(lng);