export function syncIntlFormatMessage({ translations, fileContent, }: { translations: Record; fileContent: string; }): { updated: boolean; fileContent: string } { let updated = false; const entries = Object.entries(translations); for (const [messageId, messageValue] of entries) { const escapedId = messageId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // Find intl.formatMessage({...}) blocks that contain the specific id const outerRegex = new RegExp( `intl\\.formatMessage\\(\\s*\\{([^}]*?\\bid\\s*:\\s*['"]${escapedId}['"][^}]*?)\\}\\s*\\)`, "gs" ); fileContent = fileContent.replace( outerRegex, (fullMatch, innerObject) => { // Find defaultMessage: '...' or "..." const dmRegex = /defaultMessage\s*:\s*(['"])((?:\\.|[\s\S])*?)\1/; if (!dmRegex.test(innerObject)) return fullMatch; const newInner = innerObject.replace( dmRegex, (_m: unknown, quote: string, _old: unknown) => { // Escape backslashes first, then the surrounding quote, and newlines const escaped = messageValue .replace(/\\/g, "\\\\") .replace(new RegExp(quote, "g"), `\\${quote}`) .replace(/\n/g, "\\n"); return `defaultMessage: ${quote}${escaped}${quote}`; } ); updated = true; return `intl.formatMessage({${newInner}})`; } ); } return { updated, fileContent }; }