/** * i18n-aggregator.ts * * Aggregates translation files that match a list of prefixes. * */ import { promises as fs } from "fs"; import * as path from "path"; import { factorioPath, scriptOutputPath } from "./file.helper.ts"; import { dumpFactorioLocale } from "./command.helper.ts"; type Translations = Record>; export const LOCALE_OF_INTEREST = ["fluid", "item", "recipe", "item-group", "quality", "virtual-signal"]; export const LOCALE_TO_EXPORT = ["en", "ja", "zh-CH", "de", "fr"]; /** * Aggregates i18n JSON files that match a list of prefixes and writes a single * JSON file containing all translations for the specified i18n code. * * @param prefixes Array of file prefixes to look for. Example: ['app', 'common'] * @param inputFolder The folder to search for the locale files. * @param outputFolder The folder where the aggregated JSON will be written. * @param i18nCode The i18n code that will be used as the output file name. * * The function searches `inputFolder` for files that start with one of the * provided prefixes and end with `-locale.json`. Each matching file is * parsed as JSON and stored in a `Record` where the key is the * prefix and the value is the parsed JSON object. The final aggregated * object is written to `outputFolder/i18n/.json`. */ export async function aggregateI18n( prefixes: string[], inputFolder: string, outputFolder: string, i18nCode: string ): Promise { // Resolve absolute paths const inputPath = path.resolve(inputFolder); const outputPath = path.resolve(outputFolder, "i18n"); // Ensure the output directory exists await fs.mkdir(outputPath, { recursive: true }); // Read all files in the input directory const allFiles = await fs.readdir(inputPath); // Map of prefix => filename const prefixToFile: Record = {}; // Find the first file that matches each prefix for (const prefix of prefixes) { const filename = prefix + "-locale.json"; const match = allFiles.find((f) => f == filename); if (match) { prefixToFile[prefix] = match; } } const result: Translations = {}; // Read and parse each matched file for (const [prefix, fileName] of Object.entries(prefixToFile)) { const filePath = path.join(inputPath, fileName); const data = await fs.readFile(filePath, "utf-8"); try { result[prefix] = JSON.parse(data); } catch { result[prefix] = {}; } } // Write the aggregated JSON to the output folder const outputFile = path.join(outputPath, `${i18nCode}.json`); await fs.writeFile(outputFile, JSON.stringify(result, null, 2), "utf-8"); } /** * Updates the first `locale=` line in a file to the supplied locale code. * * @param localCode New locale code (e.g. "en-US", "de-DE") * */ export async function setLocaleInIni(localCode: string): Promise { const resolvedPath = path.resolve(factorioPath, "config", "config.ini"); const content = await fs.readFile(resolvedPath, "utf8"); await fs.writeFile(resolvedPath, content.replace(/^locale=.*$/m, "locale=" + localCode), "utf8"); } export async function extractLocale(outputFolder: string) { for (let i18nCode of LOCALE_TO_EXPORT) { console.log("Export i18n for " + i18nCode); await setLocaleInIni(i18nCode); await dumpFactorioLocale(); await aggregateI18n(LOCALE_OF_INTEREST, scriptOutputPath, outputFolder, i18nCode); } }