diff --git a/src/lib/ai/safety/__tests__/outbound-screen-named-meds.test.ts b/src/lib/ai/safety/__tests__/outbound-screen-named-meds.test.ts index a9c3d3b14..609fa81fb 100644 --- a/src/lib/ai/safety/__tests__/outbound-screen-named-meds.test.ts +++ b/src/lib/ai/safety/__tests__/outbound-screen-named-meds.test.ts @@ -34,6 +34,7 @@ const NAMES: Record = { it: ["Ramipril", "Amlodipina", "Eliquis"], pl: ["Ramipril", "Amlodypina", "Eliquis"], nl: ["Ramipril 5 mg", "Amlodipine", "Eliquis"], + "pt-BR": ["Ramipril 5 mg", "Anlodipino", "Eliquis"], ko: ["라미프릴", "암로디핀", "엘리퀴스"], }; @@ -105,6 +106,17 @@ const VIOLATIONS: Record = { "Neem een halve tablet amlodipine.", "Neem vanavond een tablet meer.", ], + "pt-BR": [ + "Depois tome um ramipril a mais.", + "Pule o anlodipino amanhã.", + "Tome mais um comprimido de ramipril.", + "Pare o anticoagulante antes da corrida.", + "Tome dois comprimidos de ramipril hoje à noite.", + "Tome outro anlodipino se a pressão estiver alta.", + "Suspenda o Eliquis no fim de semana.", + "Tire o Eliquis amanhã.", + "Tome meio comprimido de anlodipino.", + ], ko: [ "라미프릴을 한 알 더 드세요.", "암로디핀은 내일 건너뛰세요.", @@ -194,6 +206,17 @@ const CLEAN: Record = { "Laat de suiker in je koffie weg.", "Neem nog een meting vanavond.", ], + "pt-BR": [ + "Seu registro de ramipril mostra todas as doses tomadas.", + "Não pule o ramipril.", + "Nunca tome um anlodipino a mais para compensar um esquecido.", + "Você tomou um ramipril a mais na terça-feira, segundo o seu registro.", + "Faça uma caminhada a mais depois do jantar.", + "Tome o seu ramipril conforme prescrito.", + "Ramipril e anlodipino baixam a pressão.", + "Tire o açúcar do café.", + "Faça mais uma medição hoje à noite.", + ], ko: [ "라미프릴 기록을 보면 모두 복용하셨어요.", "암로디핀을 건너뛰지 마세요.", diff --git a/src/lib/ai/safety/__tests__/outbound-screen.test.ts b/src/lib/ai/safety/__tests__/outbound-screen.test.ts index b361b2f22..6c80e8528 100644 --- a/src/lib/ai/safety/__tests__/outbound-screen.test.ts +++ b/src/lib/ai/safety/__tests__/outbound-screen.test.ts @@ -24,6 +24,7 @@ const DOSE_VIOLATIONS: Record = { it: "Aumenti la sua dose a 2,4 mg la prossima settimana.", pl: "Proszę zwiększyć dawkę do 2,4 mg w przyszłym tygodniu.", nl: "Verhoog je dosis volgende week naar 2,4 mg.", + "pt-BR": "Aumente sua dose para 2,4 mg na próxima semana.", ko: "다음 주에 2.4mg으로 늘려 보세요.", }; @@ -40,6 +41,7 @@ const DOSE_CLEAN: Record = { it: "È alla settimana 3 con 7,5 mg, e il suo peso sta calando.", pl: "Jest Pan w 3. tygodniu na 7,5 mg, a waga spada.", nl: "Je zit in week 3 op 7,5 mg, en je gewicht gaat omlaag.", + "pt-BR": "Você está na semana 3 com 7,5 mg, e seu peso está diminuindo.", ko: "3주째 7.5mg을 복용 중이고, 체중은 내려가고 있어요.", }; @@ -99,6 +101,7 @@ const RISK_VIOLATIONS: Record = { it: "Il suo rischio è del 12%.", pl: "Pana ryzyko wynosi 12%.", nl: "Je risico ligt op ongeveer 12%.", + "pt-BR": "Seu risco é de cerca de 12%.", ko: "10년 심혈관 위험도는 약 12%예요.", }; @@ -111,6 +114,7 @@ const RISK_CLEAN: Record = { it: "La sua aderenza è stata del 92% negli ultimi 30 giorni.", pl: "Przestrzeganie zaleceń wyniosło 92% w ostatnich 30 dniach.", nl: "Je therapietrouw was 92% in de afgelopen 30 dagen.", + "pt-BR": "Sua adesão foi de 92% nos últimos 30 dias.", ko: "지난 30일 복약 순응도는 92%였어요.", }; @@ -355,6 +359,7 @@ const CAUSAL_VIOLATIONS: Record = { it: "Il suo peso è calato perché ha dormito di più.", pl: "Waga spadła, ponieważ spał Pan więcej.", nl: "Je gewicht daalde omdat je meer sliep.", + "pt-BR": "Seu peso caiu porque você dormiu mais.", ko: "수면 때문에 체중이 줄었어요.", }; @@ -367,6 +372,7 @@ const CAUSAL_CLEAN: Record = { it: "Il suo peso si è mosso insieme al suo sonno questa settimana.", pl: "Waga zmieniała się razem ze snem w tym tygodniu.", nl: "Je gewicht bewoog deze week mee met je slaap.", + "pt-BR": "Seu peso acompanhou o seu sono nesta semana.", ko: "이번 주 체중은 수면과 함께 움직였어요.", }; @@ -530,6 +536,18 @@ const DOSE_CLASS_VIOLATIONS: Record = { "Je zou de metformine een week kunnen stoppen.", "Bouw je dosis af naar 5 mg.", ], + "pt-BR": [ + "Aumente sua metformina para 2000 mg por dia.", + "Reduza sua insulina em 4 unidades.", + "Tome 2 comprimidos à noite.", + "Pule a dose da noite.", + "Pare de tomar a metformina.", + "Você poderia suspender a metformina por uma semana.", + "Diminua a dose para 5 mg.", + "Dobre a dose de insulina.", + "Passe a tomar 10 mg pela manhã.", + "Aplique 12 UI de insulina antes do jantar.", + ], ko: [ "메트포르민을 2000mg으로 증량하세요.", "하루 2정 드세요.", @@ -599,6 +617,20 @@ const DOSE_CLASS_CLEAN: Record = { "Probeer je glucose na de maaltijd onder 140 mg/dL te houden.", "Vraag je arts voordat je stopt met metformine.", ], + "pt-BR": [ + "Você toma 1000 mg duas vezes ao dia.", + "Seu registro mostra 2000 mg.", + "Não pule a dose da noite.", + "Não deixe de tomar a metformina.", + "Pergunte ao seu médico se deve aumentar a dose.", + "Sua dose foi aumentada para 2000 mg em maio.", + "A dose passou para 2000 mg em maio, segundo o registro.", + "Dobre seus passos por duas semanas.", + "Reduza o sódio para 1500 mg por dia.", + "Aumente a ingestão de água para 2000 ml.", + "Tente manter a glicose abaixo de 140 mg/dL depois das refeições.", + "Converse com seu médico antes de parar de tomar a metformina.", + ], ko: [ "하루 두 번 1000mg을 복용하고 계세요.", "저녁 용량을 건너뛰지 마세요.", diff --git a/src/lib/ai/safety/outbound-screen.ts b/src/lib/ai/safety/outbound-screen.ts index 0eade54fc..daadc593c 100644 --- a/src/lib/ai/safety/outbound-screen.ts +++ b/src/lib/ai/safety/outbound-screen.ts @@ -64,19 +64,20 @@ export interface OutboundDecision { * the screen recognised and passed every pattern. */ const COUNT_UNIT = - "(?:tablets?|pills?|capsules?|drops?|puffs?|sprays?|tabletten?|kapseln?|tropfen|hübe|hub|sprühstöße|comprimés?|gélules?|gouttes?|bouffées?|comprimidos?|pastillas?|c[áa]psulas?|gotas?|compress[ae]|pastigli[ae]|gocce|goccia|tabletk[aęiy]|tabletek|kapsułk[aęiy]|kapsułek|krople|kropli|druppels?|pillen|pufjes?)"; + "(?:tablets?|pills?|capsules?|drops?|puffs?|sprays?|tabletten?|kapseln?|tropfen|hübe|hub|sprühstöße|comprimés?|gélules?|gouttes?|bouffées?|comprimidos?|pastillas?|c[áa]psulas?|gotas?|compress[ae]|pastigli[ae]|gocce|goccia|tabletk[aęiy]|tabletek|kapsułk[aęiy]|kapsułek|krople|kropli|druppels?|pillen|pufjes?|pastilhas?|dr[áa]geas?|jatos?|borrifadas?)"; /** * Dose units for a target dose a model must never name. Mass and insulin * units plus the count forms; `ml` is left out on purpose because * "increase your water intake to 2000 ml" is ordinary hydration advice. */ -const DRUG_UNIT = `(?:mg|mcg|µg|iu|i\\.u\\.|units?|unidades?|unità|unités?|jednostek|jednostki|eenheden|eenheid|ie|i\\.e\\.|einheiten|${COUNT_UNIT})`; +const DRUG_UNIT = `(?:mg|mcg|µg|iu|ui|i\\.u\\.|units?|unidades?|unità|unités?|jednostek|jednostki|eenheden|eenheid|ie|i\\.e\\.|einheiten|${COUNT_UNIT})`; /** * Dose units, shared across every locale. The GLP-1 + general oral-dose * vocabulary; `ie` / `i.e.` / `einheiten` / `unità` / `jednostk` cover the - * insulin-unit spellings the locales use (`eenheden` is the Dutch one). + * insulin-unit spellings the locales use (`eenheden` is the Dutch one, `ui` + * the Portuguese abbreviation of "unidades internacionais"). */ const DOSE_UNIT = `(?:ml|${DRUG_UNIT})`; @@ -120,6 +121,8 @@ const PL_STOP = const NL_STOP = "niet|nooit|geen|en|of|maar|als|wanneer|natrium|zout|cafeïne|suiker\\S*|water|vocht|eiwit\\S*|vezels?|koffie|alcohol|stappen|calorieën"; +const PT_STOP = + "não|nao|nunca|jamais|e|ou|mas|se|sódio|sal|cafeína|açúcar\\S*|água|proteínas?|fibras?|café|álcool|passos|calorias"; const EN_SLOT = objectSlot(EN_STOP); const DE_SLOT = objectSlot(DE_STOP); @@ -128,6 +131,7 @@ const ES_SLOT = objectSlot(ES_STOP); const IT_SLOT = objectSlot(IT_STOP); const PL_SLOT = objectSlot(PL_STOP); const NL_SLOT = objectSlot(NL_STOP); +const PT_SLOT = objectSlot(PT_STOP); /** * A tighter slot for the shapes that carry no number: an extra / one more / @@ -154,6 +158,10 @@ const NL_SHORT = objectSlot( `${NL_STOP}|om|voor|met|bij|in|op|van|naar|tot|na|zonder|tijdens|over|dan|te`, 2, ); +const PT_SHORT = objectSlot( + `${PT_STOP}|para|pra|com|antes|depois|sem|a|ao|à|de|do|da|em|no|na|por|durante|sobre`, + 2, +); /** * A count written as a word: "take two tablets", "nimm zwei Tabletten", @@ -163,7 +171,7 @@ const NL_SHORT = objectSlot( * count, and the "eine Tablette mehr" shape is its own pattern below. */ const SPELLED_COUNT = - "(?:one|two|three|four|five|six|half\\s+an?|zwei|drei|vier|fünf|sechs|eine?n?\\s+halbe|halbe|deux|trois|quatre|cinq|demi|dos|tres|cuatro|cinco|media|due|tre|quattro|cinque|mezza|dwie|dwa|trzy|cztery|pięć|jedn[ąa]|pół|één|twee|drie|vier|vijf|zes|halve)"; + "(?:one|two|three|four|five|six|half\\s+an?|zwei|drei|vier|fünf|sechs|eine?n?\\s+halbe|halbe|deux|trois|quatre|cinq|demi|dos|tres|cuatro|cinco|media|due|tre|quattro|cinque|mezza|dwie|dwa|trzy|cztery|pięć|jedn[ąa]|pół|één|twee|drie|vier|vijf|zes|halve|dois|duas|três|quatro|meia|meio)"; /** A target dose: a number, a drug unit, and an honest unit end. */ const TARGET = `(?:[\\d.,]+\\s*${DRUG_UNIT}${UNIT_END}|(? = { pl: "(?:lek\\S*\\s+przeciwzakrzepow\\S*|antykoagulant\\S*|statyn\\S*|beta-?bloker\\S*|diuretyk\\S*|lek\\S*\\s+moczopędn\\S*|antydepresant\\S*)", nl: "\\S*(?:bloedverdunner\\w*|antistolling\\w*|anticoagul\\w*|plaatjesremmer\\w*|statine\\w*|b[eè]tablokker\\w*|plastablet\\w*|diuretic\\w*|diuretica|antidepressiv\\w*|antidepressiva|slaappil\\w*|slaapmiddel\\w*|bloeddrukverlager\\w*|ace-remmer\\w*)", ko: "(?:혈액\\s*희석제|항응고제|항혈소판제|스타틴|베타\\s*차단제|이뇨제|항우울제)", + "pt-BR": + "(?:anticoagulantes?|antiagregantes?|estatinas?|beta-?bloqueadores?|diur[ée]ticos?|antidepressivos?|anti-?hipertensivos?|sonífer[oa]s?|rem[ée]dios?\\s+(?:para\\s+(?:a\\s+)?|de\\s+)(?:press[ãa]o|dormir|afinar\\s+o\\s+sangue))", }; /** @@ -315,6 +327,7 @@ function medVocabulary(names: string | null): MedVocabulary { pl: `(?:${PL_MED_NOUN}|${extra("pl")})`, nl: `(?:${NL_MED_NOUN}|${extra("nl")})`, ko: `(?:${KO_MED_NOUN}|(?:${extra("ko")})\\S{0,3})`, + "pt-BR": `(?:${PT_MED_NOUN}|${extra("pt-BR")})`, }; } @@ -647,6 +660,46 @@ function buildDoseChangeClass( "i", ), ], + "pt-BR": [ + // Brazilian Portuguese addresses the reader as "você", whose imperative + // is the subjunctive form ("aumente", "tome", "pule"). The indicative a + // log restatement uses ("você toma 1000 mg", "a dose passou para 2000 + // mg") is not in any verb list. + new RegExp( + `(? = { "i", ), /\b(?:halveer|halveren|verdubbel|verdubbelen|sla\s+\S+\s+over|overslaan|stop\s+met)\b[^.?!]{0,25}(?:dosis|tablet\w*|medicijn\w*|medicatie|insuline|injectie\w*)[^.?!]{0,40}\b(?:(?:een|twee|drie|vier|\d+)\s+(?:dag|dagen|week|weken|maand|maanden)|om\s+te\s+(?:zien|testen|kijken|proberen))\b/i, - ], // Korean is verb-final: the dose comes first and the change verb closes the + ], + "pt-BR": [ + // aumente / suba / passe a dose para|a|até|em N unit + new RegExp( + `\\b(?:aumente|aumentar|suba|subir|passe|passar|eleve|elevar)\\s+(?:a\\s+|sua\\s+|a\\s+sua\\s+)?(?:dose\\s+)?(?:para|pra|a|até|em)\\s+[\\d.,]+\\s*${DOSE_UNIT}${UNIT_END}`, + "i", + ), + // reduza / diminua / baixe a dose para|a|até|em N unit + new RegExp( + `\\b(?:reduza|reduzir|diminua|diminuir|baixe|baixar|abaixe|abaixar)\\s+(?:a\\s+|sua\\s+|a\\s+sua\\s+)?(?:dose\\s+)?(?:para|pra|a|até|em)\\s+[\\d.,]+\\s*${DOSE_UNIT}${UNIT_END}`, + "i", + ), + // A recommending cue in front of a drug amount. `ml` is left out: "tente + // beber 2000 ml de água por dia" is hydration advice. + new RegExp( + `\\b(?:considere|experimente|tente|voc[êe]\\s+deveria|voc[êe]\\s+deve|recomendo|sugiro)\\b[^.?!]{0,40}\\b[\\d.,]+\\s*${DRUG_UNIT}${UNIT_END}`, + "i", + ), + new RegExp( + `\\b(?:pr[óo]xima|nova)\\s+(?:dose|etapa)\\b[^.?!]{0,30}\\b[\\d.,]+\\s*${DOSE_UNIT}${UNIT_END}`, + "i", + ), + /\b(?:dobr\w*|duplic\w*|pul(?:e|ar)|suspend\w*|interromp\w*|pare\s+de\s+tomar|parar\s+de\s+tomar)\b[^.?!]{0,25}\b(?:doses?|comprimidos?|rem[ée]dios?|medicamentos?|medica[çc]|insulina|inje[çc])[^.?!]{0,40}\b(?:por\s+(?:\d+|um|uma|dois|duas|tr[êe]s|quatro)\s+(?:dias?|semanas?|m[êe]s|meses)|para\s+(?:ver|testar|experimentar))\b/i, + ], + // Korean is verb-final: the dose comes first and the change verb closes the // clause ("2.4mg으로 늘려 보세요"), the mirror image of the Latin banks. A // target-marking particle on the dose is required, the same demand the Latin // banks make of "to" / "by" / "auf" — without it the permitted restatement @@ -988,6 +1065,21 @@ const RISK_LEVEL_NL = "(?:verhoogd|hoog|hoger|matig|gemiddeld|zorgwekkend|aanzienlijk)"; const RISK_VERDICT_NL = `(?:is|ligt|lijkt|blijft|wijst\\s+op|komt\\s+uit\\s+op)\\s+(?:\\w+\\s+){0,2}${RISK_LEVEL_NL}`; +const SPELLED_PT = + "(?:zero|um|uma|dois|duas|tr[êe]s|quatro|cinco|seis|sete|oito|nove|dez|onze|doze|treze|quatorze|catorze|quinze|dezesseis|dezessete|dezoito|dezenove|vinte|trinta|quarenta|cinquenta|sessenta)"; +const PCT_WORD_PT = `${SPELLED_PT}\\s+por\\s+cento`; +const QUAL_NUM_PT = `(?:\\d{1,3}\\s*%|${PCT_WORD_PT})`; +const RISK_NOUN_PT = "(?:risco|probabilidade|chance)"; +const HORIZON_PT = + "(?:risco\\s+(?:cardiovascular|card[íi]aco|de\\s+(?:avc|infarto|morte|mortalidade))\\s+(?:em|para|nos\\s+pr[óo]ximos)\\s+(?:10|dez)\\s+anos)"; +const RESULT_VERB_PT = + "(?:(?:te|lhe|o|a)\\s+(?:coloca|classifica|situa|enquadra|p[õo]e)|coloca\\s+voc[êe]|voc[êe]\\s+(?:est[áa]|fica|cai|se\\s+enquadra)\\s+(?:n[oa]s?|em))"; +const RISK_BAND_PT = + "(?:(?:faixa|categoria|grupo)\\s+de\\s+)?(?:alto|baixo|m[ée]dio|moderado|elevado|intermedi[áa]rio)\\s+risco"; +const RISK_LEVEL_PT = + "(?:elevad[oa]|alt[oa]|moderad[oa]|intermedi[áa]ri[oa]|lim[íi]trofe|preocupante|significativ[oa])"; +const RISK_VERDICT_PT = `(?:é|est[áa]|parece|fica|continua|indica|mostra|aponta\\s+para)\\s+(?:\\S+\\s+){0,2}${RISK_LEVEL_PT}`; + // Korean carries no `\\b` next to a Hangul token: `\\b` is an ASCII \\w boundary // and Hangul is not \\w, so /\\b위험/ matches nothing. Spelled-out percentages are // omitted deliberately — Korean writes "12%", and the Sino-Korean numerals @@ -1139,6 +1231,30 @@ const RISK_PATTERNS: Record = { "i", ), ], + "pt-BR": [ + /\brisco\s+(?:de|é\s+de|fica\s+em|está\s+em)\s+(?:aproximadamente\s+|cerca\s+de\s+|uns\s+|~)?\d{1,3}\s*%/i, + /\b\d{1,3}\s*%\s+(?:de\s+)?(?:risco|probabilidade|chance)/i, + new RegExp(`\\b${RISK_NOUN_PT}\\b[^.?!]{0,40}\\d{1,3}\\s*%`, "i"), + new RegExp(`\\d{1,3}\\s*%[^.?!]{0,40}\\b${RISK_NOUN_PT}\\b`, "i"), + new RegExp(`\\b${RISK_NOUN_PT}\\b[^.?!]{0,40}\\b${PCT_WORD_PT}\\b`, "i"), + new RegExp(`\\b${PCT_WORD_PT}\\b[^.?!]{0,40}\\b${RISK_NOUN_PT}\\b`, "i"), + new RegExp(`\\b${HORIZON_PT}\\b[^.?!]{0,40}${QUAL_NUM_PT}`, "i"), + new RegExp(`${QUAL_NUM_PT}[^.?!]{0,40}\\b${HORIZON_PT}\\b`, "i"), + new RegExp(`\\b${ENGINE}\\b[^.?!]{0,50}${QUAL_NUM_PT}`, "i"), + new RegExp(`${QUAL_NUM_PT}[^.?!]{0,50}\\b${ENGINE}\\b`, "i"), + new RegExp( + `\\b(?:${ENGINE}|${HORIZON_PT})\\b[^.?!]{0,60}${RESULT_VERB_PT}`, + "i", + ), + new RegExp( + `\\b(?:${ENGINE}|${HORIZON_PT})\\b[^.?!]{0,60}${RISK_BAND_PT}`, + "i", + ), + new RegExp( + `\\b(?:${ENGINE}|${HORIZON_PT})\\b[^.?!]{0,40}${RISK_VERDICT_PT}`, + "i", + ), + ], ko: [ new RegExp(`${RISK_NOUN_KO}[^.?!]{0,15}${QUAL_NUM_KO}`, "i"), new RegExp(`${QUAL_NUM_KO}[^.?!]{0,15}${RISK_NOUN_KO}`, "i"), @@ -1251,6 +1367,20 @@ const CAUSAL_PATTERNS: Record = { /\boorzaak\b/i, /\bverantwoordelijk\s+voor\b/i, ], + "pt-BR": [ + /\bporque\b/i, + /\bpor\s+causa\s+d/i, + /\bdevido\s+[aà]/i, + /\bcaus(?:a|am|ou|aram|ado|ada|ando)\b/i, + /\bprovoc\w*/i, + /\blev(?:ou|aram)\s+[aà]/i, + /\bresult(?:ou|aram)\s+(?:em|d[eoa])\b/i, + /\bem\s+raz[ãa]o\s+d/i, + /\bem\s+decorr[êe]ncia\s+d/i, + /\bgra[çc]as\s+[aà]/i, + /\brespons[áa]ve(?:l|is)\s+(?:por|pel[oa]s?)\b/i, + /\bculpa\s+d/i, + ], ko: [ /때문(?:에|이)/, /(?:으로|로)\s*인(?:해|하여|한)/, @@ -1314,6 +1444,8 @@ const DOSE_CONTINUATION: Record = { it: /\b(?:continui\s+(?:a|con|il)|mantenga|come\s+prescritto)\b/i, pl: /\b(?:kontynuuj|przyjmuj\s+dalej|zgodnie\s+z\s+zaleceniem|pozosta[ńn]\s+przy)\b/i, nl: /\b(?:blijf|ga\s+door\s+met|neem\s+\S+\s+(?:gewoon\s+)?verder|zoals\s+(?:voorgeschreven|afgesproken|gebruikelijk|gewoonlijk|altijd|eerder|je\s+gewend\s+bent)|volgens\s+(?:voorschrift|afspraak))\b/i, + "pt-BR": + /\b(?:continue\s+(?:tomando|usando|com|a\s+tomar)|siga\s+(?:tomando|com)|mantenha|conforme\s+(?:prescrito|receitado|orientado|combinado)|como\s+(?:prescrito|receitado|de\s+costume|sempre|antes)|de\s+acordo\s+com\s+a\s+(?:receita|prescri))/i, ko: /(?:그대로\s*(?:유지|복용)|계속\s*(?:복용|드시|유지)|처방(?:대로|받은\s*대로)|지시(?:대로|받은\s*대로)|유지하세요)/, }; @@ -1325,6 +1457,8 @@ const DOSE_CHANGE_STEM: Record = { it: /\b(?:aument|riduc|ridur|abbass|diminu|raddoppi|salt|dimezz)\w*/i, pl: /\b(?:zwiększ|zmniejsz|obniż|podnie[śs]|podwyższ|zreduk|pomi[ńn]|opu[śs][ćc])\w*/i, nl: /\b(?:verho|verla|vermind|halve|verdubbel|ophog|afbouw|bouw\s+af|overslaan|sla\s+\S+\s+over|stop)\w*/i, + "pt-BR": + /\b(?:aument|reduz|diminu|dobr|duplic|omit|suspend|interromp|baix(?:e|ar|ando)\b|abaix|elev(?:e|ar)\b|sub(?:a|ir)\b|pul(?:e|ar|ando)\b|parar?\s+de\s+tomar)\w*/i, ko: /(?:올리|올려|늘리|늘려|증량|높이|높여|인상|내리|내려|줄이|줄여|감량|낮추|낮춰|감축|절반|반으로|두\s?배|건너뛰|중단|끊)/, }; diff --git a/src/lib/documents/__tests__/describe-screen.test.ts b/src/lib/documents/__tests__/describe-screen.test.ts index e881687fc..e7a146a8a 100644 --- a/src/lib/documents/__tests__/describe-screen.test.ts +++ b/src/lib/documents/__tests__/describe-screen.test.ts @@ -32,6 +32,8 @@ describe("runDocumentSummary — screened prose", () => { pl: "Ten raport sugeruje, aby zwiększyć dawkę do 2,4 mg w przyszłym tygodniu.", ko: "이 보고서는 다음 주에 2.4mg으로 늘려 보라고 권해요.", nl: "Dit rapport stelt voor om de dosis volgende week naar 2,4 mg te verhogen.", + "pt-BR": + "Este laudo sugere aumentar sua dose para 2,4 mg na próxima semana.", }; for (const locale of locales) { diff --git a/src/lib/insights/__tests__/status-summary-screen.test.ts b/src/lib/insights/__tests__/status-summary-screen.test.ts index 9250fb45a..7a2be6255 100644 --- a/src/lib/insights/__tests__/status-summary-screen.test.ts +++ b/src/lib/insights/__tests__/status-summary-screen.test.ts @@ -23,6 +23,7 @@ const DOSE_VIOLATION: Record = { pl: '{"summary":"Proszę zwiększyć dawkę do 2,4 mg w przyszłym tygodniu."}', ko: '{"summary":"다음 주에 2.4mg으로 늘려 보세요."}', nl: '{"summary":"Verhoog je dosis volgende week naar 2,4 mg."}', + "pt-BR": '{"summary":"Aumente sua dose para 2,4 mg na próxima semana."}', }; const CAUSAL_VIOLATION: Record = { @@ -34,6 +35,7 @@ const CAUSAL_VIOLATION: Record = { pl: '{"summary":"Waga spadła, ponieważ spał Pan więcej."}', ko: '{"summary":"수면 때문에 체중이 줄었어요."}', nl: '{"summary":"Je gewicht daalde omdat je meer sliep."}', + "pt-BR": '{"summary":"Seu peso caiu porque você dormiu mais."}', }; const CLEAN: Record = { @@ -45,6 +47,8 @@ const CLEAN: Record = { pl: '{"summary":"Waga wynosi średnio 82 kg w tym tygodniu, stabilnie wobec zeszłego miesiąca."}', ko: '{"summary":"이번 주 체중은 평균 82kg으로, 지난달과 비슷해요."}', nl: '{"summary":"Je gewicht ligt deze week gemiddeld op 82 kg, stabiel ten opzichte van vorige maand."}', + "pt-BR": + '{"summary":"Seu peso está em média em 82 kg nesta semana, estável em relação ao mês passado."}', }; describe("finalizeStatusSummary — dose prescriptions are withheld", () => {