diff --git a/lib/create-tree.js b/lib/create-tree.js index eec6f240a8..0a5e477112 100644 --- a/lib/create-tree.js +++ b/lib/create-tree.js @@ -4,10 +4,22 @@ import fs from 'fs/promises' import Page from './page.js' const __dirname = path.dirname(fileURLToPath(import.meta.url)) +// Module level cache +const _basePaths = new Map() +// Return a full directory based on __dirname from a specific language directory. +// This function is memoized with a simple global cache object. +function getBasePath(directory) { + if (!_basePaths.has(directory)) { + _basePaths.set(directory, path.posix.join(__dirname, '..', directory, 'content')) + console.log(_basePaths.get(directory)) + } + return _basePaths.get(directory) +} + export default async function createTree(originalPath, langObj) { // This basePath definition is needed both here and in lib/page-data.js because this // function runs recursively, and the value for originalPath changes on recursive runs. - const basePath = path.posix.join(__dirname, '..', langObj.dir, 'content') + const basePath = getBasePath(langObj.dir) // On recursive runs, this is processing page.children items in `/` format. // If the path exists as is, assume this is a directory with a child index.md. diff --git a/script/i18n/prune-stale-files.js b/script/i18n/prune-stale-files.js new file mode 100755 index 0000000000..69ebd18f54 --- /dev/null +++ b/script/i18n/prune-stale-files.js @@ -0,0 +1,55 @@ +#!/usr/bin/env node +import fs from 'fs' +import path from 'path' +import walk from 'walk-sync' +import program from 'commander' +import languages from '../../lib/languages.js' + +program + .description( + `Removes any file in the translations directory that doesn't have a 1-1 mapping with an English file in the content directory` + ) + .option('-d, --dry-run', `List the files that will be deleted, but don't remove them).`) + .parse(process.argv) + +const languageDir = Object.keys(languages) + .filter((language) => !languages[language].wip && language !== 'en') + .map((language) => languages[language].dir) + +main() + +async function main() { + const listOfContentFiles = walk(path.join(process.cwd(), 'content'), { + includeBasePath: false, + directories: false, + }) + + const translatedFilePaths = [] + languageDir.forEach((directory) => { + const listOfFiles = walk(path.join(directory, 'content'), { + includeBasePath: true, + directories: false, + }).map((path) => path.replace(process.cwd(), '')) + translatedFilePaths.push(...listOfFiles) + }) + + let outOfSyncFilesCount = 0 + translatedFilePaths.forEach((translatedFilePath) => { + const translationRelativePath = translatedFilePath.split('/content/')[1] + + // If there is a 1:1 mapping of translated file to english file + // we're in sync, don't log + if (listOfContentFiles.includes(translationRelativePath)) { + return + } + + outOfSyncFilesCount++ + if (!program.opts().dryRun) { + fs.unlinkSync(translatedFilePath) + } else { + console.log(translatedFilePath) + } + }) + + console.log(`Out of sync file size: ${outOfSyncFilesCount}`) +}