From 6c15a66cde77a4d0e3a59e28a8ca21ffb2c1f3dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Thu, 22 Oct 2026 15:15:48 +0200 Subject: [PATCH] feat(mental-health): show Brazil's crisis line to pt-BR readers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A Brazilian Portuguese reader who answered PHQ-9 item 9 saw the international set: 112 and two directories. They now see CVV (Centro de Valorização da Vida), 188 by phone and the chat at cvv.org.br, free and answering around the clock, with SAMU's 192 as the emergency number. Both were checked against cvv.org.br and the Ministry of Health's SAMU page. A bare "pt" or "pt-PT" keeps the international set, because 188 does not connect from Portugal. The CVV label is translated in every bundle, and a test pins that every resource of every locale's set resolves its label in that locale. --- messages/de.json | 3 ++ messages/en.json | 3 ++ messages/es.json | 3 ++ messages/fr.json | 3 ++ messages/it.json | 3 ++ messages/ko.json | 3 ++ messages/nl.json | 3 ++ messages/pl.json | 3 ++ messages/pt-BR.json | 3 ++ .../__tests__/crisis-resources.test.ts | 36 +++++++++++++++++++ src/lib/mental-health/crisis-resources.ts | 16 +++++++++ 11 files changed, 79 insertions(+) create mode 100644 src/lib/mental-health/__tests__/crisis-resources.test.ts diff --git a/messages/de.json b/messages/de.json index 725531c59..3246ea3e3 100644 --- a/messages/de.json +++ b/messages/de.json @@ -11069,6 +11069,9 @@ }, "crisisTextLine": { "name": "Crisis Text Line" + }, + "cvv": { + "name": "CVV, Centro de Valorização da Vida (rund um die Uhr, kostenlos, vertraulich)" } }, "instrumentDescription": { diff --git a/messages/en.json b/messages/en.json index e2c3a9223..023d08326 100644 --- a/messages/en.json +++ b/messages/en.json @@ -11069,6 +11069,9 @@ }, "crisisTextLine": { "name": "Crisis Text Line" + }, + "cvv": { + "name": "CVV, Centro de Valorização da Vida (24/7, free, confidential)" } }, "instrumentDescription": { diff --git a/messages/es.json b/messages/es.json index 6c23f0402..3c613d3bc 100644 --- a/messages/es.json +++ b/messages/es.json @@ -11069,6 +11069,9 @@ }, "crisisTextLine": { "name": "Crisis Text Line" + }, + "cvv": { + "name": "CVV, Centro de Valorização da Vida (24/7, gratuito y confidencial)" } }, "instrumentDescription": { diff --git a/messages/fr.json b/messages/fr.json index 763756fd7..dc744e4ab 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -11069,6 +11069,9 @@ }, "crisisTextLine": { "name": "Crisis Text Line" + }, + "cvv": { + "name": "CVV, Centro de Valorização da Vida (24h/24, 7j/7, gratuit et confidentiel)" } }, "instrumentDescription": { diff --git a/messages/it.json b/messages/it.json index f0b376277..f97e90b09 100644 --- a/messages/it.json +++ b/messages/it.json @@ -11069,6 +11069,9 @@ }, "crisisTextLine": { "name": "Crisis Text Line" + }, + "cvv": { + "name": "CVV, Centro de Valorização da Vida (24/7, gratuito e riservato)" } }, "instrumentDescription": { diff --git a/messages/ko.json b/messages/ko.json index 57a78bf48..2e1f6d750 100644 --- a/messages/ko.json +++ b/messages/ko.json @@ -11069,6 +11069,9 @@ }, "crisisTextLine": { "name": "Crisis Text Line" + }, + "cvv": { + "name": "CVV, Centro de Valorização da Vida (24시간 연중무휴, 무료, 비밀 보장)" } }, "instrumentDescription": { diff --git a/messages/nl.json b/messages/nl.json index ce6a13521..0be779297 100644 --- a/messages/nl.json +++ b/messages/nl.json @@ -11069,6 +11069,9 @@ }, "crisisTextLine": { "name": "Crisis Text Line" + }, + "cvv": { + "name": "CVV, Centro de Valorização da Vida (dag en nacht, gratis, vertrouwelijk)" } }, "instrumentDescription": { diff --git a/messages/pl.json b/messages/pl.json index fd677359a..8d7435a9b 100644 --- a/messages/pl.json +++ b/messages/pl.json @@ -11069,6 +11069,9 @@ }, "crisisTextLine": { "name": "Crisis Text Line" + }, + "cvv": { + "name": "CVV, Centro de Valorização da Vida (całodobowo, bezpłatnie i poufnie)" } }, "instrumentDescription": { diff --git a/messages/pt-BR.json b/messages/pt-BR.json index 28d99aad1..389ae0ba8 100644 --- a/messages/pt-BR.json +++ b/messages/pt-BR.json @@ -11069,6 +11069,9 @@ }, "crisisTextLine": { "name": "Crisis Text Line" + }, + "cvv": { + "name": "CVV, Centro de Valorização da Vida (24 horas, gratuito, sigiloso)" } }, "instrumentDescription": { diff --git a/src/lib/mental-health/__tests__/crisis-resources.test.ts b/src/lib/mental-health/__tests__/crisis-resources.test.ts new file mode 100644 index 000000000..af7c5df12 --- /dev/null +++ b/src/lib/mental-health/__tests__/crisis-resources.test.ts @@ -0,0 +1,36 @@ +import { describe, expect, it } from "vitest"; + +import { locales } from "@/lib/i18n/config"; +import { getServerTranslator } from "@/lib/i18n/server-translator"; + +import { crisisResourcesForLocale } from "../crisis-resources"; + +describe("crisisResourcesForLocale", () => { + it("gives a Brazilian Portuguese reader CVV and SAMU", () => { + const set = crisisResourcesForLocale("pt-BR"); + expect(set.emergencyNumber).toBe("192"); + expect(set.resources[0]).toEqual({ + id: "cvv", + contacts: ["188", "cvv.org.br/chat"], + }); + }); + + it("keeps the international set for Portuguese outside Brazil", () => { + // 188 does not connect from Portugal. + for (const locale of ["pt", "pt-PT"]) { + const set = crisisResourcesForLocale(locale); + expect(set.emergencyNumber).toBe("112"); + expect(set.resources.map((r) => r.id)).not.toContain("cvv"); + } + }); + + it("names every resource of every locale's set in that locale", () => { + for (const locale of locales) { + const { t } = getServerTranslator(locale); + for (const resource of crisisResourcesForLocale(locale).resources) { + const key = `mentalHealth.crisisResource.${resource.id}.name`; + expect(t(key), `${locale} ${key}`).not.toBe(key); + } + } + }); +}); diff --git a/src/lib/mental-health/crisis-resources.ts b/src/lib/mental-health/crisis-resources.ts index bd3743977..386d2680b 100644 --- a/src/lib/mental-health/crisis-resources.ts +++ b/src/lib/mental-health/crisis-resources.ts @@ -98,6 +98,19 @@ const US: CrisisResourceSet = { ], }; +/** + * Brazil (pt-BR) — CVV by phone and chat, SAMU as the emergency number. + * Both numbers are free and answer around the clock (cvv.org.br; the + * Ministry of Health's SAMU 192 page). + */ +const BR: CrisisResourceSet = { + emergencyNumber: "192", + resources: [ + { id: "cvv", contacts: ["188", "cvv.org.br/chat"] }, + { id: "findahelpline", contacts: ["findahelpline.com"] }, + ], +}; + /** * Resolve a crisis-resource set from the user's locale. Region detection is * coarse (locale prefix) and defaults to the international set — the goal is to @@ -117,5 +130,8 @@ export function crisisResourcesForLocale( if (lc === "de-ch" || lc === "de_ch" || lc === "ch") return CH; if (lc.startsWith("de")) return DE_AT_CH; if (lc === "en-us" || lc.startsWith("en_us") || lc === "us") return US; + // Brazilian Portuguese only: CVV's 188 does not connect from Portugal, so a + // bare "pt" or "pt-PT" keeps the international set. + if (lc === "pt-br" || lc === "pt_br" || lc === "br") return BR; return INTERNATIONAL; }