mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-18 00:56:02 +00:00
feat: add --removeUnused flag to extract translations
This commit is contained in:
5
common/translations-cli/constants.js
Normal file
5
common/translations-cli/constants.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
const defaultLanguage = 'en-US';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
defaultLanguage,
|
||||||
|
};
|
||||||
@@ -27,13 +27,18 @@ async function extractTranslationsFromFile(file) {
|
|||||||
return translations;
|
return translations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @typedef {{ ignoreDuplicates?: boolean }} ExtractOptions */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string[]} directories
|
* @param {string[]} directories
|
||||||
* @param {string[]} extensions
|
* @param {string[]} extensions
|
||||||
|
* @param {ExtractOptions} options
|
||||||
*
|
*
|
||||||
* @returns {Promise<Record<string, string>>}
|
* @returns {Promise<Record<string, string>>}
|
||||||
*/
|
*/
|
||||||
async function extractAllTranslations(directories, extensions) {
|
async function extractAllTranslations(directories, extensions, options = {}) {
|
||||||
|
const { ignoreDuplicates } = options;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
/** @type {Record<string, string>} */
|
/** @type {Record<string, string>} */
|
||||||
const allTranslations = {};
|
const allTranslations = {};
|
||||||
@@ -53,7 +58,7 @@ async function extractAllTranslations(directories, extensions) {
|
|||||||
|
|
||||||
translationKeyToFiles[key].push(file);
|
translationKeyToFiles[key].push(file);
|
||||||
|
|
||||||
if (allTranslations[key] && allTranslations[key] !== fileTranslations[key]) {
|
if (!ignoreDuplicates && allTranslations[key] && allTranslations[key] !== fileTranslations[key]) {
|
||||||
console.error(
|
console.error(
|
||||||
`Different translations for the same key [${key}] found. ${file}: ${
|
`Different translations for the same key [${key}] found. ${file}: ${
|
||||||
fileTranslations[key]
|
fileTranslations[key]
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
//@ts-check
|
//@ts-check
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
const { defaultLanguage } = require('./constants');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} file
|
* @param {string} file
|
||||||
@@ -122,8 +123,6 @@ const getTranslationChanges = (existingTranslations, newTranslations) => {
|
|||||||
return { added, removed, updated };
|
return { added, removed, updated };
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultLanguage = 'en-US';
|
|
||||||
|
|
||||||
function getDefaultTranslations() {
|
function getDefaultTranslations() {
|
||||||
return getLanguageTranslations(defaultLanguage);
|
return getLanguageTranslations(defaultLanguage);
|
||||||
}
|
}
|
||||||
@@ -149,6 +148,17 @@ function setLanguageTranslations(language, translations) {
|
|||||||
fs.writeFileSync(file, JSON.stringify(translations, null, 2));
|
fs.writeFileSync(file, JSON.stringify(translations, null, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} language
|
||||||
|
* @param {Record<string, string>} newTranslations
|
||||||
|
*/
|
||||||
|
function updateLanguageTranslations(language, newTranslations) {
|
||||||
|
const translations = getLanguageTranslations(language);
|
||||||
|
const updatedTranslations = { ...translations, ...newTranslations };
|
||||||
|
|
||||||
|
setLanguageTranslations(language, updatedTranslations);
|
||||||
|
}
|
||||||
|
|
||||||
function getAllLanguages() {
|
function getAllLanguages() {
|
||||||
const dir = resolveFile('translations');
|
const dir = resolveFile('translations');
|
||||||
|
|
||||||
@@ -174,6 +184,7 @@ module.exports = {
|
|||||||
getDefaultTranslations,
|
getDefaultTranslations,
|
||||||
getLanguageTranslations,
|
getLanguageTranslations,
|
||||||
setLanguageTranslations,
|
setLanguageTranslations,
|
||||||
|
updateLanguageTranslations,
|
||||||
getAllLanguages,
|
getAllLanguages,
|
||||||
getAllNonDefaultLanguages,
|
getAllNonDefaultLanguages,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,20 +9,22 @@ const {
|
|||||||
getTranslationChanges,
|
getTranslationChanges,
|
||||||
setLanguageTranslations,
|
setLanguageTranslations,
|
||||||
getAllNonDefaultLanguages,
|
getAllNonDefaultLanguages,
|
||||||
|
updateLanguageTranslations,
|
||||||
|
getDefaultTranslations,
|
||||||
} = require('./helpers');
|
} = require('./helpers');
|
||||||
const { extractAllTranslations } = require('./extract');
|
const { extractAllTranslations } = require('./extract');
|
||||||
const { getMissingTranslations } = require('./addMissing');
|
const { getMissingTranslations } = require('./addMissing');
|
||||||
|
const { defaultLanguage } = require('./constants');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {{ extensions: string[], directories: string[], outputFile: string}} ExtractConfig
|
* @typedef {{ extensions: string[], directories: string[]}} ExtractConfig
|
||||||
* @typedef {ExtractConfig & { verbose?: boolean }} ExtractOptions
|
* @typedef {ExtractConfig & { verbose?: boolean, removeUnused?: boolean }} ExtractOptions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @type {ExtractConfig} */
|
/** @type {ExtractConfig} */
|
||||||
const defaultConfig = {
|
const defaultConfig = {
|
||||||
extensions: ['.js', '.ts', '.svelte'],
|
extensions: ['.js', '.ts', '.svelte'],
|
||||||
directories: ['app', 'packages/web'],
|
directories: ['app', 'packages/web'],
|
||||||
outputFile: './translations/en-US.json',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
program.name('dbgate-translations-cli').description('CLI tool for managing translation').version('1.0.0');
|
program.name('dbgate-translations-cli').description('CLI tool for managing translation').version('1.0.0');
|
||||||
@@ -32,33 +34,25 @@ program
|
|||||||
.description('Extract translation keys from source files')
|
.description('Extract translation keys from source files')
|
||||||
.option('-d, --directories <directories...>', 'directories to search', defaultConfig.directories)
|
.option('-d, --directories <directories...>', 'directories to search', defaultConfig.directories)
|
||||||
.option('-e, --extensions <extensions...>', 'file extensions to process', defaultConfig.extensions)
|
.option('-e, --extensions <extensions...>', 'file extensions to process', defaultConfig.extensions)
|
||||||
.option('-o, --outputFile <file>', 'output file path', defaultConfig.outputFile)
|
.option('-r, --removeUnused', 'Remove unused keys from the output file')
|
||||||
.option('-v, --verbose', 'verbose mode')
|
.option('-v, --verbose', 'verbose mode')
|
||||||
.action(async (/** @type {ExtractOptions} */ options) => {
|
.action(async (/** @type {ExtractOptions} */ options) => {
|
||||||
try {
|
try {
|
||||||
const { directories, extensions, outputFile, verbose } = options;
|
const { directories, extensions, verbose, removeUnused } = options;
|
||||||
|
|
||||||
const resolvedRirectories = resolveDirs(directories);
|
const resolvedRirectories = resolveDirs(directories);
|
||||||
const resolvedExtensions = resolveExtensions(extensions);
|
const resolvedExtensions = resolveExtensions(extensions);
|
||||||
|
|
||||||
const translations = await extractAllTranslations(resolvedRirectories, resolvedExtensions);
|
const extractedTranslations = await extractAllTranslations(resolvedRirectories, resolvedExtensions);
|
||||||
|
const defaultTranslations = getDefaultTranslations();
|
||||||
|
|
||||||
const resolvedOutputFile = resolveFile(outputFile);
|
const { added, removed, updated } = getTranslationChanges(defaultTranslations, extractedTranslations);
|
||||||
ensureFileDirExists(resolvedOutputFile);
|
|
||||||
|
|
||||||
/** @type {Record<string, string>} */
|
|
||||||
let existingTranslations = {};
|
|
||||||
if (fs.existsSync(resolvedOutputFile)) {
|
|
||||||
existingTranslations = JSON.parse(fs.readFileSync(resolvedOutputFile, 'utf-8'));
|
|
||||||
}
|
|
||||||
|
|
||||||
const { added, removed, updated } = getTranslationChanges(existingTranslations, translations);
|
|
||||||
|
|
||||||
console.log('\nTranslation changes:');
|
console.log('\nTranslation changes:');
|
||||||
console.log(`- Added: ${added.length} keys`);
|
console.log(`- Added: ${added.length} keys`);
|
||||||
console.log(`- Removed: ${removed.length} keys`);
|
console.log(`- ${removeUnused ? 'Removed' : 'Unused'}: ${removed.length} keys`);
|
||||||
console.log(`- Updated: ${updated.length} keys`);
|
console.log(`- Updated: ${updated.length} keys`);
|
||||||
console.log(`- Total: ${Object.keys(translations).length} keys`);
|
console.log(`- Total: ${Object.keys(extractedTranslations).length} keys`);
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
if (added.length > 0) {
|
if (added.length > 0) {
|
||||||
@@ -75,13 +69,26 @@ program
|
|||||||
console.log('\nUpdated keys:');
|
console.log('\nUpdated keys:');
|
||||||
updated.forEach(key => {
|
updated.forEach(key => {
|
||||||
console.log(` ~ ${key}`);
|
console.log(` ~ ${key}`);
|
||||||
console.log(` Old: ${existingTranslations[key]}`);
|
console.log(` Old: ${defaultLanguage[key]}`);
|
||||||
console.log(` New: ${translations[key]}`);
|
console.log(` New: ${extractedTranslations[key]}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.writeFileSync(resolvedOutputFile, JSON.stringify(translations, null, 2));
|
if (removeUnused) {
|
||||||
|
console.log('Unused keys were removed.\n');
|
||||||
|
setLanguageTranslations(defaultLanguage, extractedTranslations);
|
||||||
|
} else {
|
||||||
|
console.log('New translations were saved. Unused keys are kept.\n');
|
||||||
|
updateLanguageTranslations(defaultLanguage, extractedTranslations);
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
console.log('\nUnused keys:');
|
||||||
|
for (const key of removed) {
|
||||||
|
console.log(`${key}: "${defaultTranslations[key]}"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
console.error('Error during extraction:', error.message);
|
console.error('Error during extraction:', error.message);
|
||||||
|
|||||||
Reference in New Issue
Block a user