feat: 31 languages + disk safety panel + electron auto-updater + VM uninstall
CI / Test & Lint (push) Canceled after 0s
CI / Security audit (push) Canceled after 0s

i18n:
- Expanded from 6 to 31 languages (no Hebrew per policy)
- Added: pt, ru, ja, ko, hi, tr, it, nl, pl, sv, id, uk, th, vi, fa, cs, ms, ro, el, bn, hu, fi, da, no, ur
- RTL support for ar, fa, ur
- Language selector dropdown wired into dashboard navbar

Disk Safety:
- New backend route /api/v1/disk-settings (GET/POST/cleanup)
- Frontend modal with sliders for health interval, max entries, retention days
- Clean Up Now button triggers immediate cleanup
- Wired into dashboard navbar

Desktop Auto-Updater (from timed-out subagent):
- electron-updater installed and configured
- Checks get.dashcaddy.net/release/ for updates
- Publish config added to package.json

VM Uninstall:
- Wizard calls vmDestroy before regular uninstall
- Cleans up VM/disk sandbox on uninstall

Cleanup:
- Recursive data nesting guard (nesting-guard.js)
- Removed 242MB of data/data/data/ duplicates
This commit is contained in:
Krystie
2026-08-13 03:04:48 -07:00
parent 8ac1937784
commit d25343000f
8 changed files with 739 additions and 271 deletions
+2
View File
@@ -94,6 +94,7 @@ const eventsRoutes = require('../routes/events');
const workflowsRoutes = require('../routes/workflows');
const dependenciesRoutes = require('../routes/dependencies');
const securityRoutes = require('../routes/security');
const diskSettingsRoutes = require('../routes/disk-settings');
const logInsightsRoutes = require('../routes/log-insights');
const billingRoutes = require('../routes/billing');
const DependencyManager = require('./managers/dependency-manager');
@@ -757,6 +758,7 @@ async function createApp() {
}));
// Log Insights — plain English activity summary + safe log disposal
apiRouter.use('/disk-settings', diskSettingsRoutes);
apiRouter.use(logInsightsRoutes({
asyncHandler: ctx.asyncHandler,
ok: ctx.ok,
+1 -1
View File
@@ -14,7 +14,7 @@ const KNOWN_KEYS = [
'configurationType', 'defaults', 'customLogo', 'customFavicon',
'dashboardTitle', 'tailscale', 'license', 'skipped',
'routingMode', 'domain', 'email', 'defaultIP', 'pylon',
'customLogoDark', 'customLogoLight'
'customLogoDark', 'customLogoLight', 'language'
];
/**
+511 -270
View File
@@ -1,302 +1,543 @@
/**
* DC-077: Internationalization (i18n) framework for DashCaddy
* DashCaddy Internationalization (i18n) — 31 languages
*
* Lightweight translation system for the dashboard frontend and API responses.
* Supports multiple languages via JSON translation files loaded on demand.
* Translations for dashboard UI and API error messages.
* Languages: Arabic, Bengali, Chinese, Czech, Danish, Dutch, English, Finnish,
* French, German, Greek, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean,
* Malay, Norwegian, Persian, Polish, Portuguese, Romanian, Russian, Spanish,
* Swedish, Thai, Turkish, Ukrainian, Urdu, Vietnamese.
*
* Languages are stored in /assets/i18n/{lang}.json
* Default language is 'en' (English).
*
* Usage in frontend JS:
* const { t, setLanguage, getLanguage } = window.DCI18n;
* document.querySelector('.title').textContent = t('dashboard.title');
*
* Usage in API responses:
* const i18n = require('./i18n');
* const msg = i18n.t('error.container_not_found', req.lang || 'en');
* No Hebrew — per project policy.
*/
const fs = require('fs');
const path = require('path');
// Built-in translations (loaded synchronously at startup)
const TRANSLATIONS = {
en: {
'dashboard.title': 'Dashboard',
'dashboard.services': 'Services',
'dashboard.containers': 'Containers',
'dashboard.health': 'Health',
'dashboard.settings': 'Settings',
'dashboard.backups': 'Backups',
'dashboard.monitoring': 'Monitoring',
'dashboard.security': 'Security',
'service.status.healthy': 'Healthy',
'service.status.degraded': 'Degraded',
'service.status.down': 'Down',
'service.status.unknown': 'Unknown',
'service.status.pending': 'Pending',
'action.start': 'Start',
'action.stop': 'Stop',
'action.restart': 'Restart',
'action.delete': 'Delete',
'action.update': 'Update',
'action.deploy': 'Deploy',
'action.save': 'Save',
'action.cancel': 'Cancel',
en: { // 🇬🇧 English
'dashboard.title': 'Dashboard', 'dashboard.services': 'Services', 'dashboard.containers': 'Containers',
'dashboard.health': 'Health', 'dashboard.settings': 'Settings', 'dashboard.backups': 'Backups',
'dashboard.monitoring': 'Monitoring', 'dashboard.security': 'Security',
'service.status.healthy': 'Healthy', 'service.status.degraded': 'Degraded', 'service.status.down': 'Down',
'service.status.unknown': 'Unknown', 'service.status.pending': 'Pending',
'action.start': 'Start', 'action.stop': 'Stop', 'action.restart': 'Restart', 'action.delete': 'Delete',
'action.update': 'Update', 'action.deploy': 'Deploy', 'action.save': 'Save', 'action.cancel': 'Cancel',
'action.confirm': 'Confirm',
'error.not_found': 'Resource not found',
'error.unauthorized': 'Unauthorized',
'error.forbidden': 'Forbidden',
'error.rate_limited': 'Too many requests',
'error.internal': 'Internal server error',
'error.container_not_found': 'Container not found',
'error.service_not_found': 'Service not found',
'error.invalid_input': 'Invalid input',
'error.docker_unreachable': 'Docker daemon is not reachable',
'error.not_found': 'Resource not found', 'error.unauthorized': 'Unauthorized', 'error.forbidden': 'Forbidden',
'error.rate_limited': 'Too many requests', 'error.internal': 'Internal server error',
'error.container_not_found': 'Container not found', 'error.service_not_found': 'Service not found',
'error.invalid_input': 'Invalid input', 'error.docker_unreachable': 'Docker daemon is not reachable',
'error.disk_full': 'Disk space is critically low',
},
es: {
'dashboard.title': 'Panel de control',
'dashboard.services': 'Servicios',
'dashboard.containers': 'Contenedores',
'dashboard.health': 'Salud',
'dashboard.settings': 'Configuración',
'dashboard.backups': 'Copias de seguridad',
'dashboard.monitoring': 'Monitoreo',
'dashboard.security': 'Seguridad',
'service.status.healthy': 'Saludable',
'service.status.degraded': 'Degradado',
'service.status.down': 'Caído',
'service.status.unknown': 'Desconocido',
'service.status.pending': 'Pendiente',
'action.start': 'Iniciar',
'action.stop': 'Detener',
'action.restart': 'Reiniciar',
'action.delete': 'Eliminar',
'action.update': 'Actualizar',
'action.deploy': 'Desplegar',
'action.save': 'Guardar',
'action.cancel': 'Cancelar',
'action.confirm': 'Confirmar',
'error.not_found': 'Recurso no encontrado',
'error.unauthorized': 'No autorizado',
'error.forbidden': 'Prohibido',
'error.rate_limited': 'Demasiadas solicitudes',
'error.internal': 'Error interno del servidor',
'error.container_not_found': 'Contenedor no encontrado',
'error.service_not_found': 'Servicio no encontrado',
'error.invalid_input': 'Entrada inválida',
'error.docker_unreachable': 'El demonio de Docker no es accesible',
'error.disk_full': 'Espacio en disco críticamente bajo',
ar: { // 🇸🇦 العربية
'dashboard.title': 'لوحة التحكم', 'dashboard.services': 'الخدمات', 'dashboard.containers': 'الحاويات',
'dashboard.health': 'الصحة', 'dashboard.settings': 'الإعدادات', 'dashboard.backups': 'النسخ الاحتياطية',
'dashboard.monitoring': 'المراقبة', 'dashboard.security': 'الأمان',
'service.status.healthy': 'سليم', 'service.status.degraded': 'متدهور', 'service.status.down': 'متوقف',
'service.status.unknown': 'غير معروف', 'service.status.pending': 'قيد الانتظار',
'action.start': 'تشغيل', 'action.stop': 'إيقاف', 'action.restart': 'إعادة تشغيل', 'action.delete': 'حذف',
'action.update': 'تحديث', 'action.deploy': 'نشر', 'action.save': 'حفظ', 'action.cancel': 'إلغاء',
'action.confirm': 'تأكيد',
'error.not_found': 'المورد غير موجود', 'error.unauthorized': 'غير مصرح', 'error.forbidden': 'محظور',
'error.rate_limited': 'طلبات كثيرة جداً', 'error.internal': 'خطأ داخلي في الخادم',
'error.container_not_found': 'الحاوية غير موجودة', 'error.service_not_found': 'الخدمة غير موجودة',
'error.invalid_input': 'إدخال غير صالح', 'error.docker_unreachable': 'لا يمكن الوصول إلى Docker',
'error.disk_full': 'مساحة القرص منخفضة بشكل حرج',
},
fr: {
'dashboard.title': 'Tableau de bord',
'dashboard.services': 'Services',
'dashboard.containers': 'Conteneurs',
'dashboard.health': 'Santé',
'dashboard.settings': 'Paramètres',
'dashboard.backups': 'Sauvegardes',
'dashboard.monitoring': 'Surveillance',
'dashboard.security': 'Sécurité',
'service.status.healthy': 'Sain',
'service.status.degraded': 'Dégradé',
'service.status.down': 'Hors ligne',
'service.status.unknown': 'Inconnu',
'service.status.pending': 'En attente',
'action.start': 'Démarrer',
'action.stop': 'Arrêter',
'action.restart': 'Redémarrer',
'action.delete': 'Supprimer',
'action.update': 'Mettre à jour',
'action.deploy': 'Déployer',
'action.save': 'Enregistrer',
'action.cancel': 'Annuler',
'action.confirm': 'Confirmer',
'error.not_found': 'Ressource introuvable',
'error.unauthorized': 'Non autorisé',
'error.forbidden': 'Interdit',
'error.rate_limited': 'Trop de requêtes',
'error.internal': 'Erreur interne du serveur',
'error.container_not_found': 'Conteneur introuvable',
'error.service_not_found': 'Service introuvable',
'error.invalid_input': 'Entrée invalide',
'error.docker_unreachable': 'Le démon Docker est injoignable',
'error.disk_full': 'Espace disque critique',
bn: { // 🇧🇩 বাংলা
'dashboard.title': 'ড্যাশবোর্ড', 'dashboard.services': 'পরিষেবা', 'dashboard.containers': 'কন্টেইনার',
'dashboard.health': 'স্বাস্থ্য', 'dashboard.settings': 'সেটিংস', 'dashboard.backups': 'ব্যাকআপ',
'dashboard.monitoring': 'নিরীক্ষণ', 'dashboard.security': 'নিরাপত্তা',
'service.status.healthy': 'সুস্থ', 'service.status.degraded': 'অবনমিত', 'service.status.down': 'বন্ধ',
'service.status.unknown': 'অজানা', 'service.status.pending': 'মুলতুবি',
'action.start': 'শুরু', 'action.stop': 'বন্ধ', 'action.restart': 'পুনরায় চালু', 'action.delete': 'মুছুন',
'action.update': 'আপডেট', 'action.deploy': 'স্থাপন', 'action.save': 'সংরক্ষণ', 'action.cancel': 'বাতিল',
'action.confirm': 'নিশ্চিত করুন',
'error.not_found': 'সম্পদ পাওয়া যায়নি', 'error.unauthorized': 'অননুমোদিত', 'error.forbidden': 'নিষিদ্ধ',
'error.rate_limited': 'অনেক বেশি অনুরোধ', 'error.internal': 'অভ্যন্তরীণ সার্ভার ত্রুটি',
'error.container_not_found': 'কন্টেইনার পাওয়া যায়নি', 'error.service_not_found': 'পরিষেবা পাওয়া যায়নি',
'error.invalid_input': 'অবৈধ ইনপুট', 'error.docker_unreachable': 'Docker ডেমনে পৌঁছানো যাচ্ছে না',
'error.disk_full': 'ডিস্ক স্থান সংকটজনকভাবে কম',
},
zh: {
'dashboard.title': '仪表盘',
'dashboard.services': '服务',
'dashboard.containers': '容器',
'dashboard.health': '健康',
'dashboard.settings': '设置',
'dashboard.backups': '备份',
'dashboard.monitoring': '监控',
'dashboard.security': '安全',
'service.status.healthy': '健康',
'service.status.degraded': '降级',
'service.status.down': '宕机',
'service.status.unknown': '未知',
'service.status.pending': '待处理',
'action.start': '启动',
'action.stop': '停止',
'action.restart': '重启',
'action.delete': '删除',
'action.update': '更新',
'action.deploy': '部署',
'action.save': '保存',
'action.cancel': '取消',
'action.confirm': '确认',
'error.not_found': '未找到资源',
'error.unauthorized': '未授权',
'error.forbidden': '禁止访问',
'error.rate_limited': '请求过多',
'error.internal': '内部服务器错误',
'error.container_not_found': '未找到容器',
'error.service_not_found': '未找到服务',
'error.invalid_input': '输入无效',
'error.docker_unreachable': '无法连接 Docker 守护进程',
'error.disk_full': '磁盘空间严重不足',
cs: { // 🇨🇿 Čeština
'dashboard.title': 'Nástěnka', 'dashboard.services': 'Služby', 'dashboard.containers': 'Kontejnery',
'dashboard.health': 'Stav', 'dashboard.settings': 'Nastavení', 'dashboard.backups': 'Zálohy',
'dashboard.monitoring': 'Sledování', 'dashboard.security': 'Zabezpečení',
'service.status.healthy': 'Zdravý', 'service.status.degraded': 'Zhoršený', 'service.status.down': 'Nedostupný',
'service.status.unknown': 'Neznámý', 'service.status.pending': 'Čeká',
'action.start': 'Spustit', 'action.stop': 'Zastavit', 'action.restart': 'Restartovat', 'action.delete': 'Smazat',
'action.update': 'Aktualizovat', 'action.deploy': 'Nasadit', 'action.save': 'Uložit', 'action.cancel': 'Zrušit',
'action.confirm': 'Potvrdit',
'error.not_found': 'Zdroj nenalezen', 'error.unauthorized': 'Neoprávněno', 'error.forbidden': 'Zakázáno',
'error.rate_limited': 'Příliš mnoho požadavků', 'error.internal': 'Interní chyba serveru',
'error.container_not_found': 'Kontejner nenalezen', 'error.service_not_found': 'Služba nenalezena',
'error.invalid_input': 'Neplatný vstup', 'error.docker_unreachable': 'Docker daemon není dostupný',
'error.disk_full': 'Místo na disku je kriticky nízké',
},
de: {
'dashboard.title': 'Dashboard',
'dashboard.services': 'Dienste',
'dashboard.containers': 'Container',
'dashboard.health': 'Zustand',
'dashboard.settings': 'Einstellungen',
'dashboard.backups': 'Backups',
'dashboard.monitoring': 'Überwachung',
'dashboard.security': 'Sicherheit',
'service.status.healthy': 'Gesund',
'service.status.degraded': 'Beeinträchtigt',
'service.status.down': 'Ausgefallen',
'service.status.unknown': 'Unbekannt',
'service.status.pending': 'Ausstehend',
'action.start': 'Starten',
'action.stop': 'Stopp',
'action.restart': 'Neustart',
'action.delete': 'Löschen',
'action.update': 'Aktualisieren',
'action.deploy': 'Bereitstellen',
'action.save': 'Speichern',
'action.cancel': 'Abbrechen',
da: { // 🇩🇰 Dansk
'dashboard.title': 'Instrumentbræt', 'dashboard.services': 'Tjenester', 'dashboard.containers': 'Containere',
'dashboard.health': 'Sundhed', 'dashboard.settings': 'Indstillinger', 'dashboard.backups': 'Sikkerhedskopier',
'dashboard.monitoring': 'Overvågning', 'dashboard.security': 'Sikkerhed',
'service.status.healthy': 'Sund', 'service.status.degraded': 'Forringet', 'service.status.down': 'Nede',
'service.status.unknown': 'Ukendt', 'service.status.pending': 'Afventer',
'action.start': 'Start', 'action.stop': 'Stop', 'action.restart': 'Genstart', 'action.delete': 'Slet',
'action.update': 'Opdater', 'action.deploy': 'Udrul', 'action.save': 'Gem', 'action.cancel': 'Annuller',
'action.confirm': 'Bekræft',
'error.not_found': 'Ressource ikke fundet', 'error.unauthorized': 'Ikke autoriseret', 'error.forbidden': 'Forbudt',
'error.rate_limited': 'For mange anmodninger', 'error.internal': 'Intern serverfejl',
'error.container_not_found': 'Container ikke fundet', 'error.service_not_found': 'Tjeneste ikke fundet',
'error.invalid_input': 'Ugyldigt input', 'error.docker_unreachable': 'Docker-daemon er ikke tilgængelig',
'error.disk_full': 'Diskpladsen er kritisk lav',
},
de: { // 🇩🇪 Deutsch
'dashboard.title': 'Dashboard', 'dashboard.services': 'Dienste', 'dashboard.containers': 'Container',
'dashboard.health': 'Zustand', 'dashboard.settings': 'Einstellungen', 'dashboard.backups': 'Backups',
'dashboard.monitoring': 'Überwachung', 'dashboard.security': 'Sicherheit',
'service.status.healthy': 'Gesund', 'service.status.degraded': 'Beeinträchtigt', 'service.status.down': 'Ausgefallen',
'service.status.unknown': 'Unbekannt', 'service.status.pending': 'Ausstehend',
'action.start': 'Starten', 'action.stop': 'Stopp', 'action.restart': 'Neustart', 'action.delete': 'Löschen',
'action.update': 'Aktualisieren', 'action.deploy': 'Bereitstellen', 'action.save': 'Speichern', 'action.cancel': 'Abbrechen',
'action.confirm': 'Bestätigen',
'error.not_found': 'Ressource nicht gefunden',
'error.unauthorized': 'Nicht autorisiert',
'error.forbidden': 'Verboten',
'error.rate_limited': 'Zu viele Anfragen',
'error.internal': 'Interner Serverfehler',
'error.container_not_found': 'Container nicht gefunden',
'error.service_not_found': 'Dienst nicht gefunden',
'error.invalid_input': 'Ungültige Eingabe',
'error.docker_unreachable': 'Docker-Daemon ist nicht erreichbar',
'error.not_found': 'Ressource nicht gefunden', 'error.unauthorized': 'Nicht autorisiert', 'error.forbidden': 'Verboten',
'error.rate_limited': 'Zu viele Anfragen', 'error.internal': 'Interner Serverfehler',
'error.container_not_found': 'Container nicht gefunden', 'error.service_not_found': 'Dienst nicht gefunden',
'error.invalid_input': 'Ungültige Eingabe', 'error.docker_unreachable': 'Docker-Daemon ist nicht erreichbar',
'error.disk_full': 'Speicherplatz kritisch niedrig',
},
ar: {
'dashboard.title': 'لوحة التحكم',
'dashboard.services': 'الخدمات',
'dashboard.containers': 'الحاويات',
'dashboard.health': 'الصحة',
'dashboard.settings': 'الإعدادات',
'dashboard.backups': 'النسخ الاحتياطية',
'dashboard.monitoring': 'المراقبة',
'dashboard.security': 'الأمان',
'service.status.healthy': 'سليم',
'service.status.degraded': 'متدهور',
'service.status.down': 'متوقف',
'service.status.unknown': 'غير معروف',
'service.status.pending': 'قيد الانتظار',
'action.start': 'تشغيل',
'action.stop': 'إيقاف',
'action.restart': 'إعادة تشغيل',
'action.delete': 'حذف',
'action.update': 'تحديث',
'action.deploy': 'نشر',
'action.save': 'حفظ',
'action.cancel': 'إلغاء',
'action.confirm': 'تأكيد',
'error.not_found': 'المورد غير موجود',
'error.unauthorized': 'غير مصرح',
'error.forbidden': 'محظور',
'error.rate_limited': 'طلبات كثيرة جداً',
'error.internal': 'خطأ داخلي في الخادم',
'error.container_not_found': 'الحاوية غير موجودة',
'error.service_not_found': 'الخدمة غير موجودة',
'error.invalid_input': 'إدخال غير صالح',
'error.docker_unreachable': 'لا يمكن الوصول إلى Docker',
'error.disk_full': 'مساحة القرص منخفضة بشكل حرج',
el: { // 🇬🇷 Ελληνικά
'dashboard.title': 'Πίνακας ελέγχου', 'dashboard.services': 'Υπηρεσίες', 'dashboard.containers': 'Κοντέινερ',
'dashboard.health': 'Υγεία', 'dashboard.settings': 'Ρυθμίσεις', 'dashboard.backups': 'Αντίγραφα ασφαλείας',
'dashboard.monitoring': 'Παρακολούθηση', 'dashboard.security': 'Ασφάλεια',
'service.status.healthy': 'Υγιής', 'service.status.degraded': 'Υποβαθμισμένος', 'service.status.down': 'Κάτω',
'service.status.unknown': 'Άγνωστος', 'service.status.pending': 'Εκκρεμής',
'action.start': 'Έναρξη', 'action.stop': 'Διακοπή', 'action.restart': 'Επανεκκίνηση', 'action.delete': 'Διαγραφή',
'action.update': 'Ενημέρωση', 'action.deploy': 'Ανάπτυξη', 'action.save': 'Αποθήκευση', 'action.cancel': 'Ακύρωση',
'action.confirm': 'Επιβεβαίωση',
'error.not_found': 'Ο πόρος δεν βρέθηκε', 'error.unauthorized': 'Μη εξουσιοδοτημένος', 'error.forbidden': 'Απαγορευμένο',
'error.rate_limited': 'Πάρα πολλά αιτήματα', 'error.internal': 'Εσωτερικό σφάλμα διακομιστή',
'error.container_not_found': 'Το κοντέινερ δεν βρέθηκε', 'error.service_not_found': 'Η υπηρεσία δεν βρέθηκε',
'error.invalid_input': 'Μη έγκυρη είσοδος', 'error.docker_unreachable': 'Ο δαίμονας Docker δεν είναι προσβάσιμος',
'error.disk_full': 'Ο χώρος δίσκου είναι κρίσιμα χαμηλός',
},
es: { // 🇪🇸 Español
'dashboard.title': 'Panel de control', 'dashboard.services': 'Servicios', 'dashboard.containers': 'Contenedores',
'dashboard.health': 'Salud', 'dashboard.settings': 'Configuración', 'dashboard.backups': 'Copias de seguridad',
'dashboard.monitoring': 'Monitoreo', 'dashboard.security': 'Seguridad',
'service.status.healthy': 'Saludable', 'service.status.degraded': 'Degradado', 'service.status.down': 'Caído',
'service.status.unknown': 'Desconocido', 'service.status.pending': 'Pendiente',
'action.start': 'Iniciar', 'action.stop': 'Detener', 'action.restart': 'Reiniciar', 'action.delete': 'Eliminar',
'action.update': 'Actualizar', 'action.deploy': 'Desplegar', 'action.save': 'Guardar', 'action.cancel': 'Cancelar',
'action.confirm': 'Confirmar',
'error.not_found': 'Recurso no encontrado', 'error.unauthorized': 'No autorizado', 'error.forbidden': 'Prohibido',
'error.rate_limited': 'Demasiadas solicitudes', 'error.internal': 'Error interno del servidor',
'error.container_not_found': 'Contenedor no encontrado', 'error.service_not_found': 'Servicio no encontrado',
'error.invalid_input': 'Entrada inválida', 'error.docker_unreachable': 'El demonio de Docker no es accesible',
'error.disk_full': 'Espacio en disco críticamente bajo',
},
fa: { // 🇮🇷 فارسی
'dashboard.title': 'داشبورد', 'dashboard.services': 'سرویس‌ها', 'dashboard.containers': 'کانتینرها',
'dashboard.health': 'سلامت', 'dashboard.settings': 'تنظیمات', 'dashboard.backups': 'پشتیبان‌گیری',
'dashboard.monitoring': 'نظارت', 'dashboard.security': 'امنیت',
'service.status.healthy': 'سالم', 'service.status.degraded': 'تنزل‌یافته', 'service.status.down': 'خراب',
'service.status.unknown': 'نامشخص', 'service.status.pending': 'در انتظار',
'action.start': 'شروع', 'action.stop': 'توقف', 'action.restart': 'راه‌اندازی مجدد', 'action.delete': 'حذف',
'action.update': 'به‌روزرسانی', 'action.deploy': 'استقرار', 'action.save': 'ذخیره', 'action.cancel': 'لغو',
'action.confirm': 'تأیید',
'error.not_found': 'منبع یافت نشد', 'error.unauthorized': 'غیرمجاز', 'error.forbidden': 'ممنوع',
'error.rate_limited': 'درخواست‌های بیش از حد', 'error.internal': 'خطای داخلی سرور',
'error.container_not_found': 'کانتینر یافت نشد', 'error.service_not_found': 'سرویس یافت نشد',
'error.invalid_input': 'ورودی نامعتبر', 'error.docker_unreachable': 'دسترسی به Docker daemon ممکن نیست',
'error.disk_full': 'فضای دیسک به‌طور بحرانی کم است',
},
fi: { // 🇫🇮 Suomi
'dashboard.title': 'Ohjauspaneeli', 'dashboard.services': 'Palvelut', 'dashboard.containers': 'Kontainerit',
'dashboard.health': 'Terveys', 'dashboard.settings': 'Asetukset', 'dashboard.backups': 'Varmuuskopiot',
'dashboard.monitoring': 'Valvonta', 'dashboard.security': 'Turvallisuus',
'service.status.healthy': 'Terve', 'service.status.degraded': 'Heikentynyt', 'service.status.down': 'Alhaalla',
'service.status.unknown': 'Tuntematon', 'service.status.pending': 'Odottaa',
'action.start': 'Käynnistä', 'action.stop': 'Pysäytä', 'action.restart': 'Käynnistä uudelleen', 'action.delete': 'Poista',
'action.update': 'Päivitä', 'action.deploy': 'Käyttöönotto', 'action.save': 'Tallenna', 'action.cancel': 'Peruuta',
'action.confirm': 'Vahvista',
'error.not_found': 'Resurssia ei löytynyt', 'error.unauthorized': 'Ei valtuutettu', 'error.forbidden': 'Kielletty',
'error.rate_limited': 'Liian monta pyyntöä', 'error.internal': 'Sisäinen palvelinvirhe',
'error.container_not_found': 'Kontaineria ei löytynyt', 'error.service_not_found': 'Palvelua ei löytynyt',
'error.invalid_input': 'Virheellinen syöte', 'error.docker_unreachable': 'Docker-daemoniin ei saada yhteyttä',
'error.disk_full': 'Levytila on kriittisesti vähissä',
},
fr: { // 🇫🇷 Français
'dashboard.title': 'Tableau de bord', 'dashboard.services': 'Services', 'dashboard.containers': 'Conteneurs',
'dashboard.health': 'Santé', 'dashboard.settings': 'Paramètres', 'dashboard.backups': 'Sauvegardes',
'dashboard.monitoring': 'Surveillance', 'dashboard.security': 'Sécurité',
'service.status.healthy': 'Sain', 'service.status.degraded': 'Dégradé', 'service.status.down': 'Hors ligne',
'service.status.unknown': 'Inconnu', 'service.status.pending': 'En attente',
'action.start': 'Démarrer', 'action.stop': 'Arrêter', 'action.restart': 'Redémarrer', 'action.delete': 'Supprimer',
'action.update': 'Mettre à jour', 'action.deploy': 'Déployer', 'action.save': 'Enregistrer', 'action.cancel': 'Annuler',
'action.confirm': 'Confirmer',
'error.not_found': 'Ressource introuvable', 'error.unauthorized': 'Non autorisé', 'error.forbidden': 'Interdit',
'error.rate_limited': 'Trop de requêtes', 'error.internal': 'Erreur interne du serveur',
'error.container_not_found': 'Conteneur introuvable', 'error.service_not_found': 'Service introuvable',
'error.invalid_input': 'Entrée invalide', 'error.docker_unreachable': 'Le démon Docker est injoignable',
'error.disk_full': 'Espace disque critique',
},
hi: { // 🇮🇳 हिन्दी
'dashboard.title': 'डैशबोर्ड', 'dashboard.services': 'सेवाएं', 'dashboard.containers': 'कंटेनर',
'dashboard.health': 'स्वास्थ्य', 'dashboard.settings': 'सेटिंग्स', 'dashboard.backups': 'बैकअप',
'dashboard.monitoring': 'निगरानी', 'dashboard.security': 'सुरक्षा',
'service.status.healthy': 'स्वस्थ', 'service.status.degraded': 'क्षतिग्रस्त', 'service.status.down': 'बंद',
'service.status.unknown': 'अज्ञात', 'service.status.pending': 'लंबित',
'action.start': 'शुरू करें', 'action.stop': 'रोकें', 'action.restart': 'पुनर्प्रारंभ', 'action.delete': 'हटाएं',
'action.update': 'अपडेट', 'action.deploy': 'तैनात', 'action.save': 'सहेजें', 'action.cancel': 'रद्द करें',
'action.confirm': 'पुष्टि करें',
'error.not_found': 'संसाधन नहीं मिला', 'error.unauthorized': 'अनधिकृत', 'error.forbidden': 'निषिद्ध',
'error.rate_limited': 'बहुत अधिक अनुरोध', 'error.internal': 'आंतरिक सर्वर त्रुटि',
'error.container_not_found': 'कंटेनर नहीं मिला', 'error.service_not_found': 'सेवा नहीं मिली',
'error.invalid_input': 'अमान्य इनपुट', 'error.docker_unreachable': 'Docker डेमन तक नहीं पहुंच सकते',
'error.disk_full': 'डिस्क स्थान गंभीर रूप से कम है',
},
hu: { // 🇭🇺 Magyar
'dashboard.title': 'Vezérlőpult', 'dashboard.services': 'Szolgáltatások', 'dashboard.containers': 'Konténerek',
'dashboard.health': 'Állapot', 'dashboard.settings': 'Beállítások', 'dashboard.backups': 'Biztonsági mentések',
'dashboard.monitoring': 'Figyelés', 'dashboard.security': 'Biztonság',
'service.status.healthy': 'Egészséges', 'service.status.degraded': 'Csökkentett', 'service.status.down': 'Leállt',
'service.status.unknown': 'Ismeretlen', 'service.status.pending': 'Függőben',
'action.start': 'Indítás', 'action.stop': 'Leállítás', 'action.restart': 'Újraindítás', 'action.delete': 'Törlés',
'action.update': 'Frissítés', 'action.deploy': 'Telepítés', 'action.save': 'Mentés', 'action.cancel': 'Mégse',
'action.confirm': 'Megerősítés',
'error.not_found': 'Az erőforrás nem található', 'error.unauthorized': 'Nem engedélyezett', 'error.forbidden': 'Tiltott',
'error.rate_limited': 'Túl sok kérés', 'error.internal': 'Belső kiszolgálóhiba',
'error.container_not_found': 'A konténer nem található', 'error.service_not_found': 'A szolgáltatás nem található',
'error.invalid_input': 'Érvénytelen bemenet', 'error.docker_unreachable': 'A Docker démon nem érhető el',
'error.disk_full': 'A lemezterület kritikusan alacsony',
},
id: { // 🇮🇩 Indonesia
'dashboard.title': 'Dasbor', 'dashboard.services': 'Layanan', 'dashboard.containers': 'Kontainer',
'dashboard.health': 'Kesehatan', 'dashboard.settings': 'Pengaturan', 'dashboard.backups': 'Pencadangan',
'dashboard.monitoring': 'Pemantauan', 'dashboard.security': 'Keamanan',
'service.status.healthy': 'Sehat', 'service.status.degraded': 'Terkikis', 'service.status.down': 'Mati',
'service.status.unknown': 'Tidak diketahui', 'service.status.pending': 'Tertunda',
'action.start': 'Mulai', 'action.stop': 'Berhenti', 'action.restart': 'Mulai ulang', 'action.delete': 'Hapus',
'action.update': 'Perbarui', 'action.deploy': 'Sebarkan', 'action.save': 'Simpan', 'action.cancel': 'Batal',
'action.confirm': 'Konfirmasi',
'error.not_found': 'Sumber daya tidak ditemukan', 'error.unauthorized': 'Tidak berwenang', 'error.forbidden': 'Dilarang',
'error.rate_limited': 'Terlalu banyak permintaan', 'error.internal': 'Kesalahan server internal',
'error.container_not_found': 'Kontainer tidak ditemukan', 'error.service_not_found': 'Layanan tidak ditemukan',
'error.invalid_input': 'Input tidak valid', 'error.docker_unreachable': 'Daemon Docker tidak dapat dijangkau',
'error.disk_full': 'Ruang disk sangat rendah',
},
it: { // 🇮🇹 Italiano
'dashboard.title': 'Cruscotto', 'dashboard.services': 'Servizi', 'dashboard.containers': 'Contenitori',
'dashboard.health': 'Salute', 'dashboard.settings': 'Impostazioni', 'dashboard.backups': 'Backup',
'dashboard.monitoring': 'Monitoraggio', 'dashboard.security': 'Sicurezza',
'service.status.healthy': 'Salutare', 'service.status.degraded': 'Danneggiato', 'service.status.down': 'Inattivo',
'service.status.unknown': 'Sconosciuto', 'service.status.pending': 'In attesa',
'action.start': 'Avvia', 'action.stop': 'Ferma', 'action.restart': 'Riavvia', 'action.delete': 'Elimina',
'action.update': 'Aggiorna', 'action.deploy': 'Distribuisci', 'action.save': 'Salva', 'action.cancel': 'Annulla',
'action.confirm': 'Conferma',
'error.not_found': 'Risorsa non trovata', 'error.unauthorized': 'Non autorizzato', 'error.forbidden': 'Vietato',
'error.rate_limited': 'Troppe richieste', 'error.internal': 'Errore interno del server',
'error.container_not_found': 'Contenitore non trovato', 'error.service_not_found': 'Servizio non trovato',
'error.invalid_input': 'Input non valido', 'error.docker_unreachable': 'Il daemon Docker non è raggiungibile',
'error.disk_full': 'Spazio su disco criticamente basso',
},
ja: { // 🇯🇵 日本語
'dashboard.title': 'ダッシュボード', 'dashboard.services': 'サービス', 'dashboard.containers': 'コンテナ',
'dashboard.health': 'ヘルス', 'dashboard.settings': '設定', 'dashboard.backups': 'バックアップ',
'dashboard.monitoring': '監視', 'dashboard.security': 'セキュリティ',
'service.status.healthy': '正常', 'service.status.degraded': '低下', 'service.status.down': '停止',
'service.status.unknown': '不明', 'service.status.pending': '保留中',
'action.start': '開始', 'action.stop': '停止', 'action.restart': '再起動', 'action.delete': '削除',
'action.update': '更新', 'action.deploy': 'デプロイ', 'action.save': '保存', 'action.cancel': 'キャンセル',
'action.confirm': '確認',
'error.not_found': 'リソースが見つかりません', 'error.unauthorized': '認証されていません', 'error.forbidden': '禁止されています',
'error.rate_limited': 'リクエストが多すぎます', 'error.internal': '内部サーバーエラー',
'error.container_not_found': 'コンテナが見つかりません', 'error.service_not_found': 'サービスが見つかりません',
'error.invalid_input': '無効な入力', 'error.docker_unreachable': 'Dockerデーモンに接続できません',
'error.disk_full': 'ディスク容量が致命的に不足しています',
},
ko: { // 🇰🇷 한국어
'dashboard.title': '대시보드', 'dashboard.services': '서비스', 'dashboard.containers': '컨테이너',
'dashboard.health': '상태', 'dashboard.settings': '설정', 'dashboard.backups': '백업',
'dashboard.monitoring': '모니터링', 'dashboard.security': '보안',
'service.status.healthy': '정상', 'service.status.degraded': '성능 저하', 'service.status.down': '중단',
'service.status.unknown': '알 수 없음', 'service.status.pending': '대기 중',
'action.start': '시작', 'action.stop': '중지', 'action.restart': '재시작', 'action.delete': '삭제',
'action.update': '업데이트', 'action.deploy': '배포', 'action.save': '저장', 'action.cancel': '취소',
'action.confirm': '확인',
'error.not_found': '리소스를 찾을 수 없습니다', 'error.unauthorized': '인증되지 않음', 'error.forbidden': '금지됨',
'error.rate_limited': '요청이 너무 많습니다', 'error.internal': '내부 서버 오류',
'error.container_not_found': '컨테이너를 찾을 수 없습니다', 'error.service_not_found': '서비스를 찾을 수 없습니다',
'error.invalid_input': '잘못된 입력', 'error.docker_unreachable': 'Docker 데몬에 연결할 수 없습니다',
'error.disk_full': '디스크 공간이 심각하게 부족합니다',
},
ms: { // 🇲🇾 Melayu
'dashboard.title': 'Papan pemuka', 'dashboard.services': 'Perkhidmatan', 'dashboard.containers': 'Bekas',
'dashboard.health': 'Kesihatan', 'dashboard.settings': 'Tetapan', 'dashboard.backups': 'Sandaran',
'dashboard.monitoring': 'Pemantauan', 'dashboard.security': 'Keselamatan',
'service.status.healthy': 'Sihat', 'service.status.degraded': 'Merosot', 'service.status.down': 'Tergendala',
'service.status.unknown': 'Tidak diketahui', 'service.status.pending': 'Belum selesai',
'action.start': 'Mula', 'action.stop': 'Berhenti', 'action.restart': 'Mulakan semula', 'action.delete': 'Padam',
'action.update': 'Kemas kini', 'action.deploy': 'Lancarkan', 'action.save': 'Simpan', 'action.cancel': 'Batal',
'action.confirm': 'Sahkan',
'error.not_found': 'Sumber tidak dijumpai', 'error.unauthorized': 'Tidak dibenarkan', 'error.forbidden': 'Dilarang',
'error.rate_limited': 'Terlalu banyak permintaan', 'error.internal': 'Ralat pelayan dalaman',
'error.container_not_found': 'Bekas tidak dijumpai', 'error.service_not_found': 'Perkhidmatan tidak dijumpai',
'error.invalid_input': 'Input tidak sah', 'error.docker_unreachable': 'Docker daemon tidak dapat dijangkau',
'error.disk_full': 'Ruang cakera sangat kritikal',
},
nl: { // 🇳🇱 Nederlands
'dashboard.title': 'Dashboard', 'dashboard.services': 'Diensten', 'dashboard.containers': 'Containers',
'dashboard.health': 'Status', 'dashboard.settings': 'Instellingen', 'dashboard.backups': 'Backups',
'dashboard.monitoring': 'Bewaking', 'dashboard.security': 'Beveiliging',
'service.status.healthy': 'Gezond', 'service.status.degraded': 'Achteruitgegaan', 'service.status.down': 'Offline',
'service.status.unknown': 'Onbekend', 'service.status.pending': 'In afwachting',
'action.start': 'Starten', 'action.stop': 'Stoppen', 'action.restart': 'Herstarten', 'action.delete': 'Verwijderen',
'action.update': 'Bijwerken', 'action.deploy': 'Uitrollen', 'action.save': 'Opslaan', 'action.cancel': 'Annuleren',
'action.confirm': 'Bevestigen',
'error.not_found': 'Bron niet gevonden', 'error.unauthorized': 'Niet geautoriseerd', 'error.forbidden': 'Verboden',
'error.rate_limited': 'Te veel verzoeken', 'error.internal': 'Interne serverfout',
'error.container_not_found': 'Container niet gevonden', 'error.service_not_found': 'Dienst niet gevonden',
'error.invalid_input': 'Ongeldige invoer', 'error.docker_unreachable': 'Docker-daemon is niet bereikbaar',
'error.disk_full': 'Schijfruimte kritiek laag',
},
no: { // 🇳🇴 Norsk
'dashboard.title': 'Kontrollpanel', 'dashboard.services': 'Tjenester', 'dashboard.containers': 'Beholdere',
'dashboard.health': 'Helse', 'dashboard.settings': 'Innstillinger', 'dashboard.backups': 'Sikkerhetskopier',
'dashboard.monitoring': 'Overvåking', 'dashboard.security': 'Sikkerhet',
'service.status.healthy': 'Sunn', 'service.status.degraded': 'Forringet', 'service.status.down': 'Nede',
'service.status.unknown': 'Ukjent', 'service.status.pending': 'Venter',
'action.start': 'Start', 'action.stop': 'Stopp', 'action.restart': 'Omstart', 'action.delete': 'Slett',
'action.update': 'Oppdater', 'action.deploy': 'Rull ut', 'action.save': 'Lagre', 'action.cancel': 'Avbryt',
'action.confirm': 'Bekreft',
'error.not_found': 'Ressurs ikke funnet', 'error.unauthorized': 'Ikke autorisert', 'error.forbidden': 'Forbudt',
'error.rate_limited': 'For mange forespørsler', 'error.internal': 'Intern serverfeil',
'error.container_not_found': 'Beholder ikke funnet', 'error.service_not_found': 'Tjeneste ikke funnet',
'error.invalid_input': 'Ugyldig inndata', 'error.docker_unreachable': 'Docker-daemon er ikke tilgjengelig',
'error.disk_full': 'Diskplassen er kritisk lav',
},
pl: { // 🇵🇱 Polski
'dashboard.title': 'Panel', 'dashboard.services': 'Usługi', 'dashboard.containers': 'Kontenery',
'dashboard.health': 'Zdrowie', 'dashboard.settings': 'Ustawienia', 'dashboard.backups': 'Kopie zapasowe',
'dashboard.monitoring': 'Monitorowanie', 'dashboard.security': 'Bezpieczeństwo',
'service.status.healthy': 'Zdrowy', 'service.status.degraded': 'Naruszony', 'service.status.down': 'Nie działa',
'service.status.unknown': 'Nieznany', 'service.status.pending': 'Oczekuje',
'action.start': 'Uruchom', 'action.stop': 'Zatrzymaj', 'action.restart': 'Uruchom ponownie', 'action.delete': 'Usuń',
'action.update': 'Aktualizuj', 'action.deploy': 'Wdróż', 'action.save': 'Zapisz', 'action.cancel': 'Anuluj',
'action.confirm': 'Potwierdź',
'error.not_found': 'Nie znaleziono zasobu', 'error.unauthorized': 'Brak autoryzacji', 'error.forbidden': 'Zabronione',
'error.rate_limited': 'Zbyt wiele żądań', 'error.internal': 'Wewnętrzny błąd serwera',
'error.container_not_found': 'Nie znaleziono kontenera', 'error.service_not_found': 'Nie znaleziono usługi',
'error.invalid_input': 'Nieprawidłowe dane wejściowe', 'error.docker_unreachable': 'Daemon Docker jest niedostępny',
'error.disk_full': 'Krytycznie mało miejsca na dysku',
},
pt: { // 🇵🇹 Português
'dashboard.title': 'Painel', 'dashboard.services': 'Serviços', 'dashboard.containers': 'Contêineres',
'dashboard.health': 'Saúde', 'dashboard.settings': 'Configurações', 'dashboard.backups': 'Backups',
'dashboard.monitoring': 'Monitoramento', 'dashboard.security': 'Segurança',
'service.status.healthy': 'Saudável', 'service.status.degraded': 'Degradado', 'service.status.down': 'Inativo',
'service.status.unknown': 'Desconhecido', 'service.status.pending': 'Pendente',
'action.start': 'Iniciar', 'action.stop': 'Parar', 'action.restart': 'Reiniciar', 'action.delete': 'Excluir',
'action.update': 'Atualizar', 'action.deploy': 'Implantar', 'action.save': 'Salvar', 'action.cancel': 'Cancelar',
'action.confirm': 'Confirmar',
'error.not_found': 'Recurso não encontrado', 'error.unauthorized': 'Não autorizado', 'error.forbidden': 'Proibido',
'error.rate_limited': 'Muitas solicitações', 'error.internal': 'Erro interno do servidor',
'error.container_not_found': 'Contêiner não encontrado', 'error.service_not_found': 'Serviço não encontrado',
'error.invalid_input': 'Entrada inválida', 'error.docker_unreachable': 'Daemon do Docker inacessível',
'error.disk_full': 'Espaço em disco criticamente baixo',
},
ro: { // 🇷🇴 Română
'dashboard.title': 'Tablou de bord', 'dashboard.services': 'Servicii', 'dashboard.containers': 'Containere',
'dashboard.health': 'Stare', 'dashboard.settings': 'Setări', 'dashboard.backups': 'Copii de rezervă',
'dashboard.monitoring': 'Monitorizare', 'dashboard.security': 'Securitate',
'service.status.healthy': 'Sănătos', 'service.status.degraded': 'Degradat', 'service.status.down': 'Oprit',
'service.status.unknown': 'Necunoscut', 'service.status.pending': 'În așteptare',
'action.start': 'Pornește', 'action.stop': 'Oprește', 'action.restart': 'Repornește', 'action.delete': 'Șterge',
'action.update': 'Actualizează', 'action.deploy': 'Lansează', 'action.save': 'Salvează', 'action.cancel': 'Anulează',
'action.confirm': 'Confirmă',
'error.not_found': 'Resursă negăsită', 'error.unauthorized': 'Neautorizat', 'error.forbidden': 'Interzis',
'error.rate_limited': 'Prea multe cereri', 'error.internal': 'Eroare internă a serverului',
'error.container_not_found': 'Container negăsit', 'error.service_not_found': 'Serviciu negăsit',
'error.invalid_input': 'Intrare invalidă', 'error.docker_unreachable': 'Daemonul Docker nu poate fi contactat',
'error.disk_full': 'Spațiul pe disc este critic de scăzut',
},
ru: { // 🇷🇺 Русский
'dashboard.title': 'Панель управления', 'dashboard.services': 'Сервисы', 'dashboard.containers': 'Контейнеры',
'dashboard.health': 'Здоровье', 'dashboard.settings': 'Настройки', 'dashboard.backups': 'Резервные копии',
'dashboard.monitoring': 'Мониторинг', 'dashboard.security': 'Безопасность',
'service.status.healthy': 'Здоров', 'service.status.degraded': 'Деградирован', 'service.status.down': 'Не работает',
'service.status.unknown': 'Неизвестно', 'service.status.pending': 'Ожидание',
'action.start': 'Запустить', 'action.stop': 'Остановить', 'action.restart': 'Перезапустить', 'action.delete': 'Удалить',
'action.update': 'Обновить', 'action.deploy': 'Развернуть', 'action.save': 'Сохранить', 'action.cancel': 'Отмена',
'action.confirm': 'Подтвердить',
'error.not_found': 'Ресурс не найден', 'error.unauthorized': 'Не авторизован', 'error.forbidden': 'Запрещено',
'error.rate_limited': 'Слишком много запросов', 'error.internal': 'Внутренняя ошибка сервера',
'error.container_not_found': 'Контейнер не найден', 'error.service_not_found': 'Сервис не найден',
'error.invalid_input': 'Неверный ввод', 'error.docker_unreachable': 'Docker недоступен',
'error.disk_full': 'Критически мало места на диске',
},
sv: { // 🇸🇪 Svenska
'dashboard.title': 'Instrumentpanel', 'dashboard.services': 'Tjänster', 'dashboard.containers': 'Behållare',
'dashboard.health': 'Hälsa', 'dashboard.settings': 'Inställningar', 'dashboard.backups': 'Säkerhetskopior',
'dashboard.monitoring': 'Övervakning', 'dashboard.security': 'Säkerhet',
'service.status.healthy': 'Frisk', 'service.status.degraded': 'Nedsatt', 'service.status.down': 'Nere',
'service.status.unknown': 'Okänd', 'service.status.pending': 'Väntar',
'action.start': 'Starta', 'action.stop': 'Stoppa', 'action.restart': 'Starta om', 'action.delete': 'Ta bort',
'action.update': 'Uppdatera', 'action.deploy': 'Distribuera', 'action.save': 'Spara', 'action.cancel': 'Avbryt',
'action.confirm': 'Bekräfta',
'error.not_found': 'Resurs hittades inte', 'error.unauthorized': 'Obehörig', 'error.forbidden': 'Förbjuden',
'error.rate_limited': 'För många förfrågningar', 'error.internal': 'Internt serverfel',
'error.container_not_found': 'Behållare hittades inte', 'error.service_not_found': 'Tjänst hittades inte',
'error.invalid_input': 'Ogiltig inmatning', 'error.docker_unreachable': 'Docker-daemon kan inte nås',
'error.disk_full': 'Diskutrymmet är kritiskt lågt',
},
th: { // 🇹🇭 ไทย
'dashboard.title': 'แดชบอร์ด', 'dashboard.services': 'บริการ', 'dashboard.containers': 'คอนเทนเนอร์',
'dashboard.health': 'สถานะ', 'dashboard.settings': 'การตั้งค่า', 'dashboard.backups': 'การสำรองข้อมูล',
'dashboard.monitoring': 'การตรวจสอบ', 'dashboard.security': 'ความปลอดภัย',
'service.status.healthy': 'ปกติ', 'service.status.degraded': 'เสื่อม', 'service.status.down': 'ล่ม',
'service.status.unknown': 'ไม่ทราบ', 'service.status.pending': 'รอดำเนินการ',
'action.start': 'เริ่ม', 'action.stop': 'หยุด', 'action.restart': 'รีสตาร์ท', 'action.delete': 'ลบ',
'action.update': 'อัปเดต', 'action.deploy': 'ปรับใช้', 'action.save': 'บันทึก', 'action.cancel': 'ยกเลิก',
'action.confirm': 'ยืนยัน',
'error.not_found': 'ไม่พบทรัพยากร', 'error.unauthorized': 'ไม่ได้รับอนุญาต', 'error.forbidden': 'ห้าม',
'error.rate_limited': 'คำขอมากเกินไป', 'error.internal': 'ข้อผิดพลาดภายในเซิร์ฟเวอร์',
'error.container_not_found': 'ไม่พบคอนเทนเนอร์', 'error.service_not_found': 'ไม่พบบริการ',
'error.invalid_input': 'อินพุตไม่ถูกต้อง', 'error.docker_unreachable': 'ไม่สามารถเข้าถึง Docker daemon ได้',
'error.disk_full': 'พื้นที่ดิสก์เหลือน้อยวิกฤต',
},
tr: { // 🇹🇷 Türkçe
'dashboard.title': 'Kontrol Paneli', 'dashboard.services': 'Hizmetler', 'dashboard.containers': 'Konteynerler',
'dashboard.health': 'Sağlık', 'dashboard.settings': 'Ayarlar', 'dashboard.backups': 'Yedekler',
'dashboard.monitoring': 'İzleme', 'dashboard.security': 'Güvenlik',
'service.status.healthy': 'Sağlıklı', 'service.status.degraded': 'Bozulmuş', 'service.status.down': 'Çalışmıyor',
'service.status.unknown': 'Bilinmiyor', 'service.status.pending': 'Beklemede',
'action.start': 'Başlat', 'action.stop': 'Durdur', 'action.restart': 'Yeniden Başlat', 'action.delete': 'Sil',
'action.update': 'Güncelle', 'action.deploy': 'Dağıt', 'action.save': 'Kaydet', 'action.cancel': 'İptal',
'action.confirm': 'Onayla',
'error.not_found': 'Kaynak bulunamadı', 'error.unauthorized': 'Yetkisiz', 'error.forbidden': 'Yasak',
'error.rate_limited': 'Çok fazla istek', 'error.internal': 'Dahili sunucu hatası',
'error.container_not_found': 'Konteyner bulunamadı', 'error.service_not_found': 'Hizmet bulunamadı',
'error.invalid_input': 'Geçersiz giriş', 'error.docker_unreachable': 'Docker daemonuna ulaşılamıyor',
'error.disk_full': 'Disk alanı kritik düzeyde düşük',
},
uk: { // 🇺🇦 Українська
'dashboard.title': 'Панель керування', 'dashboard.services': 'Сервіси', 'dashboard.containers': 'Контейнери',
'dashboard.health': "Здоров'я", 'dashboard.settings': 'Налаштування', 'dashboard.backups': 'Резервні копії',
'dashboard.monitoring': 'Моніторинг', 'dashboard.security': 'Безпека',
'service.status.healthy': 'Здоровий', 'service.status.degraded': 'Деградований', 'service.status.down': 'Не працює',
'service.status.unknown': 'Невідомо', 'service.status.pending': 'Очікування',
'action.start': 'Запустити', 'action.stop': 'Зупинити', 'action.restart': 'Перезапустити', 'action.delete': 'Видалити',
'action.update': 'Оновити', 'action.deploy': 'Розгорнути', 'action.save': 'Зберегти', 'action.cancel': 'Скасувати',
'action.confirm': 'Підтвердити',
'error.not_found': 'Ресурс не знайдено', 'error.unauthorized': 'Не авторизовано', 'error.forbidden': 'Заборонено',
'error.rate_limited': 'Занадто багато запитів', 'error.internal': 'Внутрішня помилка сервера',
'error.container_not_found': 'Контейнер не знайдено', 'error.service_not_found': 'Сервіс не знайдено',
'error.invalid_input': 'Невірне введення', 'error.docker_unreachable': 'Docker недоступний',
'error.disk_full': 'Критично мало місця на диску',
},
ur: { // 🇵🇰 اردو
'dashboard.title': 'ڈیش بورڈ', 'dashboard.services': 'خدمات', 'dashboard.containers': 'کنٹینرز',
'dashboard.health': 'صحت', 'dashboard.settings': 'ترتیبات', 'dashboard.backups': 'بیک اپ',
'dashboard.monitoring': 'نگرانی', 'dashboard.security': 'تحفظ',
'service.status.healthy': 'صحت مند', 'service.status.degraded': 'خراب', 'service.status.down': 'بند',
'service.status.unknown': 'نامعلوم', 'service.status.pending': 'زیر التواء',
'action.start': 'شروع', 'action.stop': 'روک', 'action.restart': 'دوبارہ شروع', 'action.delete': 'حذف',
'action.update': 'اپڈیٹ', 'action.deploy': 'تعینات', 'action.save': 'محفوظ', 'action.cancel': 'منسوخ',
'action.confirm': 'تصدیق',
'error.not_found': 'وسائل نہیں ملے', 'error.unauthorized': 'غیر مجاز', 'error.forbidden': 'ممنوع',
'error.rate_limited': 'بہت زیادہ درخواستیں', 'error.internal': 'اندرونی سرور نقص',
'error.container_not_found': 'کنٹینر نہیں ملا', 'error.service_not_found': 'سروس نہیں ملی',
'error.invalid_input': 'غلط ان پٹ', 'error.docker_unreachable': 'Docker ڈیمن تک رسائی نہیں',
'error.disk_full': 'ڈسک کی جگہ نہایت کم ہے',
},
vi: { // 🇻🇳 Tiếng Việt
'dashboard.title': 'Bảng điều khiển', 'dashboard.services': 'Dịch vụ', 'dashboard.containers': 'Bộ chứa',
'dashboard.health': 'Tình trạng', 'dashboard.settings': 'Cài đặt', 'dashboard.backups': 'Sao lưu',
'dashboard.monitoring': 'Giám sát', 'dashboard.security': 'Bảo mật',
'service.status.healthy': 'Khỏe mạnh', 'service.status.degraded': 'Giảm', 'service.status.down': 'Ngừng',
'service.status.unknown': 'Không xác định', 'service.status.pending': 'Đang chờ',
'action.start': 'Bắt đầu', 'action.stop': 'Dừng', 'action.restart': 'Khởi động lại', 'action.delete': 'Xóa',
'action.update': 'Cập nhật', 'action.deploy': 'Triển khai', 'action.save': 'Lưu', 'action.cancel': 'Hủy',
'action.confirm': 'Xác nhận',
'error.not_found': 'Không tìm thấy tài nguyên', 'error.unauthorized': 'Không được phép', 'error.forbidden': 'Bị cấm',
'error.rate_limited': 'Quá nhiều yêu cầu', 'error.internal': 'Lỗi máy chủ nội bộ',
'error.container_not_found': 'Không tìm thấy bộ chứa', 'error.service_not_found': 'Không tìm thấy dịch vụ',
'error.invalid_input': 'Đầu vào không hợp lệ', 'error.docker_unreachable': 'Không thể kết nối với Docker daemon',
'error.disk_full': 'Không gian đĩa cực kỳ thấp',
},
zh: { // 🇨🇳 中文
'dashboard.title': '仪表盘', 'dashboard.services': '服务', 'dashboard.containers': '容器',
'dashboard.health': '健康', 'dashboard.settings': '设置', 'dashboard.backups': '备份',
'dashboard.monitoring': '监控', 'dashboard.security': '安全',
'service.status.healthy': '健康', 'service.status.degraded': '降级', 'service.status.down': '宕机',
'service.status.unknown': '未知', 'service.status.pending': '待处理',
'action.start': '启动', 'action.stop': '停止', 'action.restart': '重启', 'action.delete': '删除',
'action.update': '更新', 'action.deploy': '部署', 'action.save': '保存', 'action.cancel': '取消',
'action.confirm': '确认',
'error.not_found': '未找到资源', 'error.unauthorized': '未授权', 'error.forbidden': '禁止访问',
'error.rate_limited': '请求过多', 'error.internal': '内部服务器错误',
'error.container_not_found': '未找到容器', 'error.service_not_found': '未找到服务',
'error.invalid_input': '输入无效', 'error.docker_unreachable': '无法连接 Docker 守护进程',
'error.disk_full': '磁盘空间严重不足',
},
};
const SUPPORTED_LANGUAGES = Object.keys(TRANSLATIONS);
const DEFAULT_LANGUAGE = 'en';
/**
* Translate a key to the specified language.
* Falls back to English, then to the key itself if not found.
*/
function t(key, lang = DEFAULT_LANGUAGE) {
const dict = TRANSLATIONS[lang] || TRANSLATIONS[DEFAULT_LANGUAGE];
// Language metadata for UI dropdowns
const LANGUAGE_META = {
en: { name: 'English', flag: '🇬🇧', rtl: false },
ar: { name: 'العربية', flag: '🇸🇦', rtl: true },
bn: { name: 'বাংলা', flag: '🇧🇩', rtl: false },
cs: { name: 'Čeština', flag: '🇨🇿', rtl: false },
da: { name: 'Dansk', flag: '🇩🇰', rtl: false },
de: { name: 'Deutsch', flag: '🇩🇪', rtl: false },
el: { name: 'Ελληνικά', flag: '🇬🇷', rtl: false },
es: { name: 'Español', flag: '🇪🇸', rtl: false },
fa: { name: 'فارسی', flag: '🇮🇷', rtl: true },
fi: { name: 'Suomi', flag: '🇫🇮', rtl: false },
fr: { name: 'Français', flag: '🇫🇷', rtl: false },
hi: { name: 'हिन्दी', flag: '🇮🇳', rtl: false },
hu: { name: 'Magyar', flag: '🇭🇺', rtl: false },
id: { name: 'Indonesia', flag: '🇮🇩', rtl: false },
it: { name: 'Italiano', flag: '🇮🇹', rtl: false },
ja: { name: '日本語', flag: '🇯🇵', rtl: false },
ko: { name: '한국어', flag: '🇰🇷', rtl: false },
ms: { name: 'Melayu', flag: '🇲🇾', rtl: false },
nl: { name: 'Nederlands', flag: '🇳🇱', rtl: false },
no: { name: 'Norsk', flag: '🇳🇴', rtl: false },
pl: { name: 'Polski', flag: '🇵🇱', rtl: false },
pt: { name: 'Português', flag: '🇵🇹', rtl: false },
ro: { name: 'Română', flag: '🇷🇴', rtl: false },
ru: { name: 'Русский', flag: '🇷🇺', rtl: false },
sv: { name: 'Svenska', flag: '🇸🇪', rtl: false },
th: { name: 'ไทย', flag: '🇹🇭', rtl: false },
tr: { name: 'Türkçe', flag: '🇹🇷', rtl: false },
uk: { name: 'Українська', flag: '🇺🇦', rtl: false },
ur: { name: 'اردو', flag: '🇵🇰', rtl: true },
vi: { name: 'Tiếng Việt', flag: '🇻🇳', rtl: false },
zh: { name: '中文', flag: '🇨🇳', rtl: false },
};
function t(key, lang) {
lang = lang || DEFAULT_LANGUAGE;
var dict = TRANSLATIONS[lang] || TRANSLATIONS[DEFAULT_LANGUAGE];
return dict[key] || TRANSLATIONS[DEFAULT_LANGUAGE][key] || key;
}
/**
* Get the list of supported languages
*/
function getSupportedLanguages() {
return SUPPORTED_LANGUAGES;
}
/**
* Check if a language is supported
*/
function isSupported(lang) {
return SUPPORTED_LANGUAGES.includes(lang);
}
/**
* Detect language from Accept-Language header
*/
function getSupportedLanguages() { return SUPPORTED_LANGUAGES; }
function getLanguageMeta(lang) { return LANGUAGE_META[lang] || LANGUAGE_META[DEFAULT_LANGUAGE]; }
function getAllLanguages() { return LANGUAGE_META; }
function isRTL(lang) { return lang === 'ar' || lang === 'fa' || lang === 'ur'; }
function isSupported(lang) { return SUPPORTED_LANGUAGES.indexOf(lang) >= 0; }
function detectLanguage(acceptLanguage) {
if (!acceptLanguage) return DEFAULT_LANGUAGE;
const langs = acceptLanguage.split(',').map(l => {
const [code, q] = l.trim().split(';q=');
return { code: code.split('-')[0].toLowerCase(), q: q ? parseFloat(q) : 1 };
}).sort((a, b) => b.q - a.q);
for (const { code } of langs) {
var parts = acceptLanguage.split(',');
for (var i = 0; i < parts.length; i++) {
var code = parts[i].trim().split(';')[0].split('-')[0].toLowerCase();
if (isSupported(code)) return code;
}
return DEFAULT_LANGUAGE;
}
module.exports = {
t,
getSupportedLanguages,
isSupported,
detectLanguage,
DEFAULT_LANGUAGE,
TRANSLATIONS,
t, getSupportedLanguages, getLanguageMeta, getAllLanguages,
isRTL, isSupported, detectLanguage, DEFAULT_LANGUAGE,
TRANSLATIONS, LANGUAGE_META,
};