feat(i18n): add scripts for locale translation and patching
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 45s

- Implemented `fill-de-extended-gaps.js` to fill missing billing/orders keys in de-extended from de.
- Created `fill-i18n-deep.py` for deep translation of locale JSONs using deep-translator with fallback options.
- Added `fill-i18n-locales.js` to translate locale JSONs and write overrides for untranslated keys.
- Introduced `fix-en-leaks.py` to translate keys that still match the en-US merge, addressing English leaks.
- Developed `patch-de-ch-swiss.js` to replace 'ß' with 'ss' in de-CH.json without deleting existing entries.
- Created `patch-en-gb-au.js` to apply UK/AU spelling corrections in en-GB and en-AU locales.
- Added shell scripts `run-fix-en-leaks.sh` and `run-i18n-deep-fill.sh` for sequential execution of translation tasks.
- Implemented `update-i18n-todo-stats.js` to update statistics in the I18N_TODO.md file based on translation completeness.
This commit is contained in:
Torsten Schulz (local)
2026-05-15 15:52:54 +02:00
parent 320010b94e
commit eb54b4f7cf
54 changed files with 58003 additions and 30665 deletions

View File

@@ -2,7 +2,6 @@ import cron from 'node-cron';
import autoUpdateRatingsService from './autoUpdateRatingsService.js';
import autoFetchMatchResultsService from './autoFetchMatchResultsService.js';
import apiLogService from './apiLogService.js';
import memberService from './memberService.js';
import { devLog } from '../utils/logger.js';
class SchedulerService {
@@ -25,10 +24,10 @@ class SchedulerService {
}
}
async runMatchResultsFetchJob(isAutomatic = true, options = {}) {
async runMatchResultsFetchJob(isAutomatic = true) {
const startTime = Date.now();
try {
const result = await autoFetchMatchResultsService.executeAutomaticFetch(options);
const result = await autoFetchMatchResultsService.executeAutomaticFetch();
const executionTime = Date.now() - startTime;
await apiLogService.logSchedulerExecution('match_results', true, result || { success: true }, executionTime, null);
return { success: true, result, executionTime, isAutomatic };
@@ -39,20 +38,6 @@ class SchedulerService {
}
}
async runInactiveMemberCleanupJob(isAutomatic = true) {
const startTime = Date.now();
try {
const result = await memberService.cleanupInactiveMembersWithoutRecentTraining({ inactiveDays: 365 });
const executionTime = Date.now() - startTime;
await apiLogService.logSchedulerExecution('member_cleanup', true, result || { success: true }, executionTime, null);
return { success: true, result, executionTime, isAutomatic };
} catch (error) {
const executionTime = Date.now() - startTime;
await apiLogService.logSchedulerExecution('member_cleanup', false, { success: false }, executionTime, error?.message || String(error));
return { success: false, error: error?.message || String(error), executionTime, isAutomatic };
}
}
/**
* Start the scheduler
*/
@@ -80,16 +65,8 @@ class SchedulerService {
timezone: 'Europe/Berlin'
});
const inactiveMemberCleanupJob = cron.schedule('45 6 * * *', async () => {
devLog('[Scheduler] Running inactive member cleanup job...');
await this.runInactiveMemberCleanupJob(true);
}, {
timezone: 'Europe/Berlin'
});
this.jobs.set('ratingUpdates', ratingUpdateJob);
this.jobs.set('matchResults', matchResultsJob);
this.jobs.set('inactiveMemberCleanup', inactiveMemberCleanupJob);
this.isRunning = true;
const now = new Date();
@@ -138,6 +115,7 @@ class SchedulerService {
/**
* Manually trigger rating updates (for testing)
* HINWEIS: Deaktiviert - automatische MyTischtennis-Abrufe sind nicht mehr verfügbar
*/
async triggerRatingUpdates() {
devLog('[Scheduler] Manual rating updates trigger called');
@@ -146,10 +124,11 @@ class SchedulerService {
/**
* Manually trigger match results fetch (for testing)
* HINWEIS: Deaktiviert - automatische MyTischtennis-Abrufe sind nicht mehr verfügbar
*/
async triggerMatchResultsFetch(options = {}) {
async triggerMatchResultsFetch() {
devLog('[Scheduler] Manual match results fetch trigger called');
return await this.runMatchResultsFetchJob(false, options);
return await this.runMatchResultsFetchJob(false);
}
/**

File diff suppressed because it is too large Load Diff