feat: add i18n framework with Indonesian translation support (#124)

* feat: add i18n support with separate translation files

- Extract translations from store.js to separate files for easier management
- Add translation files for English (en.js), Indonesian (id.js), Turkish (tr.js), and Chinese (zh.js)
- Load translations via window.translations object before Alpine store initialization
- Add Bahasa Indonesia option to language selector

* feat: translate remaining hardcoded UI strings

- Update index.html to use t() for Menu and GitHub labels
- Update views to translate Tier, Quota, Live, tier badges, and close button
- Update components to use translated error messages and confirmation dialogs
- Update utils to use translated validation and error messages
- Update app-init.js to use translated OAuth success/error messages
This commit is contained in:
Irvan Fauziansyah
2026-01-15 22:33:38 +07:00
committed by GitHub
parent 9ffb83ab74
commit e2d03f9b25
17 changed files with 1413 additions and 890 deletions

View File

@@ -318,7 +318,7 @@ window.Components.claudeConfig = () => ({
*/
async executeSavePreset(name) {
if (!name || !name.trim()) {
Alpine.store('global').showToast('Preset name is required', 'error');
Alpine.store('global').showToast(Alpine.store('global').t('presetNameRequired'), 'error');
return;
}
@@ -363,10 +363,10 @@ window.Components.claudeConfig = () => ({
);
document.getElementById('save_preset_modal').close();
} else {
throw new Error(data.error || 'Save failed');
throw new Error(data.error || Alpine.store('global').t('saveFailed'));
}
} catch (e) {
Alpine.store('global').showToast('Failed to save preset: ' + e.message, 'error');
Alpine.store('global').showToast(Alpine.store('global').t('failedToSavePreset') + ': ' + e.message, 'error');
} finally {
this.savingPreset = false;
}
@@ -377,12 +377,13 @@ window.Components.claudeConfig = () => ({
*/
async deleteSelectedPreset() {
if (!this.selectedPresetName) {
Alpine.store('global').showToast('No preset selected', 'warning');
Alpine.store('global').showToast(Alpine.store('global').t('noPresetSelected'), 'warning');
return;
}
// Confirm deletion
if (!confirm(`Delete preset "${this.selectedPresetName}"?`)) {
const confirmMsg = Alpine.store('global').t('deletePresetConfirm', { name: this.selectedPresetName });
if (!confirm(confirmMsg)) {
return;
}
@@ -408,10 +409,10 @@ window.Components.claudeConfig = () => ({
'success'
);
} else {
throw new Error(data.error || 'Delete failed');
throw new Error(data.error || Alpine.store('global').t('deleteFailed'));
}
} catch (e) {
Alpine.store('global').showToast('Failed to delete preset: ' + e.message, 'error');
Alpine.store('global').showToast(Alpine.store('global').t('failedToDeletePreset') + ': ' + e.message, 'error');
} finally {
this.deletingPreset = false;
}