diff --git a/next-i18next.config.js b/next-i18next.config.js
index 81fec6340..2f34263ac 100644
--- a/next-i18next.config.js
+++ b/next-i18next.config.js
@@ -4,6 +4,7 @@ module.exports = {
i18n: {
defaultLocale: "en",
locales: [
+ "ca",
"cs",
"da",
"de",
diff --git a/public/locales/ca/app.json b/public/locales/ca/app.json
new file mode 100644
index 000000000..7ef9ffce2
--- /dev/null
+++ b/public/locales/ca/app.json
@@ -0,0 +1,132 @@
+{
+ "12h": "12 h",
+ "24h": "24 h",
+ "addParticipant": "Afegir participant",
+ "addTimeOption": "Afegir franja horària",
+ "alreadyVoted": "Ja heu votat",
+ "applyToAllDates": "Aplicar a totes les dates",
+ "areYouSure": "N'esteu segur?",
+ "back": "Torna",
+ "calendarHelp": "No pot crear una enquesta sense cap opció. Afegeixi com a mínim una opció per a continuar.",
+ "calendarHelpTitle": "Oblida alguna cosa?",
+ "cancel": "Cancel·lar",
+ "comment": "Comentar",
+ "commentPlaceholder": "Deixi un comentari en aquesta enquesta (visible per a tothom)",
+ "comments": "Comentaris",
+ "continue": "Continuar",
+ "copied": "Copiat",
+ "copyLink": "Copiar l'enllaç",
+ "createdBy": "per {{name}}",
+ "createPoll": "Crear enquesta",
+ "creatingDemo": "Crear enquesta de prova…",
+ "delete": "Suprimir",
+ "deleteComment": "Suprimir comentari",
+ "deleteDate": "Suprimir data",
+ "deletedPoll": "Enquesta suprimida",
+ "deletedPollInfo": "Aquesta enquesta ja no existeix.",
+ "deletePoll": "Suprimir l'enquesta",
+ "deletePollDescription": "Totes les dades relacionades amb aquesta enquesta se suprimiran. Per confirmar, escrigui ”{{confirmText}}” a l'entrada següent:",
+ "deletingOptionsWarning": "Està suprimint opcions que han estat votades pels participants. Els seus vots també seran eliminats.",
+ "demoPollNotice": "Les enquestes de prova se suprimeixen automàticament després d'un dia",
+ "description": "Descripció",
+ "descriptionPlaceholder": "Hola a tothom, si us plau escullin les dates que els van millor!",
+ "donate": "Fer un donatiu",
+ "edit": "Editar",
+ "editDetails": "Edita els detalls",
+ "editOptions": "Edita les opcions",
+ "email": "Correu electrònic",
+ "emailPlaceholder": "jessie.smith@email.com",
+ "endingGuestSessionNotice": "Un cop finalitzada una sessió no es pot reprendre. Vostè no podrà editar cap vot o comentari que hagi fet en aquesta sessió.",
+ "endSession": "Finalitzar sessió",
+ "errorCreate": "Vaja! Hi ha hagut un problema creant la seva enquesta. L'error ha estat enregistrar i s'intentarà arreglar.",
+ "exportToCsv": "Exporta a CSV",
+ "finish": "Finalitzar",
+ "forgetMe": "Oblida'm",
+ "goToAdmin": "Anar al panell d'administració",
+ "guest": "Convidat",
+ "guestSessionNotice": "Està utilitzant una sessió de convidat. Això no permet reconèixer-te si torna més tard a editar els seus vots.",
+ "guestSessionReadMore": "Llegeix més sobre les sessions de convidats.",
+ "hide": "Amaga",
+ "ifNeedBe": "Si és necessari",
+ "linkHasExpired": "El seu enllaç ha caducat o és invàlid",
+ "loading": "Carregant…",
+ "loadingParticipants": "Carregant participants…",
+ "location": "Ubicació",
+ "locationPlaceholder": "Cafeteria Joe",
+ "lockPoll": "Bloquejar enquesta",
+ "login": "Iniciar sessió",
+ "loginCheckInbox": "Si us plau, comprovi la seva bústia.",
+ "loginMagicLinkSent": "Se li ha enviat un enllaç màgic a:",
+ "loginSendMagicLink": "Envia'm un enllaç màgic",
+ "loginViaMagicLink": "Iniciar sessió amb enllaç màgic",
+ "loginViaMagicLinkDescription": "Li enviarem un correu electrònic amb un enllaç màgic que pot utilitzar per iniciar sessió.",
+ "loginWithValidEmail": "Si us plau, introdueixi una adreça de correu electrònic vàlida",
+ "logout": "Tanca sessió",
+ "manage": "Gestionar",
+ "menu": "Menú",
+ "mixedOptionsDescription": "No pot tenir ambdues opcions de data i hora a la mateixa enquesta. Quina voldries mantenir?",
+ "mixedOptionsKeepDates": "Mantenir opcions de data",
+ "mixedOptionsKeepTimes": "Mantenir opcions de franja horària",
+ "mixedOptionsTitle": "Esperi un moment… 🤔",
+ "monday": "Dilluns",
+ "monthView": "Vista mensual",
+ "name": "Nom",
+ "namePlaceholder": "Jessie Smith",
+ "new": "Nou",
+ "newPoll": "Nova enquesta",
+ "next": "Següent",
+ "nextMonth": "Mes següent",
+ "no": "No",
+ "noDatesSelected": "No s'ha seleccionat cap data",
+ "notificationsDisabled": "S'han desactivat les notificacions",
+ "notificationsOff": "Notificacions desactivades",
+ "notificationsOn": "Notificacions activades",
+ "notificationsOnDescription": "S'enviarà un correu electrònic a {{email}} quan hi hagi novetats a l'enquesta.",
+ "notificationsVerifyEmail": "Necessita verificar el seu correu electrònic per activar les notificacions",
+ "noVotes": "Ningú ha votat aquesta opció",
+ "ok": "D'acord",
+ "options": "Opcions",
+ "participant": "Participant",
+ "participantCount_other": "{{count}} participants",
+ "participantCount": "{{count}} participant",
+ "pollHasBeenLocked": "Aquesta enquesta ha estat bloquejada",
+ "pollHasBeenVerified": "S'ha verificat la vostra enquesta",
+ "pollOwnerNotice": "Hola {{name}}, sembla que ets el creador d'aquesta enquesta.",
+ "pollsEmpty": "No s'ha creat cap enquesta",
+ "possibleAnswers": "Possibles respostes",
+ "preferences": "Preferències",
+ "previousMonth": "Mes anterior",
+ "profileLogin": "Perfil - Iniciar sessió",
+ "profileUser": "Perfil - {{username}}",
+ "requiredNameError": "El nom és obligatori",
+ "save": "Desa",
+ "saveInstruction": "Selecciona la seva disponibilitat i premi {{save}}",
+ "share": "Compartir",
+ "shareDescription": "Envia aquest enllaç als participants perquè puguin votar a l'enquesta.",
+ "shareLink": "Comparteix via enllaç",
+ "specifyTimes": "Especifica franges horàries",
+ "specifyTimesDescription": "Inclou les hores d'inici i final per a cada opció",
+ "stepSummary": "Pas {{current}} de {{total}}",
+ "sunday": "Diumenge",
+ "timeAndDate": "Data i hora",
+ "timeFormat": "Format horari:",
+ "timeZone": "Zona horària:",
+ "title": "Títol",
+ "titlePlaceholder": "Reunió mensual",
+ "today": "Avui",
+ "unlockPoll": "Desbloquejar enquesta",
+ "unverifiedMessage": "S'ha enviat un correu electrònic a {{email}} amb un enllaç per verificar a l'adreça de correu.",
+ "user": "Usuari",
+ "vote": "Vota",
+ "voteCount_other": "{{count}} vots",
+ "voteCount": "{{count}} vot",
+ "weekStartsOn": "La setmana comença en",
+ "weekView": "Vista setmanal",
+ "whatsThis": "Què és això?",
+ "yes": "Sí",
+ "you": "Vostè",
+ "yourDetails": "Les teves dades",
+ "yourName": "El vostre nom…",
+ "yourProfile": "El vostre perfil",
+ "yourPolls": "Les teves enquestes"
+}
diff --git a/public/locales/ca/common.json b/public/locales/ca/common.json
new file mode 100644
index 000000000..346f69330
--- /dev/null
+++ b/public/locales/ca/common.json
@@ -0,0 +1,15 @@
+{
+ "blog": "Blog",
+ "discussions": "Debats",
+ "donate": "Fer un donatiu",
+ "footerCredit": "Desenvolupat per @imlukevella",
+ "footerSponsor": "Aquest projecte és finançat pels usuaris. Si us plau, considera donar-nos suport fent un donatiu.",
+ "home": "Inici",
+ "language": "Idioma",
+ "links": "Enllaços",
+ "poweredBy": "Impulsat per",
+ "privacyPolicy": "Política de privacitat",
+ "starOnGithub": "Dona'ns una estrella a GitHub",
+ "support": "Suport",
+ "volunteerTranslator": "Ajuda a traduir aquesta pàgina"
+}
diff --git a/public/locales/ca/errors.json b/public/locales/ca/errors.json
new file mode 100644
index 000000000..eaf416210
--- /dev/null
+++ b/public/locales/ca/errors.json
@@ -0,0 +1,6 @@
+{
+ "notFoundTitle": "404 no s'ha trobat",
+ "notFoundDescription": "No hem pogut trobar la pàgina que estàveu buscant.",
+ "goToHome": "Anar a l'Inici",
+ "startChat": "Inicia un xat"
+}
diff --git a/public/locales/ca/homepage.json b/public/locales/ca/homepage.json
new file mode 100644
index 000000000..02dfe0e9e
--- /dev/null
+++ b/public/locales/ca/homepage.json
@@ -0,0 +1,36 @@
+{
+ "3Ls": "Sí, amb 3 Ls",
+ "adFree": "Sense anuncis",
+ "adFreeDescription": "Li pots donar un descans al teu bloquejador d'anuncis - No el necessitarà aquí.",
+ "comments": "Comentaris",
+ "commentsDescription": "Els participants poden fer comentaris a la teva enquesta i aquests seran visibles per a tothom.",
+ "features": "Característiques",
+ "featuresSubheading": "Planificant, de forma intel·ligent",
+ "follow": "Segueix-nos a",
+ "getStarted": "Comenci",
+ "heroSubText": "Trobi la data apropiada amb el mínim esforç",
+ "heroText": "Planifica reunions grupals amb facilitat",
+ "links": "Enllaços",
+ "liveDemo": "Demostració en viu",
+ "metaDescription": "Crea enquestes i vota per trobar el millor dia o hora. Una alternativa gratuïta a Doodle.",
+ "metaTitle": "Rallly - Planifica reunions de grup",
+ "mobileFriendly": "Adaptat per mòbil",
+ "mobileFriendlyDescription": "Funciona perfectament en dispositius mòbils, per tant, els participants poden respondre enquestes des d'on siguin.",
+ "new": "Nou",
+ "noLoginRequired": "No cal iniciar sessió",
+ "noLoginRequiredDescription": "No es necessita iniciar sessió per crear o participar en una enquesta",
+ "notifications": "Notificacions",
+ "notificationsDescription": "Fes un seguiment de qui ha respost. Rep notificacions quan els participants votin o comentin a la teva enquesta.",
+ "openSource": "Codi obert",
+ "openSourceDescription": "El codi font és completament obert i disponible a GitHub.",
+ "participant": "Participant",
+ "participantCount_other": "{{count}} participants",
+ "participantCount": "{{count}} participant",
+ "perfect": "Perfecte!",
+ "principles": "Principis",
+ "principlesSubheading": "No som com la resta",
+ "selfHostable": "Autoallotjable",
+ "selfHostableDescription": "Executa-ho al teu servir per tenir control absolut de totes les dades",
+ "timeSlots": "Franges horàries",
+ "timeSlotsDescription": "Definiu els temps d'inici i final individuals per a cada opció a l'enquesta. Els temps es poden ajustar automàticament a la zona horària de cada participant o es poden establir per ignorar completament les zones horàries."
+}
diff --git a/src/components/poll/language-selector.tsx b/src/components/poll/language-selector.tsx
index c34921739..a1fe1b9e7 100644
--- a/src/components/poll/language-selector.tsx
+++ b/src/components/poll/language-selector.tsx
@@ -19,6 +19,7 @@ export const LanguageSelect: React.VoidFunctionComponent<{
}}
>
+
diff --git a/src/middleware.ts b/src/middleware.ts
index 6de7e4fd4..8efcff6ce 100644
--- a/src/middleware.ts
+++ b/src/middleware.ts
@@ -2,6 +2,7 @@ import languageParser from "accept-language-parser";
import { NextRequest, NextResponse } from "next/server";
const supportedLocales = [
+ "ca",
"cs",
"da",
"de",
diff --git a/src/utils/dayjs.tsx b/src/utils/dayjs.tsx
index 8fe396425..e125c3ee9 100644
--- a/src/utils/dayjs.tsx
+++ b/src/utils/dayjs.tsx
@@ -35,6 +35,11 @@ const dayjsLocales: Record<
timeFormat: "24h",
import: () => import("dayjs/locale/es"),
},
+ ca: {
+ weekStartsOn: "monday",
+ timeFormat: "24h",
+ import: () => import("dayjs/locale/ca"),
+ },
da: {
weekStartsOn: "monday",
timeFormat: "24h",