mirror of
https://github.com/mue/mue.git
synced 2026-07-20 15:34:10 +02:00
feat(translation): implement reactive translation system with context and hooks
This commit is contained in:
43
src/contexts/README.md
Normal file
43
src/contexts/README.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Translation System
|
||||
|
||||
## Using Reactive Translations
|
||||
|
||||
The app now supports instant language switching without page refresh!
|
||||
|
||||
### For new components
|
||||
|
||||
Use the `useMessage` hook for reactive translations:
|
||||
|
||||
```jsx
|
||||
import { useMessage } from 'contexts/TranslationContext';
|
||||
|
||||
function MyComponent() {
|
||||
const title = useMessage('modals.main.title');
|
||||
const description = useMessage('modals.main.description');
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>{title}</h1>
|
||||
<p>{description}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### For existing components
|
||||
|
||||
The old `variables.getMessage()` method still works but won't automatically update when language changes. Gradually migrate to `useMessage` for components that display translations prominently.
|
||||
|
||||
### How it works
|
||||
|
||||
1. `TranslationProvider` wraps the app and listens for language change events
|
||||
2. When language is changed via the Radio component, it emits a `languageChange` event
|
||||
3. The provider updates the i18n instance and triggers re-renders
|
||||
4. Components using `useMessage` automatically update to show new translations
|
||||
|
||||
### Benefits
|
||||
|
||||
- No page refresh needed
|
||||
- Minimal performance impact (translations already loaded)
|
||||
- Backward compatible with existing code
|
||||
- Smooth user experience
|
||||
63
src/contexts/TranslationContext.jsx
Normal file
63
src/contexts/TranslationContext.jsx
Normal file
@@ -0,0 +1,63 @@
|
||||
import { createContext, useContext, useState, useEffect, useCallback } from 'react';
|
||||
import { initTranslations, translations } from 'lib/translations';
|
||||
import variables from 'config/variables';
|
||||
import EventBus from 'utils/eventbus';
|
||||
|
||||
const TranslationContext = createContext();
|
||||
|
||||
export function TranslationProvider({ children, initialLanguage }) {
|
||||
const [languagecode, setLanguagecode] = useState(initialLanguage);
|
||||
|
||||
const changeLanguage = useCallback((newLanguage) => {
|
||||
// Update the i18n instance
|
||||
variables.language = initTranslations(newLanguage);
|
||||
variables.languagecode = newLanguage;
|
||||
document.documentElement.lang = newLanguage.replace('_', '-');
|
||||
|
||||
// Update tab name if it's still the default
|
||||
if (localStorage.getItem('tabName') === variables.getMessage('tabname')) {
|
||||
const newTabName = translations[newLanguage.replace('-', '_')]?.tabname || variables.getMessage('tabname');
|
||||
localStorage.setItem('tabName', newTabName);
|
||||
document.title = newTabName;
|
||||
}
|
||||
|
||||
// Update state to trigger re-render
|
||||
setLanguagecode(newLanguage);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const handleLanguageChange = (data) => {
|
||||
if (data?.language) {
|
||||
changeLanguage(data.language);
|
||||
}
|
||||
};
|
||||
|
||||
EventBus.on('languageChange', handleLanguageChange);
|
||||
|
||||
return () => {
|
||||
EventBus.off('languageChange', handleLanguageChange);
|
||||
};
|
||||
}, [changeLanguage]);
|
||||
|
||||
return (
|
||||
<TranslationContext.Provider value={{ languagecode, changeLanguage }}>
|
||||
{children}
|
||||
</TranslationContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useTranslation() {
|
||||
const context = useContext(TranslationContext);
|
||||
if (!context) {
|
||||
throw new Error('useTranslation must be used within a TranslationProvider');
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
// Hook for reactive translations - triggers re-render when language changes
|
||||
export function useMessage(key, optional = {}) {
|
||||
const { languagecode } = useTranslation();
|
||||
// The languagecode dependency ensures this hook re-evaluates when language changes
|
||||
// This is intentional - we use it to trigger re-renders even though it's not directly used
|
||||
return languagecode ? variables.getMessage(key, optional) : '';
|
||||
}
|
||||
1
src/contexts/index.js
Normal file
1
src/contexts/index.js
Normal file
@@ -0,0 +1 @@
|
||||
export { TranslationProvider, useTranslation, useMessage } from './TranslationContext';
|
||||
Reference in New Issue
Block a user