Fix NTP server config not reaching betterdesk-server (Fixes #223).

Wire billing/NTP env from console .env into Go on Linux, Windows, and Docker; add OS NTP fallback and Commercialization settings UI to configure and restart the server.
This commit is contained in:
UNITRONIX
2026-06-27 20:33:56 +02:00
parent 84a07c04d6
commit bb2ff08f65
45 changed files with 1564 additions and 47 deletions
+476
View File
@@ -0,0 +1,476 @@
#!/usr/bin/env node
'use strict';
const fs = require('fs');
const path = require('path');
const langDir = path.join(__dirname, '..', 'lang');
const locales = fs.readdirSync(langDir).filter((f) => f.endsWith('.json'));
const patches = {
ar: {
synced_detail: 'الساعة متزامنة للفوترة',
ntp_servers: 'خوادم NTP',
ntp_servers_hint: 'أسماء مضيفة أو عناوين IP مفصولة بفواصل. تُطبَّق على خادم Go (betterdesk-server).',
max_skew_ms: 'أقصى انحراف للساعة (مللي ثانية)',
require_sync: 'اشتراط ساعة متزامنة للجلسات القابلة للفوترة',
trust_os: 'الثقة بـ NTP للنظام عند فشل الاستعلامات المباشرة',
trust_os_hint: 'استخدم حالة systemd-timesyncd/chrony عند حظر UDP NTP (DMZ/جدار ناري).',
save: 'حفظ إعدادات NTP',
saved: 'تم حفظ إعدادات الساعة. بدء إعادة تشغيل خادم Go.',
save_restart: 'حفظ إعدادات NTP وإعادة تشغيل خادم Go؟ قد تنقطع الجلسات النشطة briefly.',
status_offset: 'الانحراف',
status_server: 'مصدر NTP',
status_os: 'ساعة OS متزامنة',
status_error: 'آخر خطأ',
os_yes: 'نعم',
os_no: 'لا',
},
cs: {
synced_detail: 'Hodiny synchronizovány pro fakturaci',
ntp_servers: 'NTP servery',
ntp_servers_hint: 'Názvy hostitelů nebo IP oddělené čárkou. Platí pro Go server (betterdesk-server).',
max_skew_ms: 'Maximální odchylka hodin (ms)',
require_sync: 'Vyžadovat synchronizované hodiny pro fakturovatelné relace',
trust_os: 'Důvěřovat OS NTP při selhání přímých dotazů',
trust_os_hint: 'Použít stav systemd-timesyncd/chrony, když je UDP NTP blokováno (DMZ/firewall).',
save: 'Uložit nastavení NTP',
saved: 'Nastavení hodin uloženo. Restart Go serveru spuštěn.',
save_restart: 'Uložit NTP a restartovat Go server? Aktivní relace se mohou krátce odpojit.',
status_offset: 'Odchylka',
status_server: 'Zdroj NTP',
status_os: 'OS hodiny synchronizovány',
status_error: 'Poslední chyba',
os_yes: 'Ano',
os_no: 'Ne',
},
da: {
synced_detail: 'Ur synkroniseret til fakturering',
ntp_servers: 'NTP-servere',
ntp_servers_hint: 'Kommaseparerede værtsnavne eller IP. Gælder Go-serveren (betterdesk-server).',
max_skew_ms: 'Maks. urafvigelse (ms)',
require_sync: 'Kræv synkroniseret ur for fakturerbare sessioner',
trust_os: 'Stol på OS NTP når direkte forespørgsler fejler',
trust_os_hint: 'Brug systemd-timesyncd/chrony-status når UDP NTP er blokeret (DMZ/firewall).',
save: 'Gem NTP-indstillinger',
saved: 'Urindstillinger gemt. Genstart af Go-server startet.',
save_restart: 'Gem NTP og genstart Go-serveren? Aktive sessioner kan kort afbrydes.',
status_offset: 'Afvigelse',
status_server: 'NTP-kilde',
status_os: 'OS-ur synkroniseret',
status_error: 'Seneste fejl',
os_yes: 'Ja',
os_no: 'Nej',
},
de: {
synced_detail: 'Uhr für Abrechnung synchronisiert',
ntp_servers: 'NTP-Server',
ntp_servers_hint: 'Kommagetrennte Hostnamen oder IPs. Gilt für den Go-Server (betterdesk-server).',
max_skew_ms: 'Maximale Uhrabweichung (ms)',
require_sync: 'Synchronisierte Uhr für abrechenbare Sitzungen erforderlich',
trust_os: 'OS-NTP vertrauen, wenn direkte Abfragen fehlschlagen',
trust_os_hint: 'systemd-timesyncd/chrony-Status nutzen, wenn UDP-NTP blockiert ist (DMZ/Firewall).',
save: 'NTP-Einstellungen speichern',
saved: 'Uhreinstellungen gespeichert. Go-Server-Neustart gestartet.',
save_restart: 'NTP speichern und Go-Server neu starten? Aktive Sitzungen können kurz trennen.',
status_offset: 'Abweichung',
status_server: 'NTP-Quelle',
status_os: 'OS-Uhr synchronisiert',
status_error: 'Letzter Fehler',
os_yes: 'Ja',
os_no: 'Nein',
},
es: {
synced_detail: 'Reloj sincronizado para facturación',
ntp_servers: 'Servidores NTP',
ntp_servers_hint: 'Nombres de host o IP separados por comas. Aplica al servidor Go (betterdesk-server).',
max_skew_ms: 'Desviación máxima del reloj (ms)',
require_sync: 'Exigir reloj sincronizado para sesiones facturables',
trust_os: 'Confiar en NTP del SO si fallan las consultas directas',
trust_os_hint: 'Usar estado systemd-timesyncd/chrony cuando UDP NTP esté bloqueado (DMZ/firewall).',
save: 'Guardar ajustes NTP',
saved: 'Ajustes de reloj guardados. Reinicio del servidor Go iniciado.',
save_restart: '¿Guardar NTP y reiniciar el servidor Go? Las sesiones activas pueden desconectarse brevemente.',
status_offset: 'Desviación',
status_server: 'Fuente NTP',
status_os: 'Reloj del SO sincronizado',
status_error: 'Último error',
os_yes: 'Sí',
os_no: 'No',
},
fi: {
synced_detail: 'Kello synkronoitu laskutusta varten',
ntp_servers: 'NTP-palvelimet',
ntp_servers_hint: 'Pilkuilla erotetut isäntänimet tai IP:t. Koskee Go-palvelinta (betterdesk-server).',
max_skew_ms: 'Suurin kelloero (ms)',
require_sync: 'Vaadi synkronoitu kello laskutettaville istunnoille',
trust_os: 'Luota OS NTP:hen kun suorat kyselyt epäonnistuvat',
trust_os_hint: 'Käytä systemd-timesyncd/chrony-tilaa kun UDP NTP on estetty (DMZ/palomuuri).',
save: 'Tallenna NTP-asetukset',
saved: 'Kelloasetukset tallennettu. Go-palvelimen uudelleenkäynnistys käynnistetty.',
save_restart: 'Tallenna NTP ja käynnistä Go-palvelin uudelleen? Aktiiviset istunnot voivat katketa hetkeksi.',
status_offset: 'Ero',
status_server: 'NTP-lähde',
status_os: 'OS-kello synkronoitu',
status_error: 'Viimeisin virhe',
os_yes: 'Kyllä',
os_no: 'Ei',
},
fr: {
synced_detail: 'Horloge synchronisée pour la facturation',
ntp_servers: 'Serveurs NTP',
ntp_servers_hint: 'Noms d\'hôte ou IP séparés par des virgules. Appliqué au serveur Go (betterdesk-server).',
max_skew_ms: 'Décalage horaire max. (ms)',
require_sync: 'Exiger une horloge synchronisée pour les sessions facturables',
trust_os: 'Faire confiance au NTP OS si les requêtes directes échouent',
trust_os_hint: 'Utiliser l\'état systemd-timesyncd/chrony quand l\'UDP NTP est bloqué (DMZ/pare-feu).',
save: 'Enregistrer les paramètres NTP',
saved: 'Paramètres d\'horloge enregistrés. Redémarrage du serveur Go lancé.',
save_restart: 'Enregistrer le NTP et redémarrer le serveur Go ? Les sessions actives peuvent se déconnecter brièvement.',
status_offset: 'Décalage',
status_server: 'Source NTP',
status_os: 'Horloge OS synchronisée',
status_error: 'Dernière erreur',
os_yes: 'Oui',
os_no: 'Non',
},
hi: {
synced_detail: 'बिलिंग के लिए घड़ी सिंक',
ntp_servers: 'NTP सर्वर',
ntp_servers_hint: 'अल्पविराम से अलग होस्टनाम या IP। Go सर्वर (betterdesk-server) पर लागू।',
max_skew_ms: 'अधिकतम घड़ी विचलन (ms)',
require_sync: 'बिल योग्य सत्रों के लिए सिंक घड़ी आवश्यक',
trust_os: 'प्रत्यक्ष क्वेरी विफल होने पर OS NTP पर भरोसा करें',
trust_os_hint: 'UDP NTP अवरुद्ध होने पर systemd-timesyncd/chrony स्थिति का उपयोग करें।',
save: 'NTP सेटिंग्स सहेजें',
saved: 'घड़ी सेटिंग्स सहेजी गईं। Go सर्वर पुनः आरंभ शुरू।',
save_restart: 'NTP सहेजें और Go सर्वर पुनः आरंभ करें? सक्रिय सत्र briefly डिस्कनेक्ट हो सकते हैं।',
status_offset: 'ऑफ़सेट',
status_server: 'NTP स्रोत',
status_os: 'OS घड़ी सिंक',
status_error: 'अंतिम त्रुटि',
os_yes: 'हाँ',
os_no: 'नहीं',
},
hu: {
synced_detail: 'Óra szinkronizálva számlázáshoz',
ntp_servers: 'NTP szerverek',
ntp_servers_hint: 'Vesszővel elválasztott hostnevek vagy IP-k. A Go szerverre (betterdesk-server) vonatkozik.',
max_skew_ms: 'Max. óraeltérés (ms)',
require_sync: 'Szinkronizált óra kötelező számlázható munkamenetekhez',
trust_os: 'Bízzon az OS NTP-ben, ha a közvetlen lekérdezések sikertelenek',
trust_os_hint: 'Használja a systemd-timesyncd/chrony állapotot, ha az UDP NTP blokkolva van.',
save: 'NTP beállítások mentése',
saved: 'Óra beállítások mentve. Go szerver újraindítás elindítva.',
save_restart: 'Mentse az NTP-t és indítsa újra a Go szervert? Az aktív munkamenetek rövid ideig megszakadhatnak.',
status_offset: 'Eltérés',
status_server: 'NTP forrás',
status_os: 'OS óra szinkronizálva',
status_error: 'Utolsó hiba',
os_yes: 'Igen',
os_no: 'Nem',
},
id: {
synced_detail: 'Jam disinkronkan untuk penagihan',
ntp_servers: 'Server NTP',
ntp_servers_hint: 'Nama host atau IP dipisah koma. Berlaku untuk server Go (betterdesk-server).',
max_skew_ms: 'Selisih jam maksimum (ms)',
require_sync: 'Wajib jam tersinkron untuk sesi berbayar',
trust_os: 'Percayai NTP OS jika kueri langsung gagal',
trust_os_hint: 'Gunakan status systemd-timesyncd/chrony saat UDP NTP diblokir (DMZ/firewall).',
save: 'Simpan pengaturan NTP',
saved: 'Pengaturan jam disimpan. Restart server Go dimulai.',
save_restart: 'Simpan NTP dan restart server Go? Sesi aktif mungkin terputus sebentar.',
status_offset: 'Offset',
status_server: 'Sumber NTP',
status_os: 'Jam OS tersinkron',
status_error: 'Kesalahan terakhir',
os_yes: 'Ya',
os_no: 'Tidak',
},
it: {
synced_detail: 'Orologio sincronizzato per la fatturazione',
ntp_servers: 'Server NTP',
ntp_servers_hint: 'Hostname o IP separati da virgola. Si applica al server Go (betterdesk-server).',
max_skew_ms: 'Scostamento orario massimo (ms)',
require_sync: 'Richiedi orologio sincronizzato per sessioni fatturabili',
trust_os: 'Affidati all\'NTP del SO se le query dirette falliscono',
trust_os_hint: 'Usa lo stato systemd-timesyncd/chrony quando l\'UDP NTP è bloccato (DMZ/firewall).',
save: 'Salva impostazioni NTP',
saved: 'Impostazioni orologio salvate. Riavvio server Go avviato.',
save_restart: 'Salvare NTP e riavviare il server Go? Le sessioni attive possono disconnettersi brevemente.',
status_offset: 'Scostamento',
status_server: 'Fonte NTP',
status_os: 'Orologio OS sincronizzato',
status_error: 'Ultimo errore',
os_yes: 'Sì',
os_no: 'No',
},
ja: {
synced_detail: '課金用に時計が同期されています',
ntp_servers: 'NTPサーバー',
ntp_servers_hint: 'カンマ区切りのホスト名またはIP。Goサーバー(betterdesk-server)に適用されます。',
max_skew_ms: '最大時刻ずれ (ms)',
require_sync: '課金セッションに同期時計を必須にする',
trust_os: '直接クエリ失敗時はOS NTPを信頼',
trust_os_hint: 'UDP NTPがブロックされている場合は systemd-timesyncd/chrony の状態を使用。',
save: 'NTP設定を保存',
saved: '時計設定を保存しました。Goサーバーの再起動を開始しました。',
save_restart: 'NTPを保存してGoサーバーを再起動しますか?アクティブなセッションが一時的に切断される場合があります。',
status_offset: 'オフセット',
status_server: 'NTPソース',
status_os: 'OS時計同期',
status_error: '最後のエラー',
os_yes: 'はい',
os_no: 'いいえ',
},
ko: {
synced_detail: '과금을 위해 시계가 동기화됨',
ntp_servers: 'NTP 서버',
ntp_servers_hint: '쉼표로 구분된 호스트명 또는 IP. Go 서버(betterdesk-server)에 적용됩니다.',
max_skew_ms: '최대 시계 오차 (ms)',
require_sync: '과금 세션에 동기화된 시계 필요',
trust_os: '직접 쿼리 실패 시 OS NTP 신뢰',
trust_os_hint: 'UDP NTP가 차단된 경우 systemd-timesyncd/chrony 상태 사용.',
save: 'NTP 설정 저장',
saved: '시계 설정이 저장되었습니다. Go 서버 재시작이 시작되었습니다.',
save_restart: 'NTP를 저장하고 Go 서버를 재시작하시겠습니까? 활성 세션이 잠시 끊길 수 있습니다.',
status_offset: '오프셋',
status_server: 'NTP 소스',
status_os: 'OS 시계 동기화',
status_error: '마지막 오류',
os_yes: '예',
os_no: '아니오',
},
nb: {
synced_detail: 'Klokke synkronisert for fakturering',
ntp_servers: 'NTP-servere',
ntp_servers_hint: 'Kommaseparerte vertsnavn eller IP. Gjelder Go-serveren (betterdesk-server).',
max_skew_ms: 'Maks klokkeavvik (ms)',
require_sync: 'Krev synkronisert klokke for fakturerbare økter',
trust_os: 'Stol på OS NTP når direkte forespørsler feiler',
trust_os_hint: 'Bruk systemd-timesyncd/chrony-status når UDP NTP er blokkert.',
save: 'Lagre NTP-innstillinger',
saved: 'Klokkeinnstillinger lagret. Omstart av Go-server startet.',
save_restart: 'Lagre NTP og start Go-server på nytt? Aktive økter kan kort kobles fra.',
status_offset: 'Avvik',
status_server: 'NTP-kilde',
status_os: 'OS-klokke synkronisert',
status_error: 'Siste feil',
os_yes: 'Ja',
os_no: 'Nei',
},
nl: {
synced_detail: 'Klok gesynchroniseerd voor facturering',
ntp_servers: 'NTP-servers',
ntp_servers_hint: 'Kommagescheiden hostnamen of IP\'s. Geldt voor de Go-server (betterdesk-server).',
max_skew_ms: 'Maximale klokafwijking (ms)',
require_sync: 'Gesynchroniseerde klok vereisen voor factureerbare sessies',
trust_os: 'Vertrouw OS NTP wanneer directe queries falen',
trust_os_hint: 'Gebruik systemd-timesyncd/chrony-status wanneer UDP NTP geblokkeerd is.',
save: 'NTP-instellingen opslaan',
saved: 'Klokinstellingen opgeslagen. Herstart Go-server gestart.',
save_restart: 'NTP opslaan en Go-server herstarten? Actieve sessies kunnen kort verbreken.',
status_offset: 'Offset',
status_server: 'NTP-bron',
status_os: 'OS-klok gesynchroniseerd',
status_error: 'Laatste fout',
os_yes: 'Ja',
os_no: 'Nee',
},
pl: {
synced_detail: 'Zegar zsynchronizowany do rozliczeń',
ntp_servers: 'Serwery NTP',
ntp_servers_hint: 'Nazwy hostów lub IP oddzielone przecinkami. Dotyczy serwera Go (betterdesk-server).',
max_skew_ms: 'Maksymalne odchylenie zegara (ms)',
require_sync: 'Wymagaj zsynchronizowanego zegara dla sesji płatnych',
trust_os: 'Ufaj NTP systemu, gdy bezpośrednie zapytania zawiodą',
trust_os_hint: 'Użyj statusu systemd-timesyncd/chrony, gdy UDP NTP jest blokowane (DMZ/firewall).',
save: 'Zapisz ustawienia NTP',
saved: 'Ustawienia zegara zapisane. Uruchomiono restart serwera Go.',
save_restart: 'Zapisać NTP i zrestartować serwer Go? Aktywne sesje mogą się chwilowo rozłączyć.',
status_offset: 'Odchylenie',
status_server: 'Źródło NTP',
status_os: 'Zegar OS zsynchronizowany',
status_error: 'Ostatni błąd',
os_yes: 'Tak',
os_no: 'Nie',
},
pt: {
synced_detail: 'Relógio sincronizado para faturação',
ntp_servers: 'Servidores NTP',
ntp_servers_hint: 'Nomes de host ou IP separados por vírgula. Aplica-se ao servidor Go (betterdesk-server).',
max_skew_ms: 'Desvio máximo do relógio (ms)',
require_sync: 'Exigir relógio sincronizado para sessões faturáveis',
trust_os: 'Confiar no NTP do SO quando consultas diretas falharem',
trust_os_hint: 'Usar estado systemd-timesyncd/chrony quando UDP NTP estiver bloqueado.',
save: 'Guardar definições NTP',
saved: 'Definições de relógio guardadas. Reinício do servidor Go iniciado.',
save_restart: 'Guardar NTP e reiniciar o servidor Go? Sessões ativas podem desligar-se brevemente.',
status_offset: 'Desvio',
status_server: 'Fonte NTP',
status_os: 'Relógio do SO sincronizado',
status_error: 'Último erro',
os_yes: 'Sim',
os_no: 'Não',
},
ro: {
synced_detail: 'Ceas sincronizat pentru facturare',
ntp_servers: 'Servere NTP',
ntp_servers_hint: 'Nume gazdă sau IP separate prin virgulă. Se aplică serverului Go (betterdesk-server).',
max_skew_ms: 'Abatere maximă ceas (ms)',
require_sync: 'Cere ceas sincronizat pentru sesiuni facturabile',
trust_os: 'Ai încredere în NTP OS când interogările directe eșuează',
trust_os_hint: 'Folosește starea systemd-timesyncd/chrony când UDP NTP este blocat.',
save: 'Salvează setările NTP',
saved: 'Setările ceasului salvate. Repornire server Go inițiată.',
save_restart: 'Salvezi NTP și repornești serverul Go? Sesiunile active se pot deconecta scurt.',
status_offset: 'Abatere',
status_server: 'Sursă NTP',
status_os: 'Ceas OS sincronizat',
status_error: 'Ultima eroare',
os_yes: 'Da',
os_no: 'Nu',
},
sv: {
synced_detail: 'Klocka synkroniserad för fakturering',
ntp_servers: 'NTP-servrar',
ntp_servers_hint: 'Kommaseparerade värdnamn eller IP. Gäller Go-servern (betterdesk-server).',
max_skew_ms: 'Max klockavvikelse (ms)',
require_sync: 'Kräv synkad klocka för fakturerbara sessioner',
trust_os: 'Lita på OS NTP när direkta frågor misslyckas',
trust_os_hint: 'Använd systemd-timesyncd/chrony-status när UDP NTP blockeras.',
save: 'Spara NTP-inställningar',
saved: 'Klockinställningar sparade. Omstart av Go-server startad.',
save_restart: 'Spara NTP och starta om Go-servern? Aktiva sessioner kan kopplas från kort.',
status_offset: 'Avvikelse',
status_server: 'NTP-källa',
status_os: 'OS-klocka synkad',
status_error: 'Senaste fel',
os_yes: 'Ja',
os_no: 'Nej',
},
th: {
synced_detail: 'นาฬิกาซิงค์สำหรับการเรียกเก็บเงิน',
ntp_servers: 'เซิร์ฟเวอร์ NTP',
ntp_servers_hint: 'ชื่อโฮสต์หรือ IP คั่นด้วยจุลภาค ใช้กับเซิร์ฟเวอร์ Go (betterdesk-server)',
max_skew_ms: 'ความคลาดเคลื่อนสูงสุดของนาฬิกา (ms)',
require_sync: 'ต้องมีนาฬิกาซิงค์สำหรับเซสชันที่เรียกเก็บเงิน',
trust_os: 'เชื่อถือ NTP ของ OS เมื่อการสอบถามโดยตรงล้มเหลว',
trust_os_hint: 'ใช้สถานะ systemd-timesyncd/chrony เมื่อ UDP NTP ถูกบล็อก',
save: 'บันทึกการตั้งค่า NTP',
saved: 'บันทึกการตั้งค่านาฬิกาแล้ว เริ่มรีสตาร์ทเซิร์ฟเวอร์ Go',
save_restart: 'บันทึก NTP และรีสตาร์ทเซิร์ฟเวอร์ Go? เซสชันที่ใช้งานอาจหลุดชั่วคราว',
status_offset: 'ออฟเซ็ต',
status_server: 'แหล่ง NTP',
status_os: 'นาฬิกา OS ซิงค์',
status_error: 'ข้อผิดพลาดล่าสุด',
os_yes: 'ใช่',
os_no: 'ไม่',
},
tr: {
synced_detail: 'Faturalandırma için saat senkronize',
ntp_servers: 'NTP sunucuları',
ntp_servers_hint: 'Virgülle ayrılmış ana bilgisayar adları veya IP. Go sunucusuna (betterdesk-server) uygulanır.',
max_skew_ms: 'Maksimum saat sapması (ms)',
require_sync: 'Faturalandırılabilir oturumlar için senkron saat gerekli',
trust_os: 'Doğrudan sorgular başarısız olursa OS NTP\'ye güven',
trust_os_hint: 'UDP NTP engellendiğinde systemd-timesyncd/chrony durumunu kullanın.',
save: 'NTP ayarlarını kaydet',
saved: 'Saat ayarları kaydedildi. Go sunucusu yeniden başlatılıyor.',
save_restart: 'NTP kaydedilsin ve Go sunucusu yeniden başlatılsın mı? Aktif oturumlar kısa süre kesilebilir.',
status_offset: 'Sapma',
status_server: 'NTP kaynağı',
status_os: 'OS saati senkron',
status_error: 'Son hata',
os_yes: 'Evet',
os_no: 'Hayır',
},
uk: {
synced_detail: 'Годинник синхронізовано для білінгу',
ntp_servers: 'NTP-сервери',
ntp_servers_hint: 'Імена хостів або IP через кому. Застосовується до Go-сервера (betterdesk-server).',
max_skew_ms: 'Максимальне відхилення годинника (мс)',
require_sync: 'Вимагати синхронізований годинник для платних сесій',
trust_os: 'Довіряти OS NTP, якщо прямі запити не вдаються',
trust_os_hint: 'Використовуйте статус systemd-timesyncd/chrony, коли UDP NTP заблоковано.',
save: 'Зберегти налаштування NTP',
saved: 'Налаштування годинника збережено. Перезапуск Go-сервера розпочато.',
save_restart: 'Зберегти NTP і перезапустити Go-сервер? Активні сесії можуть коротко відключитися.',
status_offset: 'Відхилення',
status_server: 'Джерело NTP',
status_os: 'Годинник OS синхронізовано',
status_error: 'Остання помилка',
os_yes: 'Так',
os_no: 'Ні',
},
vi: {
synced_detail: 'Đồng hồ đã đồng bộ cho tính phí',
ntp_servers: 'Máy chủ NTP',
ntp_servers_hint: 'Tên máy chủ hoặc IP cách nhau bằng dấu phẩy. Áp dụng cho máy chủ Go (betterdesk-server).',
max_skew_ms: 'Độ lệch đồng hồ tối đa (ms)',
require_sync: 'Yêu cầu đồng hồ đồng bộ cho phiên tính phí',
trust_os: 'Tin cậy NTP OS khi truy vấn trực tiếp thất bại',
trust_os_hint: 'Dùng trạng thái systemd-timesyncd/chrony khi UDP NTP bị chặn.',
save: 'Lưu cài đặt NTP',
saved: 'Đã lưu cài đặt đồng hồ. Đang khởi động lại máy chủ Go.',
save_restart: 'Lưu NTP và khởi động lại máy chủ Go? Phiên đang hoạt động có thể ngắt tạm thời.',
status_offset: 'Độ lệch',
status_server: 'Nguồn NTP',
status_os: 'Đồng hồ OS đã đồng bộ',
status_error: 'Lỗi cuối',
os_yes: 'Có',
os_no: 'Không',
},
zh: {
synced_detail: '时钟已同步,可用于计费',
ntp_servers: 'NTP 服务器',
ntp_servers_hint: '逗号分隔的主机名或 IP。应用于 Go 服务器(betterdesk-server)。',
max_skew_ms: '最大时钟偏差 (ms)',
require_sync: '可计费会话要求时钟同步',
trust_os: '直接查询失败时信任 OS NTP',
trust_os_hint: 'UDP NTP 被阻止时使用 systemd-timesyncd/chrony 状态。',
save: '保存 NTP 设置',
saved: '时钟设置已保存。已启动 Go 服务器重启。',
save_restart: '保存 NTP 并重启 Go 服务器?活动会话可能短暂断开。',
status_offset: '偏移',
status_server: 'NTP 来源',
status_os: 'OS 时钟已同步',
status_error: '最后错误',
os_yes: '是',
os_no: '否',
},
'zh-TW': {
synced_detail: '時鐘已同步,可用於計費',
ntp_servers: 'NTP 伺服器',
ntp_servers_hint: '逗號分隔的主機名稱或 IP。套用至 Go 伺服器(betterdesk-server)。',
max_skew_ms: '最大時鐘偏差 (ms)',
require_sync: '可計費工作階段要求時鐘同步',
trust_os: '直接查詢失敗時信任 OS NTP',
trust_os_hint: 'UDP NTP 被阻擋時使用 systemd-timesyncd/chrony 狀態。',
save: '儲存 NTP 設定',
saved: '時鐘設定已儲存。已啟動 Go 伺服器重新啟動。',
save_restart: '儲存 NTP 並重新啟動 Go 伺服器?使用中工作階段可能短暫中斷。',
status_offset: '偏移',
status_server: 'NTP 來源',
status_os: 'OS 時鐘已同步',
status_error: '最後錯誤',
os_yes: '是',
os_no: '否',
},
};
let updated = 0;
for (const file of locales) {
const locale = file.replace(/\.json$/, '');
const patch = patches[locale];
if (!patch) continue;
const filePath = path.join(langDir, file);
const json = JSON.parse(fs.readFileSync(filePath, 'utf8'));
if (!json.commercialization?.clock) continue;
Object.assign(json.commercialization.clock, patch);
fs.writeFileSync(filePath, `${JSON.stringify(json, null, 2)}\n`, 'utf8');
updated += 1;
}
console.log(`Patched commercialization.clock in ${updated} locale files`);