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

@@ -14,12 +14,13 @@ window.Validators = window.Validators || {};
*/
window.Validators.validateRange = function(value, min, max, fieldName = 'Value') {
const numValue = Number(value);
const t = Alpine.store('global').t;
if (isNaN(numValue)) {
return {
isValid: false,
value: min,
error: `${fieldName} must be a valid number`
error: t('mustBeValidNumber', { fieldName })
};
}
@@ -27,7 +28,7 @@ window.Validators.validateRange = function(value, min, max, fieldName = 'Value')
return {
isValid: false,
value: min,
error: `${fieldName} must be at least ${min}`
error: t('mustBeAtLeast', { fieldName, min })
};
}
@@ -35,7 +36,7 @@ window.Validators.validateRange = function(value, min, max, fieldName = 'Value')
return {
isValid: false,
value: max,
error: `${fieldName} must be at most ${max}`
error: t('mustBeAtMost', { fieldName, max })
};
}
@@ -64,12 +65,13 @@ window.Validators.validatePort = function(port) {
*/
window.Validators.validateNotEmpty = function(value, fieldName = 'Field') {
const trimmedValue = String(value || '').trim();
const t = Alpine.store('global').t;
if (trimmedValue.length === 0) {
return {
isValid: false,
value: trimmedValue,
error: `${fieldName} cannot be empty`
error: t('cannotBeEmpty', { fieldName })
};
}
@@ -106,7 +108,7 @@ window.Validators.validateBoolean = function(value) {
return {
isValid: false,
value: false,
error: 'Value must be true or false'
error: Alpine.store('global').t('mustBeTrueOrFalse')
};
};