Skip to main content
Glama
getExtractPluginOptions.ts4.51 kB
import { existsSync } from 'node:fs'; import { readFile } from 'node:fs/promises'; import { join, relative } from 'node:path'; import { buildDictionary, writeContentDeclaration } from '@intlayer/chokidar'; import { getConfiguration } from '@intlayer/config'; import type { Dictionary } from '@intlayer/types'; import type { ExtractPluginOptions, ExtractResult, } from './babel-plugin-intlayer-extract'; /** * Translation node structure used in dictionaries */ type TranslationNode = { nodeType: 'translation'; translation: Record<string, string>; }; /** * Dictionary content structure - map of keys to translation nodes */ type DictionaryContentMap = Record<string, TranslationNode>; /** * Get the options for the Intlayer Babel extraction plugin * This function loads the Intlayer configuration and sets up the onExtract callback * to write dictionaries to the filesystem. */ export const getExtractPluginOptions = (): ExtractPluginOptions => { const config = getConfiguration(); const { baseDir } = config.content; const compilerDir = join(baseDir, config.compiler?.outputDir ?? 'compiler'); /** * Read existing dictionary file if it exists */ const readExistingDictionary = async ( dictionaryPath: string ): Promise<Dictionary | null> => { try { if (!existsSync(dictionaryPath)) { return null; } const content = await readFile(dictionaryPath, 'utf-8'); return JSON.parse(content) as Dictionary; } catch { return null; } }; /** * Merge extracted content with existing dictionary, preserving translations. * - Keys in extracted but not in existing: added with default locale only * - Keys in both: preserve existing translations, update default locale value * - Keys in existing but not in extracted: removed (no longer in source) */ const mergeWithExistingDictionary = ( extractedContent: Record<string, string>, existingDictionary: Dictionary | null, defaultLocale: string ): DictionaryContentMap => { const mergedContent: DictionaryContentMap = {}; const existingContent = existingDictionary?.content as | DictionaryContentMap | undefined; for (const [key, value] of Object.entries(extractedContent)) { const existingEntry = existingContent?.[key]; if ( existingEntry && existingEntry.nodeType === 'translation' && existingEntry.translation ) { // Key exists in both - preserve existing translations, update default locale mergedContent[key] = { nodeType: 'translation', translation: { ...existingEntry.translation, [defaultLocale]: value, }, }; } else { // New key - add with default locale only mergedContent[key] = { nodeType: 'translation', translation: { [defaultLocale]: value, }, }; } } return mergedContent; }; const handleExtractedContent = async (result: ExtractResult) => { const { dictionaryKey, content, locale } = result; try { const dictionaryPath = join(compilerDir, `${dictionaryKey}.content.json`); // Read existing dictionary to preserve translations const existingDictionary = await readExistingDictionary(dictionaryPath); // Merge extracted content with existing translations const mergedContent = mergeWithExistingDictionary( content, existingDictionary, locale ); const dictionary: Dictionary = { key: dictionaryKey, content: mergedContent, filePath: join( relative(baseDir, compilerDir), `${dictionaryKey}.content.json` ), }; const writeResult = await writeContentDeclaration(dictionary, config, { newDictionariesPath: relative(baseDir, compilerDir), }); // Build the dictionary immediately const dictionaryToBuild: Dictionary = { ...dictionary, filePath: relative(baseDir, writeResult.path), }; await buildDictionary([dictionaryToBuild], config); } catch (error) { console.error( `[intlayer] Failed to process extracted content for ${dictionaryKey}:`, error ); } }; return { defaultLocale: config.internationalization.defaultLocale, // filesList can be passed if needed, but usually handled by include/exclude in build tool onExtract: handleExtractedContent, }; };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/aymericzip/intlayer'

If you have feedback or need assistance with the MCP directory API, please join our Discord server