Skip to content

Commit

Permalink
Load locale ondemand + spanish locale (lukevella#249)
Browse files Browse the repository at this point in the history
  • Loading branch information
lukevella authored Jul 28, 2022
1 parent 0f35bd0 commit c2aea13
Show file tree
Hide file tree
Showing 30 changed files with 696 additions and 451 deletions.
2 changes: 2 additions & 0 deletions declarations/i18next.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import "react-i18next";

import app from "~/public/locales/en/app.json";
import common from "~/public/locales/en/common.json";
import errors from "~/public/locales/en/errors.json";
import homepage from "~/public/locales/en/homepage.json";

declare module "next-i18next" {
interface Resources {
homepage: typeof homepage;
app: typeof app;
common: typeof common;
errors: typeof errors;
}
}
2 changes: 1 addition & 1 deletion next-i18next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const path = require("path");
module.exports = {
i18n: {
defaultLocale: "en",
locales: ["en", "de", "fr", "sv"],
locales: ["en", "es", "de", "fr", "sv"],
localePath: path.resolve("./public/locales"),
reloadOnPrerender: process.env.NODE_ENV === "development",
},
Expand Down
6 changes: 5 additions & 1 deletion public/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,9 @@
"starOnGithub": "Star us on Github",
"support": "Support",
"swedish": "Swedish",
"volunteerTranslator": "Help translate this site"
"volunteerTranslator": "Help translate this site",
"notFoundTitle": "404 not found",
"notFoundDescription": "We couldn't find the page you're looking for.",
"goToHome": "Go to home",
"startChat": "Start chat"
}
6 changes: 6 additions & 0 deletions public/locales/en/errors.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"notFoundTitle": "404 not found",
"notFoundDescription": "We couldn't find the page you're looking for.",
"goToHome": "Go to home",
"startChat": "Start chat"
}
128 changes: 128 additions & 0 deletions public/locales/es/app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
{
"12h": "12h",
"24h": "24h",
"addParticipant": "Añadir participante",
"addTimeOption": "Añadir hora",
"alreadyVoted": "Ya has votado",
"applyToAllDates": "Aplicar a todas las fechas",
"areYouSure": "¿Estás seguro?",
"back": "Volver",
"calendarHelp": "No puedes crear una encuesta sin ninguna opción. Añada al menos una opción para continuar.",
"calendarHelpTitle": "¿Olvidaste algo?",
"cancel": "Cancelar",
"comment": "Comentario",
"commentPlaceholder": "Dejar un comentario en esta encuesta (visible para todos)",
"comments": "Comentarios",
"continue": "Continuar",
"copied": "Copiado",
"copyLink": "Copiar enlace",
"createdBy": "de <b>{{name}}</b>",
"createPoll": "Crear encuesta",
"creatingDemo": "Creando una encuesta de demostración…",
"delete": "Borrar",
"deleteComment": "Borrar comentario",
"deleteDate": "Borrar fecha",
"deletedPoll": "Encuesta borrada",
"deletedPollInfo": "Esta encuesta ya no existe.",
"deletePoll": "Borrar encuesta",
"deletePollDescription": "Todos los datos relacionados con esta encuesta se eliminarán. Para confirmar, por favor escribe <s>“{{confirmText}}”</s> en el campo siguiente:",
"deletingOptionsWarning": "Estás eliminando opciones por las que algunos participantes han votado. También se eliminarán sus votos.",
"demoPollNotice": "Las encuestas de demostración se eliminan automáticamente después de 1 día",
"description": "Descripción",
"descriptionPlaceholder": "¡Hola a todos, por favor elijan las fechas que les convengan!",
"donate": "Donar",
"editDetails": "Editar detalles",
"editOptions": "Editar opciones",
"email": "Correo electrónico",
"emailPlaceholder": "[email protected]",
"endingGuestSessionNotice": "Una vez que finalices la sesión de visitante, no se puede reanudar. No podrás editar ningún voto o comentario que hayas hecho con esta sesión.",
"endSession": "Cerrar Sesión",
"errorCreate": "¡Oh! Hubo un problema al crear tu encuesta. El error ha sido registrado y vamos a intentar arreglarlo.",
"exportToCsv": "Exportar a CSV",
"finish": "Finalizar",
"forgetMe": "Olvídame",
"goToAdmin": "Ir al panel de administración",
"guest": "Visitante",
"guestSessionNotice": "Estás usando una sesión de visitante. Esto nos permite reconocerte si vuelves más tarde para que puedas editar tus votos.",
"guestSessionReadMore": "Lee más sobre sesiones de visitantes.",
"hide": "Ocultar",
"ifNeedBe": "Si es necesario",
"linkHasExpired": "Tu enlace ha expirado o ya no es válido",
"loading": "Cargando…",
"loadingParticipants": "Cargando participantes…",
"location": "Ubicación",
"locationPlaceholder": "Café de Carlos",
"lockPoll": "Bloquear encuesta",
"login": "Iniciar sesión",
"loginCheckInbox": "Por favor, revisa tus correos electrónicos.",
"loginMagicLinkSent": "Se ha enviado un enlace mágico a:",
"loginSendMagicLink": "Enviarme un enlace mágico",
"loginViaMagicLink": "Iniciar sesión a través de un enlace mágico",
"loginViaMagicLinkDescription": "Te enviaremos un correo electrónico con un enlace mágico que puedes usar para iniciar sesión.",
"loginWithValidEmail": "Por favor ingresa un correo electrónico válido",
"logout": "Cerrar sesión",
"manage": "Gestionar",
"menu": "Menú",
"mixedOptionsDescription": "No puedes tener opciones de fecha y opciones de hora en la misma encuesta. ¿Cuáles quieres mantener?",
"mixedOptionsKeepDates": "Mantener las opciones de fecha",
"mixedOptionsKeepTimes": "Mantener las opciones de hora",
"mixedOptionsTitle": "Aguanta un minuto…🤔",
"monday": "Lunes",
"monthView": "Vista mensual",
"name": "Nombre",
"namePlaceholder": "Jessie Smith",
"newPoll": "Nueva encuesta",
"next": "Siguiente",
"nextMonth": "Siguiente mes",
"no": "No",
"noDatesSelected": "Ninguna fecha seleccionada",
"notificationsDisabled": "Las notificaciones han sido desactivadas",
"notificationsOff": "Las notificaciones están desactivadas",
"notificationsOn": "Las notificaciones están activadas",
"notificationsOnDescription": "Vamos a mandar un correo electrónico a <b>{{email}}</b> cuando haya actividad en esta encuesta.",
"notificationsVerifyEmail": "Tienes que verificar tu correo electrónico para activar las notificaciones",
"ok": "Aceptar",
"options": "Opciones",
"participant": "Participante",
"participantCount_other": "{{count}} participantes",
"participantCount": "{{count}} participante",
"pollHasBeenLocked": "Esta encuesta ha sido bloqueada",
"pollHasBeenVerified": "Esta encuesta ha sido verificada",
"pollOwnerNotice": "Hola {{name}}, parece que eres el dueño de esta encuesta.",
"pollsEmpty": "Ninguna encuesta creada",
"possibleAnswers": "Respuestas posibles",
"preferences": "Ajustes",
"previousMonth": "Mes anterior",
"profileLogin": "Perfil - Iniciar sesión",
"profileUser": "Perfil - {{username}}",
"requiredNameError": "El nombre es obligatorio",
"save": "Guardar",
"saveInstruction": "Selecciona tu disponibilidad y haz clic en <b>{{save}}</b>",
"share": "Compartir",
"shareDescription": "Dale este enlace a tus <b>participantes</b> para permitirles votar en tu encuesta.",
"shareLink": "Compartir con un enlace",
"specifyTimes": "Especificar tiempos",
"specifyTimesDescription": "Incluir horas de inicio y fin para cada opción",
"stepSummary": "Paso {{current}} de {{total}}",
"sunday": "Domingo",
"timeAndDate": "Fecha y hora",
"timeFormat": "Formato de hora:",
"timeZone": "Zona horaria:",
"title": "Título",
"titlePlaceholder": "Reunión mensual",
"today": "Hoy",
"unlockPoll": "Desbloquear encuesta",
"unverifiedMessage": "Se ha enviado un correo electrónico a <b>{{email}}</b> con un enlace para verificar la dirección de correo electrónico.",
"user": "Usuario",
"vote": "Votar",
"voteCount_other": "{{count}} votos",
"voteCount": "{{count}} voto",
"weekStartsOn": "La semana comienza el",
"weekView": "Vista semanal",
"whatsThis": "¿Qué es esto?",
"yes": "",
"you": "",
"yourDetails": "Tus datos",
"yourName": "Tu nombre…",
"yourPolls": "Tus encuestas"
}
21 changes: 21 additions & 0 deletions public/locales/es/common.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"blog": "Blog",
"discussions": "Discusiones",
"donate": "Donar",
"english": "Inglés",
"footerCredit": "Creado por <a>@imlukevella</a>",
"footerSponsor": "Este proyecto está financiado por los usuarios. Por favor, considera apoyarlo <a>donando</a>.",
"french": "Francés",
"german": "Alemán",
"home": "Inicio",
"italian": "Italiano",
"language": "Idioma",
"links": "Enlaces",
"poweredBy": "Con tecnología de",
"privacyPolicy": "Política de privacidad",
"spanish": "Español",
"starOnGithub": "Seguir el proyecto en GitHub",
"support": "Soporte",
"swedish": "Sueco",
"volunteerTranslator": "Ayuda a traducir esta página"
}
36 changes: 36 additions & 0 deletions public/locales/es/homepage.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"3Ls": "Sí—con 3 <e>L</e>s",
"adFree": "Sin anuncios",
"adFreeDescription": "Puedes darle un descanso a tu bloqueador de anuncios — No lo necesitarás aquí.",
"comments": "Comentarios",
"commentsDescription": "Los participantes pueden comentar en tu encuesta y los comentarios serán visibles para todos.",
"features": "Características",
"featuresSubheading": "Programar reuniones, de una manera inteligente",
"follow": "Seguir",
"getStarted": "Empezar",
"heroSubText": "Encuentra la fecha correcta sin dar vueltas",
"heroText": "Programar<br/><s>reuniones</s><br />con facilidad",
"links": "Enlaces",
"liveDemo": "Demostración en vivo",
"metaDescription": "Crea encuestas y vota para encontrar el mejor día o la mejor hora. Una alternativa gratuita a Doodle.",
"metaTitle": "Rallly - Programar reuniones",
"mobileFriendly": "Optimizado para dispositivos móviles",
"mobileFriendlyDescription": "Funciona muy bien en dispositivos móviles para que los participantes puedan responder a las encuestas dondequiera que estén.",
"new": "Nuevo",
"noLoginRequired": "No es necesario iniciar sesión",
"noLoginRequiredDescription": "No es necesario iniciar sesión para crear o participar en una encuesta",
"notifications": "Notificaciones",
"notificationsDescription": "Sabe quién ha respondido. Recibe notificaciones cuando los participantes voten o comenten en tu encuesta.",
"openSource": "Código abierto",
"openSourceDescription": "Ese proyecto es completamente de código abierto y <a>disponible en GitHub</a>.",
"participant": "Participante",
"participantCount_other": "{{count}} participantes",
"participantCount": "{{count}} participante",
"perfect": "¡Perfecto!",
"principles": "Principios",
"principlesSubheading": "No somos como los otros",
"selfHostable": "Autoalojable",
"selfHostableDescription": "Ejecútalo en tu propio servidor para tener el control total de tus datos",
"timeSlots": "Intervalos de tiempo",
"timeSlotsDescription": "Establece la hora de inicio y fin individual para cada opción de tu encuesta. Los tiempos se pueden ajustar automáticamente a la zona horaria de cada participante o pueden ser ajustados para ignorar completamente las zonas horarias."
}
3 changes: 2 additions & 1 deletion src/components/discussion/discussion.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import clsx from "clsx";
import dayjs from "dayjs";
import { AnimatePresence, motion } from "framer-motion";
import { useTranslation } from "next-i18next";
import { usePlausible } from "next-plausible";
import * as React from "react";
import { Controller, useForm } from "react-hook-form";

import { useDayjs } from "../../utils/dayjs";
import { requiredString } from "../../utils/form-validation";
import { trpc } from "../../utils/trpc";
import { Button } from "../button";
Expand All @@ -25,6 +25,7 @@ interface CommentForm {
}

const Discussion: React.VoidFunctionComponent = () => {
const { dayjs } = useDayjs();
const queryClient = trpc.useContext();
const { t } = useTranslation("app");
const { poll } = usePoll();
Expand Down
8 changes: 5 additions & 3 deletions src/components/error-page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Head from "next/head";
import Link from "next/link";
import { useTranslation } from "next-i18next";
import * as React from "react";

import { Button } from "@/components/button";
Expand All @@ -19,6 +20,7 @@ const ErrorPage: React.VoidFunctionComponent<ComponentProps> = ({
title,
description,
}) => {
const { t } = useTranslation("errors");
return (
<div className="mx-auto flex h-full max-w-full items-center justify-center bg-gray-50 px-4 py-8 lg:w-[1024px]">
<Head>
Expand All @@ -28,16 +30,16 @@ const ErrorPage: React.VoidFunctionComponent<ComponentProps> = ({
<div className="flex items-start">
<div className="text-center">
<Icon className="mb-4 inline-block w-24 text-slate-400" />
<div className="text-primary-500 mb-2 text-3xl font-bold ">
<div className="mb-2 text-3xl font-bold text-primary-500 ">
{title}
</div>
<p>{description}</p>
<div className="flex justify-center space-x-3">
<Link href="/" passHref={true}>
<a className="btn-default">Go to home</a>
<a className="btn-default">{t("goToHome")}</a>
</Link>
<Button icon={<Chat />} onClick={showCrispChat}>
Start chat
{t("startChat")}
</Button>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import clsx from "clsx";
import dayjs from "dayjs";
import { useTranslation } from "next-i18next";
import { usePlausible } from "next-plausible";
import * as React from "react";

import { usePreferences } from "@/components/preferences/use-preferences";

import {
expectTimeOption,
getDateProps,
removeAllOptionsForDay,
} from "../../../../utils/date-time-utils";
import { useDayjs } from "../../../../utils/dayjs";
import { Button } from "../../../button";
import CompactButton from "../../../compact-button";
import DateCard from "../../../date-card";
Expand Down Expand Up @@ -38,6 +36,7 @@ const MonthCalendar: React.VoidFunctionComponent<DateTimePickerProps> = ({
duration,
onChangeDuration,
}) => {
const { dayjs, weekStartsOn } = useDayjs();
const { t } = useTranslation("app");
const isTimedEvent = options.some((option) => option.type === "timeSlot");

Expand Down Expand Up @@ -76,8 +75,6 @@ const MonthCalendar: React.VoidFunctionComponent<DateTimePickerProps> = ({
);
}, [optionsByDay]);

const { weekStartsOn } = usePreferences();

const datepicker = useHeadlessDatePicker({
selection: datepickerSelection,
onNavigationChange: onNavigate,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import {
} from "@floating-ui/react-dom-interactions";
import { Listbox } from "@headlessui/react";
import clsx from "clsx";
import dayjs from "dayjs";
import * as React from "react";

import { stopPropagation } from "@/utils/stop-propagation";

import { useDayjs } from "../../../../utils/dayjs";
import ChevronDown from "../../../icons/chevron-down.svg";
import { styleMenuItem } from "../../../menu-styles";

Expand All @@ -28,6 +28,7 @@ const TimePicker: React.VoidFunctionComponent<TimePickerProps> = ({
className,
startFrom,
}) => {
const { dayjs } = useDayjs();
const { reference, floating, x, y, strategy, refs } = useFloating({
strategy: "fixed",
middleware: [
Expand Down
8 changes: 3 additions & 5 deletions src/components/forms/poll-options-form/week-calendar.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
import clsx from "clsx";
import dayjs from "dayjs";
import React from "react";
import { Calendar } from "react-big-calendar";
import { useMount } from "react-use";

import { getDuration } from "../../../utils/date-time-utils";
import { usePreferences } from "../../preferences/use-preferences";
import { useDayjs } from "../../../utils/dayjs";
import DateNavigationToolbar from "./date-navigation-toolbar";
import dayjsLocalizer from "./dayjs-localizer";
import { DateTimeOption, DateTimePickerProps } from "./types";
import { formatDateWithoutTime, formatDateWithoutTz } from "./utils";

const localizer = dayjsLocalizer(dayjs);

const WeekCalendar: React.VoidFunctionComponent<DateTimePickerProps> = ({
title,
options,
Expand All @@ -23,8 +20,9 @@ const WeekCalendar: React.VoidFunctionComponent<DateTimePickerProps> = ({
onChangeDuration,
}) => {
const [scrollToTime, setScrollToTime] = React.useState<Date>();
const { dayjs, timeFormat } = useDayjs();
const localizer = React.useMemo(() => dayjsLocalizer(dayjs), [dayjs]);

const { timeFormat } = usePreferences();
useMount(() => {
// Bit of a hack to force rbc to scroll to the right time when we close/open a modal
setScrollToTime(dayjs(date).add(-60, "minutes").toDate());
Expand Down
4 changes: 3 additions & 1 deletion src/components/headless-date-picker.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import dayjs from "dayjs";
import React from "react";

import { useDayjs } from "../utils/dayjs";

interface DayProps {
date: Date;
day: string;
Expand Down Expand Up @@ -33,6 +34,7 @@ export const useHeadlessDatePicker = (
selection: Date[];
toggle: (date: Date) => void;
} => {
const { dayjs } = useDayjs();
const [localSelection, setSelection] = React.useState<Date[]>([]);
const selection = options?.selection ?? localSelection;
const [localNavigationDate, setNavigationDate] = React.useState(today);
Expand Down
Loading

0 comments on commit c2aea13

Please sign in to comment.