feat: Implement multi-language system (ID/EN) for member dashboard

- Create translation files (locales/id.ts, locales/en.ts)
- Add LanguageContext with useLanguage hook
- Add LanguageToggle component in sidebar
- Default language: Indonesian (ID)
- Translate WalletDialog and TransactionDialog
- Language preference persisted in localStorage
- Type-safe translations with autocomplete

Next: Translate remaining pages (Overview, Wallets, Transactions, Profile)
This commit is contained in:
dwindown
2025-10-12 08:51:48 +07:00
parent c0df4a7c2a
commit 371b5e0a66
10 changed files with 676 additions and 73 deletions

210
apps/web/src/locales/en.ts Normal file
View File

@@ -0,0 +1,210 @@
export const en = {
common: {
search: 'Search',
filter: 'Filter',
add: 'Add',
edit: 'Edit',
delete: 'Delete',
cancel: 'Cancel',
save: 'Save',
close: 'Close',
loading: 'Loading...',
noData: 'No data',
confirm: 'Confirm',
success: 'Success',
error: 'Error',
total: 'Total',
date: 'Date',
amount: 'Amount',
status: 'Status',
actions: 'Actions',
all: 'All',
active: 'Active',
inactive: 'Inactive',
yes: 'Yes',
no: 'No',
},
nav: {
overview: 'Overview',
transactions: 'Transactions',
wallets: 'Wallets',
profile: 'Profile',
logout: 'Logout',
},
overview: {
title: 'Overview',
totalBalance: 'Total Balance',
totalIncome: 'Total Income',
totalExpense: 'Total Expense',
acrossWallets: 'Across {count} wallets',
income: 'income',
expense: 'expense',
recentTransactions: 'Recent Transactions',
viewAll: 'View All',
noTransactions: 'No transactions yet',
addFirstTransaction: 'Add your first transaction',
wallets: 'Wallets',
addWallet: 'Add Wallet',
noWallets: 'No wallets yet',
createFirstWallet: 'Create your first wallet',
incomeByCategory: 'Income by Category',
expenseByCategory: 'Expense by Category',
last30Days: 'Last 30 days',
last7Days: 'Last 7 days',
thisMonth: 'This month',
lastMonth: 'Last month',
thisYear: 'This year',
custom: 'Custom',
},
transactions: {
title: 'Transactions',
addTransaction: 'Add Transaction',
editTransaction: 'Edit Transaction',
deleteConfirm: 'Are you sure you want to delete this transaction?',
income: 'Income',
expense: 'Expense',
category: 'Category',
memo: 'Memo',
wallet: 'Wallet',
direction: 'Type',
filterByWallet: 'Filter by Wallet',
filterByDirection: 'Filter by Type',
filterByCategory: 'Filter by Category',
searchPlaceholder: 'Search transactions...',
noTransactions: 'No transactions',
stats: {
totalIncome: 'Total Income',
totalExpense: 'Total Expense',
netAmount: 'Net Amount',
},
},
wallets: {
title: 'Wallets',
addWallet: 'Add Wallet',
editWallet: 'Edit Wallet',
deleteConfirm: 'Are you sure you want to delete this wallet? All related transactions will be deleted.',
name: 'Name',
type: 'Type',
balance: 'Balance',
currency: 'Currency',
unit: 'Unit',
initialAmount: 'Initial Amount',
pricePerUnit: 'Price per Unit',
money: 'Money',
asset: 'Asset',
filterByType: 'Filter by Type',
searchPlaceholder: 'Search wallets...',
noWallets: 'No wallets yet',
createFirst: 'Create your first wallet to start tracking your finances',
totalBalance: 'Total Balance',
moneyWallets: 'Money Wallets',
assetWallets: 'Asset Wallets',
},
walletDialog: {
addTitle: 'Add Wallet',
editTitle: 'Edit Wallet',
name: 'Wallet Name',
namePlaceholder: 'e.g., Main Wallet, Savings',
type: 'Wallet Type',
money: 'Money',
asset: 'Asset',
currency: 'Currency',
selectCurrency: 'Select currency',
unit: 'Unit',
unitPlaceholder: 'e.g., grams, lots, shares',
initialAmount: 'Initial Amount (Optional)',
initialAmountPlaceholder: '0',
pricePerUnit: 'Price per Unit (Optional)',
pricePerUnitPlaceholder: '0',
pricePerUnitHelper: 'Price per {unit} in IDR',
},
transactionDialog: {
addTitle: 'Add Transaction',
editTitle: 'Edit Transaction',
amount: 'Amount',
amountPlaceholder: '0',
wallet: 'Wallet',
selectWallet: 'Select wallet',
direction: 'Transaction Type',
income: 'Income',
expense: 'Expense',
category: 'Category',
categoryPlaceholder: 'Select or type new category',
addCategory: 'Add',
memo: 'Memo (Optional)',
memoPlaceholder: 'Add a note...',
date: 'Date',
selectDate: 'Select date',
},
profile: {
title: 'Profile',
personalInfo: 'Personal Information',
name: 'Name',
email: 'Email',
emailVerified: 'Email Verified',
emailNotVerified: 'Email Not Verified',
avatar: 'Avatar',
changeAvatar: 'Change Avatar',
uploading: 'Uploading...',
security: 'Security',
password: 'Password',
currentPassword: 'Current Password',
newPassword: 'New Password',
confirmPassword: 'Confirm New Password',
changePassword: 'Change Password',
setPassword: 'Set Password',
noPassword: 'You logged in with Google and haven\'t set a password yet',
twoFactor: 'Two-Factor Authentication',
twoFactorDesc: 'Add an extra layer of security to your account',
phoneNumber: 'Phone Number',
phoneNumberPlaceholder: '+62812345678',
updatePhone: 'Update Phone',
emailOtp: 'Email OTP',
emailOtpDesc: 'Receive verification codes via email',
enable: 'Enable',
disable: 'Disable',
enabled: 'Enabled',
disabled: 'Disabled',
sendCode: 'Send Code',
verifyCode: 'Verify Code',
enterCode: 'Enter code',
whatsappOtp: 'WhatsApp OTP',
whatsappOtpDesc: 'Receive verification codes via WhatsApp',
authenticatorApp: 'Authenticator App',
authenticatorDesc: 'Use an authenticator app like Google Authenticator',
setup: 'Setup',
scanQr: 'Scan QR Code',
scanQrDesc: 'Scan this QR code with your authenticator app',
manualEntry: 'Or enter this code manually:',
enterAuthCode: 'Enter code from your authenticator app',
dangerZone: 'Danger Zone',
deleteAccount: 'Delete Account',
deleteAccountDesc: 'Permanently delete your account. This action cannot be undone.',
deleteAccountConfirm: 'Are you sure you want to delete your account? All data will be permanently lost.',
enterPasswordToDelete: 'Enter your password to confirm',
},
dateRange: {
last7Days: 'Last 7 days',
last30Days: 'Last 30 days',
thisMonth: 'This month',
lastMonth: 'Last month',
thisYear: 'This year',
custom: 'Custom',
from: 'From',
to: 'To',
},
}