Skip to content

Commit cc0f27c

Browse files
ussaamaspashii
andauthored
ECHO-620 add Italian language support in the app (#399)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **New Features** * Added Italian (it-IT) language support throughout the application with complete UI translations * Italian users can now select Italian in language preferences * Italian onboarding guides and verification content available * New "Help us translate" link in header for community translation contributions <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Sameer Pashikanti <sameer@dembrane.com>
1 parent d6096a0 commit cc0f27c

39 files changed

Lines changed: 5544 additions & 437 deletions

echo/frontend/lingui.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const config: LinguiConfig = {
1010
fallbackLocales: {
1111
default: "en-US",
1212
},
13-
locales: ["en-US", "nl-NL", "de-DE", "fr-FR", "es-ES"],
13+
locales: ["en-US", "nl-NL", "de-DE", "fr-FR", "es-ES", "it-IT"],
1414
sourceLocale: "en-US",
1515
};
1616

echo/frontend/src/components/announcement/utils/dateUtils.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { formatRelative } from "date-fns";
2-
import { de, enUS, es, fr, nl } from "date-fns/locale";
2+
import { de, enUS, es, fr, it, nl } from "date-fns/locale";
33
import { useLanguage } from "@/hooks/useLanguage";
44

55
// Map of supported locales to date-fns locales
@@ -8,6 +8,7 @@ const localeMap = {
88
"en-US": enUS,
99
"es-ES": es,
1010
"fr-FR": fr,
11+
"it-IT": it,
1112
"nl-NL": nl,
1213
} as const;
1314

echo/frontend/src/components/conversation/VerifiedArtefactsSection.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ const LANGUAGE_TO_LOCALE: Record<string, string> = {
3737
en: "en-US",
3838
es: "es-ES",
3939
fr: "fr-FR",
40+
it: "it-IT",
4041
nl: "nl-NL",
4142
};
4243

echo/frontend/src/components/language/LanguagePicker.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ const data: Array<{
3535
label: "Français",
3636
language: "fr-FR",
3737
},
38+
{
39+
flag: "🇮🇹",
40+
iso639_1: "it",
41+
label: "Italiano",
42+
language: "it-IT",
43+
},
3844
{
3945
flag: "🇪🇸",
4046
iso639_1: "es",

echo/frontend/src/components/layout/Header.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
IconNotes,
99
IconSettings,
1010
IconShieldLock,
11+
IconWorld,
1112
} from "@tabler/icons-react";
1213
import { useParams } from "react-router";
1314
import {
@@ -184,6 +185,15 @@ const HeaderView = ({ isAuthenticated, loading }: HeaderViewProps) => {
184185

185186
<CreateFeedbackButton />
186187

188+
<Menu.Item
189+
rightSection={<IconWorld />}
190+
component="a"
191+
href="https://tally.so/r/PdprZV"
192+
target="_blank"
193+
>
194+
<Trans>Help us translate</Trans>
195+
</Menu.Item>
196+
187197
<Menu.Item
188198
rightSection={<IconLogout />}
189199
onClick={handleLogout}

echo/frontend/src/components/participant/ParticipantOnboardingCards.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,31 @@ const ParticipantOnboardingCards = ({ project }: { project: Project }) => {
176176
],
177177
},
178178
],
179+
"it-IT": [
180+
...getSystemCards("it-IT", tutorialSlug),
181+
{
182+
section: "Controllo Microfono",
183+
slides: [
184+
{
185+
component: MicrophoneTestComponent,
186+
content: "Assicuriamoci di poterti sentire.",
187+
icon: IconMicrophone,
188+
title: "Controllo Microfono",
189+
type: "microphone",
190+
},
191+
],
192+
},
193+
{
194+
section: "Pronti a iniziare?",
195+
slides: [
196+
{
197+
component: InitiateFormComponent,
198+
icon: Play,
199+
title: "Pronti a iniziare?",
200+
},
201+
],
202+
},
203+
],
179204
"nl-NL": [
180205
...getSystemCards("nl-NL", tutorialSlug),
181206
{

echo/frontend/src/components/participant/hooks/useOnboardingCards.ts

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,75 @@ export const useOnboardingCards = () => {
330330
],
331331
},
332332
],
333+
"it-IT": [
334+
{
335+
section: "Benvenuto",
336+
slides: [
337+
{
338+
content:
339+
"Registra la tua voce per rispondere alle domande e avere un impatto.",
340+
cta: "Andiamo!",
341+
extraHelp:
342+
"Questo è un mini-tutorial. Usa i pulsanti precedente e successivo per navigare. Al termine entrerai nel portale di registrazione.",
343+
icon: PartyPopper,
344+
title: "Benvenuto su Dembrane!",
345+
},
346+
{
347+
content:
348+
"Dembrane aiuta a raccogliere facilmente contributi da grandi gruppi.",
349+
cta: "Dimmi di più",
350+
extraHelp:
351+
"Che si tratti di feedback per un comune, di input sul lavoro o di partecipazione a una ricerca, la tua voce conta!",
352+
icon: Orbit,
353+
title: "Cos'è Dembrane?",
354+
},
355+
{
356+
content:
357+
"Rispondi alle domande a tuo ritmo parlando o scrivendo.",
358+
cta: "Avanti",
359+
extraHelp:
360+
"La voce è la modalità principale perché permette risposte più naturali e ricche. Scrivere è sempre disponibile come alternativa.",
361+
icon: Speech,
362+
title: "Dì semplicemente ciò che pensi",
363+
},
364+
{
365+
content: "Dembrane è più divertente in gruppo!",
366+
cta: "Avanti",
367+
extraHelp:
368+
"È ancora meglio se trovi qualcuno con cui discutere le domande e registrare la conversazione. Non possiamo sapere chi ha detto cosa, solo quali idee sono state condivise.",
369+
icon: MessagesSquare,
370+
title: "Da soli o in gruppo",
371+
},
372+
],
373+
},
374+
{
375+
section: "Come funziona",
376+
slides: [
377+
{
378+
content:
379+
"Riceverai le domande quando sarai nel portale di registrazione.",
380+
cta: "Capito",
381+
extraHelp:
382+
"Le domande variano in base alle esigenze dell'host. Possono riguardare temi della comunità, esperienze di lavoro o ricerca. Se non ci sono domande specifiche, puoi condividere qualsiasi pensiero o preoccupazione.",
383+
icon: HelpCircle,
384+
title: "È il momento delle domande",
385+
},
386+
],
387+
},
388+
{
389+
section: "Privacy",
390+
slides: [
391+
{
392+
content: "Come registratore, controlli tu ciò che condividi.",
393+
cta: "Dimmi di più",
394+
extraHelp:
395+
"Evita di condividere dettagli che non vuoi rendere noti all'host. Chiedi sempre il consenso prima di registrare altre persone.",
396+
icon: Lock,
397+
title: "La privacy conta",
398+
},
399+
],
400+
},
401+
],
333402
"nl-NL": [
334403
{
335404
section: "Welkom",
@@ -816,6 +885,108 @@ export const useOnboardingCards = () => {
816885
],
817886
},
818887
],
888+
"it-IT": [
889+
{
890+
section: "Benvenuto",
891+
slides: [
892+
{
893+
content:
894+
"Registra la tua voce per rispondere alle domande e avere un impatto.",
895+
cta: "Andiamo!",
896+
extraHelp:
897+
"Questo è un mini-tutorial. Usa i pulsanti precedente e successivo per navigare. Al termine entrerai nel portale di registrazione.",
898+
icon: PartyPopper,
899+
title: "Benvenuto su Dembrane!",
900+
},
901+
{
902+
content:
903+
"Dembrane aiuta a raccogliere facilmente contributi da grandi gruppi.",
904+
cta: "Dimmi di più",
905+
extraHelp:
906+
"Che si tratti di feedback per un comune, di input sul lavoro o di partecipazione a una ricerca, la tua voce conta!",
907+
icon: Orbit,
908+
title: "Cos'è Dembrane?",
909+
},
910+
{
911+
content:
912+
"Rispondi alle domande a tuo ritmo parlando o scrivendo.",
913+
cta: "Avanti",
914+
extraHelp:
915+
"La voce è la modalità principale perché permette risposte più naturali e ricche. Scrivere è sempre disponibile come alternativa.",
916+
icon: Speech,
917+
title: "Dì semplicemente ciò che pensi",
918+
},
919+
{
920+
content: "Dembrane è più divertente in gruppo!",
921+
cta: "Avanti",
922+
extraHelp:
923+
"È ancora meglio se trovi qualcuno con cui discutere le domande e registrare la conversazione. Non possiamo sapere chi ha detto cosa, solo quali idee sono state condivise.",
924+
icon: MessagesSquare,
925+
title: "Da soli o in gruppo",
926+
},
927+
],
928+
},
929+
{
930+
section: "Come funziona",
931+
slides: [
932+
{
933+
content:
934+
"Riceverai le domande quando sarai nel portale di registrazione.",
935+
cta: "Capito",
936+
extraHelp:
937+
"Le domande variano in base alle esigenze dell'host. Possono riguardare temi della comunità, esperienze di lavoro o ricerca. Se non ci sono domande specifiche, puoi condividere qualsiasi pensiero o preoccupazione.",
938+
icon: HelpCircle,
939+
title: "È il momento delle domande",
940+
},
941+
],
942+
},
943+
{
944+
section: "Privacy",
945+
slides: [
946+
{
947+
content: "Come registratore, controlli tu ciò che condividi.",
948+
cta: "Dimmi di più",
949+
extraHelp:
950+
"Evita di condividere dettagli che non vuoi rendere noti all'host. Chiedi sempre il consenso prima di registrare altre persone.",
951+
icon: Lock,
952+
title: "La privacy conta",
953+
},
954+
...(getPrivacyCard("it-IT")?.slides || []),
955+
],
956+
},
957+
{
958+
section: "Migliori Pratiche",
959+
slides: [
960+
{
961+
content:
962+
"Immagina che Dembrane sia in vivavoce con te. Se riesci a sentirti, sei a posto.",
963+
cta: "Capito",
964+
extraHelp:
965+
"Un po' di rumore di fondo va bene, purché sia chiaro chi sta parlando.",
966+
icon: Volume2,
967+
title: "Riduci il Rumore di Fondo",
968+
},
969+
{
970+
content:
971+
"Assicurati di avere una connessione stabile per una registrazione fluida.",
972+
cta: "Pronto!",
973+
extraHelp:
974+
"Wi-Fi o buoni dati mobili funzionano meglio. Se la connessione cade, non preoccuparti. Puoi sempre riprendere da dove avevi interrotto.",
975+
icon: Wifi,
976+
title: "Connessione Internet Forte",
977+
},
978+
{
979+
content:
980+
"Evita interruzioni mantenendo il dispositivo sbloccato. Se si blocca, sbloccalo semplicemente e continua.",
981+
cta: "Okay",
982+
extraHelp:
983+
"Dembrane cerca di mantenere il dispositivo attivo, ma a volte i dispositivi possono sovrascrivere questa impostazione. Puoi regolare le impostazioni del dispositivo per rimanere sbloccato più a lungo se necessario.",
984+
icon: Smartphone,
985+
title: "Non bloccare il dispositivo!",
986+
},
987+
],
988+
},
989+
],
819990
"nl-NL": [
820991
{
821992
section: "Welkom",
@@ -1016,6 +1187,28 @@ export const useOnboardingCards = () => {
10161187
},
10171188
],
10181189
},
1190+
"it-IT": {
1191+
section: "Privacy",
1192+
slides: [
1193+
{
1194+
checkbox: {
1195+
label: "Accetto l'informativa sulla privacy",
1196+
required: true,
1197+
},
1198+
content:
1199+
"I tuoi dati sono archiviati in modo sicuro, analizzati e mai condivisi con terze parti.",
1200+
cta: "Ho capito",
1201+
extraHelp:
1202+
"Le registrazioni vengono trascritte e analizzate per ottenere insight, poi eliminate dopo 30 giorni. Per dettagli specifici, contatta l'host che ti ha fornito il QR code.",
1203+
icon: Server,
1204+
link: {
1205+
label: "Leggi l'informativa completa sulla privacy",
1206+
url: "https://dembrane.notion.site/Privacy-Statement-Dembrane-1439cd84270580748046cc589861d115",
1207+
},
1208+
title: "Uso dei dati e sicurezza",
1209+
},
1210+
],
1211+
},
10191212
"nl-NL": {
10201213
section: "Privacy",
10211214
slides: [

echo/frontend/src/components/participant/verify/VerifiedArtefactsList.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export const VerifiedArtefactsList = ({
3131
en: "en-US",
3232
es: "es-ES",
3333
fr: "fr-FR",
34+
it: "it-IT",
3435
nl: "nl-NL",
3536
};
3637

echo/frontend/src/components/participant/verify/VerifySelection.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@ import {
1616
} from "./hooks";
1717
import { VerifyInstructions } from "./VerifyInstructions";
1818

19-
type LanguageCode = "de" | "en" | "es" | "fr" | "nl";
19+
type LanguageCode = "de" | "en" | "es" | "fr" | "nl" | "it";
2020

2121
const LANGUAGE_TO_LOCALE: Record<LanguageCode, string> = {
2222
de: "de-DE",
2323
en: "en-US",
2424
es: "es-ES",
2525
fr: "fr-FR",
26+
it: "it-IT",
2627
nl: "nl-NL",
2728
};
2829

echo/frontend/src/components/project/ProjectPortalEditor.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,20 @@ const FormSchema = z.object({
5050
is_get_reply_enabled: z.boolean(),
5151
is_project_notification_subscription_allowed: z.boolean(),
5252
is_verify_enabled: z.boolean(),
53-
language: z.enum(["en", "nl", "de", "fr", "es"]),
53+
language: z.enum(["en", "nl", "de", "fr", "es", "it"]),
5454
verification_topics: z.array(z.string()),
5555
});
5656

5757
type ProjectPortalFormValues = z.infer<typeof FormSchema>;
5858

59-
type LanguageCode = "de" | "en" | "es" | "fr" | "nl";
59+
type LanguageCode = "de" | "en" | "es" | "fr" | "nl" | "it";
6060

6161
const LANGUAGE_TO_LOCALE: Record<LanguageCode, string> = {
6262
de: "de-DE",
6363
en: "en-US",
6464
es: "es-ES",
6565
fr: "fr-FR",
66+
it: "it-IT",
6667
nl: "nl-NL",
6768
};
6869

@@ -465,6 +466,7 @@ const ProjectPortalEditorComponent: React.FC<ProjectPortalEditorProps> = ({
465466
{ label: t`German`, value: "de" },
466467
{ label: t`Spanish`, value: "es" },
467468
{ label: t`French`, value: "fr" },
469+
{ label: t`Italian`, value: "it" },
468470
]}
469471
{...field}
470472
/>

0 commit comments

Comments
 (0)