UNPKG

lingotags

Version:

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![npm version](https://img.shields.io/npm/v/lingotags.svg)](https://www.npmjs.com/package/lingotags)

232 lines 9.18 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getGlobalKeyCounter = getGlobalKeyCounter; exports.setGlobalKeyCounter = setGlobalKeyCounter; exports.escapeJson = escapeJson; exports.logVerbose = logVerbose; exports.writeOutputFile = writeOutputFile; exports.generateUniqueKey = generateUniqueKey; exports.extractTagContent = extractTagContent; exports.extractTagName = extractTagName; exports.getRelativePath = getRelativePath; exports.shouldProcessElement = shouldProcessElement; exports.processFileContent = processFileContent; exports.writeManifest = writeManifest; exports.revertFromManifest = revertFromManifest; exports.findMaxExistingKey = findMaxExistingKey; exports.initializeKeyCounter = initializeKeyCounter; exports.importTranslations = importTranslations; exports.exportTranslations = exportTranslations; const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); let globalKeyCounter = 0; function getGlobalKeyCounter() { return globalKeyCounter; } function setGlobalKeyCounter(value) { globalKeyCounter = value; } function escapeJson(str) { return str .replace(/"/g, '\\"') .replace(/\n/g, "\\n") .replace(/\r/g, "\\r") .replace(/\t/g, "\\t"); } function logVerbose(verbose, message) { if (verbose) { console.log(message); } } function writeOutputFile(outputFile, output) { const relativeOutput = {}; for (const [filePath, matches] of Object.entries(output)) { const relativePath = getRelativePath(filePath); relativeOutput[relativePath] = matches; } fs_1.default.writeFileSync(outputFile, JSON.stringify(relativeOutput, null, 2), "utf-8"); } function generateUniqueKey() { return `unique_key_${++globalKeyCounter}`; } function extractTagContent(html) { // Remove all JSX expressions first (including nested ones) const withoutJSX = html.replace(/{[^{}]*}/g, ""); // Remove HTML/JSX tags while preserving text content const withoutTags = withoutJSX.replace(/<[^>]+>/g, ""); // Clean up residual characters and whitespace return withoutTags .replace(/["']/g, "") // Remove quotes .replace(/\s+/g, " ") // Collapse whitespace .replace(/^ | $/g, "") // Trim edges .trim(); } function extractTagName(html) { // Updated regex to handle JSX tags with namespace prefixes and custom elements const match = html.match(/<([a-zA-Z0-9-_:]+)(\s|>)/); return match ? match[1].toLowerCase() : ""; } function getRelativePath(absolutePath) { const appIndex = absolutePath.indexOf("app"); if (appIndex !== -1) { return absolutePath.slice(appIndex).replace(/\\/g, "/"); } return path_1.default.basename(absolutePath); } function shouldProcessElement(rawHtml) { const staticContent = extractTagContent(rawHtml); const hasStaticText = staticContent.length > 0; const hasJSX = /{.*?}/.test(rawHtml); return hasStaticText && (!hasJSX || (hasJSX && staticContent !== "")); } function processFileContent(fileContent, searchPatterns) { const originalContent = fileContent; let modifiedContent = fileContent; const matches = []; const keyNumberMap = new Map(); // First pass: Find existing keys (for backward compatibility) searchPatterns.forEach((pattern) => { const patternMatches = [...fileContent.matchAll(pattern)]; patternMatches.forEach((match) => { const keyMatch = match[0].match(/data-i18n-key="([^"]+)"/); if (keyMatch) { const fullKey = keyMatch[1]; const numberedMatch = fullKey.match(/unique_key_(\d+)/); if (numberedMatch) { const keyNum = parseInt(numberedMatch[1], 10); keyNumberMap.set(fullKey, keyNum); if (keyNum > globalKeyCounter) { globalKeyCounter = keyNum; } } const content = extractTagContent(match[0]); matches.push({ key: fullKey, tag: extractTagName(match[0]), content, }); } }); }); // Second pass: Process tags that don't already have translation keys searchPatterns.forEach((pattern) => { const patternMatches = [...fileContent.matchAll(pattern)]; patternMatches.forEach((match) => { const tagContent = match[0]; // Skip if this already has a data-i18n-key or t() function if (tagContent.includes("data-i18n-key=") || tagContent.includes("{t(")) return; if (!shouldProcessElement(tagContent)) return; const uniqueKey = generateUniqueKey(); let content = extractTagContent(tagContent) .replace(/\s{2,}/g, " ") .trim(); const tagName = extractTagName(tagContent); if (tagName === "button") { const buttonContent = extractTagContent(tagContent); const cleanContent = buttonContent .replace(/>/g, " ") .replace(/{.*?}/g, "") .trim(); content = cleanContent || extractTagContent(tagContent); } else { content = extractTagContent(tagContent); } // Extract the inner text part const innerTextMatch = tagContent.match(/<[^>]*>([\s\S]*?)<\/[^>]*>/); if (innerTextMatch && innerTextMatch[1]) { // Replace the inner text with t() function call const innerText = innerTextMatch[1].trim(); if (innerText) { const replacement = tagContent.replace(innerText, `{t('${uniqueKey}')}`); modifiedContent = modifiedContent.replace(tagContent, replacement); matches.push({ key: uniqueKey, tag: extractTagName(tagContent), content, }); } } }); }); return { modifiedContent, matches, originalContent }; } const DEFAULT_MANIFEST = "lingotags-manifest.json"; function writeManifest(manifestPath = DEFAULT_MANIFEST, initialKeyCounter, fileChanges) { const manifest = { initialKeyCounter, changes: fileChanges.map(({ filePath, original, modified }) => ({ filePath, originalContent: original, modifiedContent: modified, })), }; fs_1.default.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), "utf-8"); } function revertFromManifest(manifestPath = "lingotags-manifest.json") { const resolvedPath = path_1.default.resolve(process.cwd(), manifestPath); if (!fs_1.default.existsSync(resolvedPath)) { throw new Error(`Manifest file not found: ${resolvedPath}`); } const manifest = JSON.parse(fs_1.default.readFileSync(resolvedPath, "utf-8")); manifest.changes.forEach(({ filePath, originalContent }) => { if (fs_1.default.existsSync(filePath)) { fs_1.default.writeFileSync(filePath, originalContent, "utf-8"); } }); setGlobalKeyCounter(manifest.initialKeyCounter); fs_1.default.unlinkSync(resolvedPath); } function findMaxExistingKey(content) { const keyRegex = /unique_key_(\d+)/g; let maxKey = 0; let match; while ((match = keyRegex.exec(content)) !== null) { const keyNum = parseInt(match[1], 10); if (keyNum > maxKey) maxKey = keyNum; } return maxKey; } function initializeKeyCounter(files) { globalKeyCounter = 0; } function importTranslations(localeFile) { try { if (fs_1.default.existsSync(localeFile)) { const content = fs_1.default.readFileSync(localeFile, 'utf-8'); return JSON.parse(content); } } catch (error) { console.error(`Error importing translations: ${error.message}`); } return {}; } function exportTranslations(localeFile, translations, merge = true) { try { const localeDir = path_1.default.dirname(localeFile); if (!fs_1.default.existsSync(localeDir)) { fs_1.default.mkdirSync(localeDir, { recursive: true }); } let finalTranslations = translations; // If merge is true and the file exists, merge with existing translations if (merge && fs_1.default.existsSync(localeFile)) { const existingTranslations = importTranslations(localeFile); finalTranslations = { ...existingTranslations, ...translations, }; } fs_1.default.writeFileSync(localeFile, JSON.stringify(finalTranslations, null, 2), 'utf-8'); } catch (error) { console.error(`Error exporting translations: ${error.message}`); } } //# sourceMappingURL=utils.js.map