build(website): move locales translation utility to scripts/ and add validate-brand-names script

This commit is contained in:
KoalaDev
2026-07-08 17:28:11 +02:00
parent b4bf297a5b
commit 12bca85356
4 changed files with 57 additions and 4 deletions
+3
View File
@@ -46,3 +46,6 @@ website/www/
# Temporary scratch files
scratch/
# Agent customizations
.agents/
+1 -1
View File
@@ -1,6 +1,6 @@
export default [
{
ignores: ["coverage/**", "dist/**", "node_modules/**", "scratch/**", "website/www/**", ".agents/**"]
ignores: ["coverage/**", "dist/**", "node_modules/**", "scratch/**", "website/www/**"]
},
{
languageOptions: {
@@ -1,18 +1,18 @@
/**
* KoalaSync Locale Translation Script
*
* This script is stored in `.agents/examples/translate-locales-tool.cjs`
* This script is stored in `scripts/translate-locales-tool.cjs`
* so future LLM agents can easily reuse and adapt it to translate new keys.
*
* Usage:
* node .agents/examples/translate-locales-tool.cjs
* node scripts/translate-locales-tool.cjs
*/
const fs = require('fs');
const path = require('path');
const http = require('https');
const localesDir = path.join(__dirname, '../../website/locales');
const localesDir = path.join(__dirname, '../website/locales');
const enFile = path.join(localesDir, 'en.json');
const enLocale = JSON.parse(fs.readFileSync(enFile, 'utf8'));
+50
View File
@@ -0,0 +1,50 @@
const fs = require('fs');
const path = require('path');
const localesDir = path.join(__dirname, '../website/locales');
const files = fs.readdirSync(localesDir).filter(f => f.endsWith('.json') && f !== 'en.json');
const brandTranslations = [
'dos siete', 'dos-siete', 'deux sept', 'deux-sept', 'zwei sieben', 'zwei-sieben',
'due sette', 'due-sette', 'dwa siedem', 'dwa-siedem', 'twee zeven', 'twee-zeven',
'iki yedi', 'iki-yedi', 'два семь', 'два-семь', '二七', '二 七', '이칠', '이 칠',
'koala sync', 'koala-sync', 'watch 2 gether', 'watch-2-gether', 'watch 2gether',
'watch-2gether', 'jelly fin', 'jelly-fin'
];
let failed = false;
for (const file of files) {
const filePath = path.join(localesDir, file);
const content = JSON.parse(fs.readFileSync(filePath, 'utf8'));
for (const [key, value] of Object.entries(content)) {
if (typeof value !== 'string') continue;
// Check brand translations (case-insensitive)
const lowerValue = value.toLowerCase();
for (const pattern of brandTranslations) {
if (lowerValue.includes(pattern)) {
console.error(`Error in ${file} [key: ${key}]: Found translated brand pattern "${pattern}" in value: "${value}"`);
failed = true;
}
}
// Check tag validation
const tags = ['strong', 'em', 'span', 'b', 'i', 'p', 'a'];
for (const tag of tags) {
const openCount = (value.match(new RegExp(`<${tag}\\b[^>]*>`, 'g')) || []).length;
const closeCount = (value.match(new RegExp(`</${tag}\\b[^>]*>`, 'g')) || []).length;
if (openCount !== closeCount) {
console.error(`Error in ${file} [key: ${key}]: Unbalanced tag <${tag}> (open: ${openCount}, close: ${closeCount}) in value: "${value}"`);
failed = true;
}
}
}
}
if (!failed) {
console.log("All brand names and HTML tags are perfectly valid and intact across all languages!");
} else {
process.exit(1);
}