UNPKG

@rustling-pines/typesafe-locale-generator

Version:

A TypeScript-based tool to generate locale JSON files for i18n frameworks with type safety. It ensures missing translations are caught during development, reducing errors and streamlining localization. Fully customizable input/output paths, compatible wit

148 lines (147 loc) โ€ข 7.22 kB
#!/usr/bin/env node "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.processTranslations = processTranslations; const ts_node_1 = require("ts-node"); const fs_extra_1 = __importDefault(require("fs-extra")); const path_1 = __importDefault(require("path")); function processTranslations(translationInputFile, localesOutputDirectory, tempDir) { return __awaiter(this, void 0, void 0, function* () { const tempFileName = path_1.default.basename(translationInputFile, '.ts') + '.js'; try { console.log(`๐Ÿ› ๏ธ Starting Translation Processing...`); console.log(`๐Ÿ“ฅ Input File: ${translationInputFile}`); console.log(`๐Ÿ“‚ Output Directory: ${localesOutputDirectory}`); console.log(`๐Ÿ”ง Temp Directory: ${tempDir}`); // Ensure the translation input file exists if (!fs_extra_1.default.existsSync(translationInputFile)) { throw new Error(`โŒ Translation file not found: ${translationInputFile}`); } // Ensure the output directory exists fs_extra_1.default.mkdirsSync(localesOutputDirectory); // Compile the TypeScript file console.log(`๐Ÿ› ๏ธ Compiling TypeScript file...`); require('child_process').execSync(`npx tsc ${translationInputFile} --outDir ${tempDir}`, { stdio: 'inherit', }); // Search recursively for the compiled file console.log(`๐Ÿ”„ Searching for the compiled temp file...`); const compiledFilePath = findCompiledFile(tempDir, tempFileName); if (!compiledFilePath) { console.error(`โŒ Compiled temp file not found.`); console.log('๐Ÿ” Debug: Temp directory contents:'); debugTempDirectory(tempDir); throw new Error(`โŒ Compiled file could not be located: ${tempFileName}`); } console.log(`๐Ÿ”ง Resolved Temp File Path: ${compiledFilePath}`); // Register ts-node for TypeScript imports (0, ts_node_1.register)({ project: path_1.default.resolve(process.cwd(), 'tsconfig.json'), }); // Dynamically import the compiled JavaScript file console.log(`๐Ÿ”„ Loading translation configuration from: ${compiledFilePath}`); let { locales, translations } = yield Promise.resolve(`${compiledFilePath}`).then(s => __importStar(require(s))); // Validate locales array if (!Array.isArray(locales) || locales.length === 0) { console.warn(`โš ๏ธ Warning: Locales array is empty or invalid. Defaulting to ['en-us'].`); locales = ['en-us']; } // Generate JSON files for each locale for (const locale of locales) { const localeFileContent = translations.map((translation) => ({ Key: translation.key, Value: translation[locale], })); const outputFilePath = path_1.default.resolve(localesOutputDirectory, `${locale}.json`); yield fs_extra_1.default.outputJson(outputFilePath, localeFileContent, { spaces: 2 }); console.log(`โœ… Locale file generated: ${outputFilePath}`); } console.log(`โœ… All locale files generated successfully!`); } catch (error) { console.error(`โŒ Error during processing:`, error instanceof Error ? error.message : error); console.log('๐Ÿ” Debug: Temp directory contents:'); debugTempDirectory(tempDir); throw error; } finally { console.log(`๐Ÿงน Cleaning up temporary files...`); if (fs_extra_1.default.existsSync(tempDir)) { fs_extra_1.default.removeSync(tempDir); console.log(`โœ… Temporary files cleaned.`); } else { console.log(`โš ๏ธ Temp directory already cleaned or missing.`); } } }); } // Helper function to find the compiled file recursively function findCompiledFile(dir, targetFileName) { const files = fs_extra_1.default.readdirSync(dir, { withFileTypes: true }); for (const file of files) { const filePath = path_1.default.resolve(dir, file.name); if (file.isFile() && file.name === targetFileName) { return filePath; } else if (file.isDirectory()) { const nestedResult = findCompiledFile(filePath, targetFileName); if (nestedResult) return nestedResult; } } return null; } // Helper function to log the temp directory contents function debugTempDirectory(dir) { const files = fs_extra_1.default.readdirSync(dir, { withFileTypes: true }); files.forEach(file => { const fullPath = path_1.default.resolve(dir, file.name); console.log(` - ${fullPath}`); }); }