feat(i18n): add Indonesian (Bahasa Indonesia) language support (#1399)

- Add 'id' to Language type in translations.ts
- Add ~1000 Indonesian translation keys covering all UI sections
- Update LanguageContext to persist 'id' in localStorage
- Add ID button to Header.tsx language toggle
- Add �� option to HeaderBar.tsx desktop dropdown and mobile toggle
- Add Indonesian translations to inline text objects in
  LoginRequiredOverlay, StrategyMarketPage, PositionHistory

Closes #XX
This commit is contained in:
Muhammad Syaiful Anwar
2026-03-03 17:39:09 +07:00
committed by GitHub
parent 285053b7a4
commit 3358c5a53e
7 changed files with 1066 additions and 11 deletions

View File

@@ -99,8 +99,8 @@ export default function HeaderBar({
{(() => {
// Define all navigation tabs
const navTabs: { page: Page; path: string; label: string; requiresAuth: boolean }[] = [
{ page: 'data', path: '/data', label: language === 'zh' ? '数据' : 'Data', requiresAuth: false },
{ page: 'strategy-market', path: '/strategy-market', label: language === 'zh' ? '策略市场' : 'Market', requiresAuth: true },
{ page: 'data', path: '/data', label: language === 'zh' ? '数据' : language === 'id' ? 'Data' : 'Data', requiresAuth: false },
{ page: 'strategy-market', path: '/strategy-market', label: language === 'zh' ? '策略市场' : language === 'id' ? 'Pasar' : 'Market', requiresAuth: true },
{ page: 'traders', path: '/traders', label: t('configNav', language), requiresAuth: true },
{ page: 'trader', path: '/dashboard', label: t('dashboardNav', language), requiresAuth: true },
{ page: 'strategy', path: '/strategy', label: t('strategyNav', language), requiresAuth: true },
@@ -259,7 +259,7 @@ export default function HeaderBar({
className="flex items-center gap-2 px-3 py-2 rounded transition-colors text-nofx-text-muted hover:bg-white/5"
>
<span className="text-lg">
{language === 'zh' ? '🇨🇳' : '🇺🇸'}
{language === 'zh' ? '🇨🇳' : language === 'id' ? '🇮🇩' : '🇺🇸'}
</span>
<ChevronDown className="w-4 h-4" />
</button>
@@ -288,6 +288,17 @@ export default function HeaderBar({
<span className="text-base">🇺🇸</span>
<span className="text-sm">English</span>
</button>
<button
onClick={() => {
onLanguageChange?.('id')
setLanguageDropdownOpen(false)
}}
className={`w-full flex items-center gap-2 px-3 py-2 transition-colors text-nofx-text-muted hover:text-white
${language === 'id' ? 'bg-nofx-gold/10' : 'hover:bg-white/5'}`}
>
<span className="text-base">🇮🇩</span>
<span className="text-sm">Bahasa</span>
</button>
</div>
)}
</div>
@@ -329,8 +340,8 @@ export default function HeaderBar({
<div className="flex flex-col gap-6 mb-12">
{(() => {
const navTabs: { page: Page; path: string; label: string; requiresAuth: boolean }[] = [
{ page: 'data', path: '/data', label: language === 'zh' ? '数据' : 'Data', requiresAuth: false },
{ page: 'strategy-market', path: '/strategy-market', label: language === 'zh' ? '策略市场' : 'Market', requiresAuth: true },
{ page: 'data', path: '/data', label: language === 'zh' ? '数据' : language === 'id' ? 'Data' : 'Data', requiresAuth: false },
{ page: 'strategy-market', path: '/strategy-market', label: language === 'zh' ? '策略市场' : language === 'id' ? 'Pasar' : 'Market', requiresAuth: true },
{ page: 'traders', path: '/traders', label: t('configNav', language), requiresAuth: true },
{ page: 'trader', path: '/dashboard', label: t('dashboardNav', language), requiresAuth: true },
{ page: 'strategy', path: '/strategy', label: t('strategyNav', language), requiresAuth: true },
@@ -429,7 +440,7 @@ export default function HeaderBar({
<div className="grid grid-cols-2 gap-4">
{/* Lang Switcher */}
<div className="flex bg-zinc-900 rounded-lg p-1 border border-zinc-800">
{['zh', 'en'].map((lang) => (
{['zh', 'en', 'id'].map((lang) => (
<button
key={lang}
onClick={() => {
@@ -441,7 +452,7 @@ export default function HeaderBar({
: 'text-zinc-500'
}`}
>
{lang === 'zh' ? 'CN' : 'EN'}
{lang === 'zh' ? 'CN' : lang === 'id' ? 'ID' : 'EN'}
</button>
))}
</div>