import { useEffect, useState } from 'react'; import { useTempoUi } from '@/components/tempo-brand'; import { translateText } from '@/translation/service'; import { protectTranslationTokens, restoreTranslationTokens } from '@/translation/utils'; // Only the fixed public institutional texts using this component are sent to Tempo. const cache = new Map(); const pending = new Map>(); function translateInstitutionalText(text: string, language: string): Promise { const key = JSON.stringify([language, text]); const cached = cache.get(key); if (cached) return Promise.resolve(cached); const existing = pending.get(key); if (existing) return existing; const protectedText = protectTranslationTokens(text); const request = translateText({ text: protectedText.text, sourceLanguage: 'pt', targetLanguage: language, }).then(({ translatedText }) => { // Do not accept a response that lost an identifier, URL or protected term. for (const token of protectedText.replacements.keys()) { if (!translatedText.includes(token)) throw new Error('Translation lost a protected token'); } const result = restoreTranslationTokens(translatedText, protectedText.replacements); // Tempo's API returns the input on upstream failure: do not cache it as success. if (result !== text) cache.set(key, result); return result; }).finally(() => pending.delete(key)); pending.set(key, request); return request; } export function Trans({ children }: { children: string }) { const { language, t } = useTempoUi(); const localText = t(children); const [result, setResult] = useState<{ key: string; text: string } | null>(null); const key = JSON.stringify([language, children]); useEffect(() => { if (language === 'pt' || localText !== children || !children.trim()) return; let active = true; translateInstitutionalText(children, language).then((text) => { if (active) setResult({ key, text }); }).catch(() => { if (active) setResult(null); }); return () => { active = false; }; }, [children, key, language, localText]); return {result?.key === key ? result.text : localText}; }