feat(scripts): check translation coverage

This commit is contained in:
Elian Doran 2026-01-04 23:31:07 +02:00
parent cd10e66fbb
commit ed91a44928
No known key found for this signature in database
5 changed files with 59 additions and 1975 deletions

1
.gitignore vendored
View File

@ -51,3 +51,4 @@ upload
# docs
site/
apps/*/coverage
scripts/translation/.language*.json

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,21 @@
import { LOCALES } from "../../packages/commons/src/lib/i18n";
import { getLanguageStats } from "./utils";
async function main() {
const languageStats = await getLanguageStats("client");
const localeIdsWithCoverage = languageStats.results
.filter(language => language.translated_percent > 50)
.map(language => language.language_code);
for (const localeId of localeIdsWithCoverage) {
const locale = LOCALES.find(l => l.id === localeId);
if (!locale) {
console.error(`Locale not found for id: ${localeId}`);
process.exit(1);
}
}
console.log("Translation coverage check passed.");
}
main();

View File

@ -1,42 +1,15 @@
import { readFile, stat, writeFile, } from "fs/promises";
import { readFile, writeFile } from "fs/promises";
import { join } from "path";
import { getLanguageStats } from "./utils";
const scriptDir = __dirname;
const rootDir = join(scriptDir, "../..");
const docsDir = join(rootDir, "docs");
async function getLanguageStats() {
const cacheFile = join(scriptDir, ".language-stats.json");
// Try to read from the cache.
try {
const cacheStats = await stat(cacheFile);
const now = new Date();
const oneDay = 24 * 60 * 60 * 1000; // milliseconds
if (cacheStats.mtimeMs < now.getTime() + oneDay) {
console.log("Reading language stats from cache.");
return JSON.parse(await readFile(cacheFile, "utf-8"));
}
} catch (e) {
if (!(e && typeof e === "object" && "code" in e && e.code === "ENOENT")) {
throw e;
}
}
// Make the request
console.log("Reading language stats from Weblate API.");
const request = await fetch("https://hosted.weblate.org/api/components/trilium/readme/translations/");
const stats = JSON.parse(await request.text());
// Update the cache
await writeFile(cacheFile, JSON.stringify(stats, null, 4));
return stats;
}
async function rewriteLanguageBar(readme: string) {
// Filter languages by their availability.
const languageStats = await getLanguageStats();
const languageStats = await getLanguageStats("readme");
const languagesWithCoverage: any[] = languageStats.results.filter(language => language.translated_percent > 75);
const languageLinks = languagesWithCoverage
.map(language => `[${language.language.name}](./${language.filename})`)

View File

@ -0,0 +1,33 @@
import { readFile, stat,writeFile } from "fs/promises";
import { join } from "path";
const scriptDir = __dirname;
export async function getLanguageStats(project: "readme" | "client") {
const cacheFile = join(scriptDir, `.language-stats-${project}.json`);
// Try to read from the cache.
try {
const cacheStats = await stat(cacheFile);
const now = new Date();
const oneDay = 24 * 60 * 60 * 1000; // milliseconds
if (cacheStats.mtimeMs < now.getTime() + oneDay) {
console.log("Reading language stats from cache.");
return JSON.parse(await readFile(cacheFile, "utf-8"));
}
} catch (e) {
if (!(e && typeof e === "object" && "code" in e && e.code === "ENOENT")) {
throw e;
}
}
// Make the request
console.log("Reading language stats from Weblate API.");
const request = await fetch(`https://hosted.weblate.org/api/components/trilium/${project}/translations/`);
const stats = JSON.parse(await request.text());
// Update the cache
await writeFile(cacheFile, JSON.stringify(stats, null, 4));
return stats;
}