diff --git a/.gitignore b/.gitignore index c0b6b82..f838d9e 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,6 @@ website/www/ # Temporary scratch files scratch/ + +# Agent customizations +.agents/ diff --git a/eslint.config.mjs b/eslint.config.mjs index b69c69f..5b5c584 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,6 +1,6 @@ export default [ { - ignores: ["coverage/**", "dist/**", "node_modules/**", "scratch/**", "website/www/**", ".agents/**"] + ignores: ["coverage/**", "dist/**", "node_modules/**", "scratch/**", "website/www/**"] }, { languageOptions: { diff --git a/.agents/examples/translate-locales-tool.cjs b/scripts/translate-locales-tool.cjs similarity index 94% rename from .agents/examples/translate-locales-tool.cjs rename to scripts/translate-locales-tool.cjs index 8c32dce..8ac3c1d 100644 --- a/.agents/examples/translate-locales-tool.cjs +++ b/scripts/translate-locales-tool.cjs @@ -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')); diff --git a/scripts/validate-brand-names.cjs b/scripts/validate-brand-names.cjs new file mode 100644 index 0000000..5cea437 --- /dev/null +++ b/scripts/validate-brand-names.cjs @@ -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(`]*>`, '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); +}