refactor: enhance i18n handling by implementing state management for active language and optimizing resource loading

This commit is contained in:
Firman Ramdhani
2026-05-28 13:52:34 +07:00
parent d0ebceb1bb
commit dff05748f5
2 changed files with 112 additions and 55 deletions
@@ -1,48 +1,87 @@
import { useEffect } from 'react';
import { useEffect, useState } from 'react';
import { useTranslation, changeLanguage, i18n } from '@repo/core-i18n';
// Decentralized locale imports
import homeId from '../locales/id/home.json';
import homeEn from '../locales/en/home.json';
export default function I18nLandingSample() {
const { t } = useTranslation(['common', 'home']);
// Bendera penanda statis di level modul (default: false)
let isHomeDictLoaded = false;
// 1. Lazy-load the 'home' namespace when the module mounts
useEffect(() => {
export default function I18nLandingSample() {
// 1. Eksekusi SINKRONUS tepat sebelum render pertama (hanya berjalan 1x)
if (!isHomeDictLoaded) {
i18n.addResourceBundle('id', 'home', homeId, true, false);
i18n.addResourceBundle('en', 'home', homeEn, true, false);
isHomeDictLoaded = true; // Kunci benderanya agar tidak jalan lagi saat re-render
}
// 2. Sekarang useTranslation akan melihat kamus yang sudah siap
const { t } = useTranslation(['common', 'home']);
const [activeLang, setActiveLang] = useState(i18n.language);
useEffect(() => {
const handleLangChange = (lng: string) => setActiveLang(lng);
i18n.on('languageChanged', handleLangChange);
return () => {
i18n.off('languageChanged', handleLangChange);
};
}, []);
// 2. Change language without syncCallback to prove decoupling
const setLanguage = (lng: string) => {
// We intentionally omit the second argument (syncCallback)
// because the landing page is public and doesn't need backend syncing.
changeLanguage(lng).catch(console.error);
};
return (
<div style={{ padding: 40, textAlign: 'center', backgroundColor: '#f8fafc', color: '#0f172a' }}>
<h1 style={{ fontSize: 36, fontWeight: 'bold', marginBottom: 16 }}>
{t('home:welcome')}
</h1>
<h1 style={{ fontSize: 36, fontWeight: 'bold', marginBottom: 16 }}>{t('home:welcome')}</h1>
<div style={{ marginBottom: 32 }}>
<button
<button
onClick={() => setLanguage('id')}
style={{ padding: '8px 16px', marginRight: 8, cursor: 'pointer', borderRadius: 4, background: '#3b82f6', color: 'white', border: 'none' }}
style={{
padding: '8px 16px',
marginRight: 8,
cursor: 'pointer',
borderRadius: 4,
background: activeLang === 'id' ? '#1d4ed8' : '#93c5fd',
color: 'white',
border: 'none',
fontWeight: activeLang === 'id' ? 'bold' : 'normal',
}}
>
Bahasa Indonesia
</button>
<button
<button
onClick={() => setLanguage('en')}
style={{ padding: '8px 16px', cursor: 'pointer', borderRadius: 4, background: '#3b82f6', color: 'white', border: 'none' }}
style={{
padding: '8px 16px',
cursor: 'pointer',
borderRadius: 4,
background: activeLang === 'en' ? '#1d4ed8' : '#93c5fd',
color: 'white',
border: 'none',
fontWeight: activeLang === 'en' ? 'bold' : 'normal',
}}
>
English
</button>
</div>
<button style={{ padding: '16px 32px', fontSize: 18, fontWeight: 'bold', cursor: 'pointer', borderRadius: 8, background: '#10b981', color: 'white', border: 'none' }}>
<button
style={{
padding: '16px 32px',
fontSize: 18,
fontWeight: 'bold',
cursor: 'pointer',
borderRadius: 8,
background: '#10b981',
color: 'white',
border: 'none',
}}
>
{t('home:cta')}
</button>
</div>