WIP: #7324 - validate_translations #1134
|
@ -4,71 +4,17 @@ import path from 'path';
|
||||||
import { glob } from 'glob';
|
import { glob } from 'glob';
|
||||||
import yaml from 'js-yaml';
|
import yaml from 'js-yaml';
|
||||||
|
|
||||||
// 📌 Cargar traducciones YAML
|
|
||||||
const localesPath = path.resolve(__dirname + '../../i18n/locale');
|
const localesPath = path.resolve(__dirname + '../../i18n/locale');
|
||||||
const locales = fs.readdirSync(localesPath).reduce((acc, file) => {
|
let locales = {};
|
||||||
const locale = path.basename(file, '.yml');
|
async function init() {
|
||||||
acc[locale] = yaml.load(fs.readFileSync(path.join(localesPath, file), 'utf8'));
|
const files = await glob(['src/i18n/locale/**.yml', 'src/pages/**/locale/*.yml']);
|
||||||
return acc;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
// 📌 Extraer todas las claves de traducción de los archivos .vue
|
locales = files.reduce((acc, file) => {
|
||||||
async function extractTranslationKeysFromUsage() {
|
const locale = path.basename(file, '.yml');
|
||||||
const vueFiles = await glob('src/**/*.vue');
|
acc[locale] = { ...acc[locale], ...yaml.load(fs.readFileSync(file, 'utf8')) };
|
||||||
const regex = /\$t\(['"`]([\w.]+)['"`]\)|t\(['"`]([\w.]+)['"`]\)/g;
|
return acc;
|
||||||
|
}, {});
|
||||||
const keys = new Set();
|
|
||||||
|
|
||||||
vueFiles.forEach((file) => {
|
|
||||||
const content = fs.readFileSync(file, 'utf8');
|
|
||||||
let match;
|
|
||||||
while ((match = regex.exec(content)) !== null) {
|
|
||||||
keys.add(match[1] || match[2]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return Array.from(keys);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 📌 Extraer claves de la etiqueta `<i18n>` en los componentes Vue
|
|
||||||
async function extractTranslationKeysFromI18nTag() {
|
|
||||||
const vueFiles = await glob('src/**/*.vue');
|
|
||||||
const keys = new Set();
|
|
||||||
|
|
||||||
for (const file of vueFiles) {
|
|
||||||
const content = fs.readFileSync(file, 'utf8');
|
|
||||||
const i18nMatch = content.match(/<i18n[^>]*>([\s\S]*?)<\/i18n>/);
|
|
||||||
|
|
||||||
if (i18nMatch) {
|
|
||||||
try {
|
|
||||||
const i18nContent = yaml.load(i18nMatch[1]);
|
|
||||||
extractKeysFromObject(i18nContent).forEach((key) => keys.add(key));
|
|
||||||
} catch (err) {
|
|
||||||
console.warn(`⚠️ Error parsing <i18n> block in ${file}:`, err.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Array.from(keys);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 📌 Extraer claves y valores de un objeto anidado
|
|
||||||
function extractKeysFromObject(obj, prefix = '') {
|
|
||||||
let keys = [];
|
|
||||||
|
|
||||||
for (const key in obj) {
|
|
||||||
if (typeof obj[key] === 'object' && obj[key] !== null) {
|
|
||||||
keys = keys.concat(extractKeysFromObject(obj[key], `${prefix}${key}.`));
|
|
||||||
} else {
|
|
||||||
// Aquí estamos recogiendo tanto la clave como su valor
|
|
||||||
keys.push({ [`${prefix}${key}`]: obj[key] });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 📌 Validar claves extraídas contra las traducciones disponibles
|
|
||||||
function validateKeys(keys, translations) {
|
function validateKeys(keys, translations) {
|
||||||
const missingKeys = [];
|
const missingKeys = [];
|
||||||
|
|
||||||
|
@ -89,11 +35,13 @@ function validateKeys(keys, translations) {
|
||||||
return missingKeys;
|
return missingKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 📌 Ejecutar las validaciones
|
|
||||||
describe('🔍 Translation Keys Validation', async () => {
|
describe('🔍 Translation Keys Validation', async () => {
|
||||||
|
await init();
|
||||||
|
|
||||||
const vueFiles = await glob([
|
const vueFiles = await glob([
|
||||||
'src/pages/*.vue',
|
'src/pages/*.vue',
|
||||||
'src/components/CreateNewCityForm.vue',
|
'src/pages/**/*.vue',
|
||||||
|
'src/components/**/*.vue',
|
||||||
]);
|
]);
|
||||||
const regex = /\$t\(['"`]([\w.]+)['"`]\)|t\(['"`]([\w.]+)['"`]\)/g;
|
const regex = /\$t\(['"`]([\w.]+)['"`]\)|t\(['"`]([\w.]+)['"`]\)/g;
|
||||||
|
|
||||||
|
@ -122,7 +70,6 @@ describe('🔍 Translation Keys Validation', async () => {
|
||||||
Object.entries(i18nContent).forEach(([local, value]) => {
|
Object.entries(i18nContent).forEach(([local, value]) => {
|
||||||
Object.entries(value).forEach(([k, v]) => (locales[local][k] = v));
|
Object.entries(value).forEach(([k, v]) => (locales[local][k] = v));
|
||||||
});
|
});
|
||||||
// extractKeysFromObject(i18nContent).forEach((key) => keys.add(key));
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn(`⚠️ Error parsing <i18n> block in ${file}:`, err.message);
|
console.warn(`⚠️ Error parsing <i18n> block in ${file}:`, err.message);
|
||||||
}
|
}
|
||||||
|
@ -130,33 +77,16 @@ describe('🔍 Translation Keys Validation', async () => {
|
||||||
Object.entries(locales).forEach(([locale, translations]) => {
|
Object.entries(locales).forEach(([locale, translations]) => {
|
||||||
it(`should have all translation keys in ${locale}.${file}`, () => {
|
it(`should have all translation keys in ${locale}.${file}`, () => {
|
||||||
const missingKeys = validateKeys(keys, translations);
|
const missingKeys = validateKeys(keys, translations);
|
||||||
|
// try {
|
||||||
// if (missingKeys.length > 0) {
|
console.info(
|
||||||
// console.error(`❌ Missing keys in ${file}:`, missingKeys);
|
`xMissing keys in ${file}:${missingKeys.join(', ')}`,
|
||||||
|
missingKeys
|
||||||
|
);
|
||||||
|
expect(missingKeys, `xxMissing keys in ${file}`).toHaveLength(0);
|
||||||
|
// } catch (error) {
|
||||||
|
// console.error(`xxxMissing keys in ${file}${missingKeys.join(', ')}`);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
expect(missingKeys, `Missing keys in ${file}`).toHaveLength(0);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
|
||||||
const [usageKeys, i18nTagKeys] = await Promise.all([
|
|
||||||
extractTranslationKeysFromUsage(),
|
|
||||||
// extractTranslationKeysFromI18nTag(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
const allKeys = [...new Set([...usageKeys, ...i18nTagKeys])];
|
|
||||||
|
|
||||||
Object.entries(locales).forEach(([locale, translations]) => {
|
|
||||||
it(`should have all translation keys in ${locale}`, () => {
|
|
||||||
const missingKeys = validateKeys(allKeys, translations);
|
|
||||||
|
|
||||||
if (missingKeys.length > 0) {
|
|
||||||
console.error(`❌ Missing keys in ${locale}:`, missingKeys);
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(missingKeys).toEqual([]);
|
|
||||||
});
|
|
||||||
});*/
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue