Add Swedish locale (#244)

* Add Swedish locale

* Stop reload when changing language

* Add translation

* Remove unused
This commit is contained in:
Luke Vella 2022-07-26 18:50:10 +01:00 committed by GitHub
parent 0546ed44a9
commit 2bacb67beb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 194 additions and 14 deletions

View file

@ -3,7 +3,7 @@ const path = require("path");
module.exports = { module.exports = {
i18n: { i18n: {
defaultLocale: "en", defaultLocale: "en",
locales: ["en", "de", "fr"], locales: ["en", "de", "fr", "sv"],
localePath: path.resolve("./public/locales"), localePath: path.resolve("./public/locales"),
reloadOnPrerender: process.env.NODE_ENV === "development", reloadOnPrerender: process.env.NODE_ENV === "development",
}, },

View file

@ -16,5 +16,6 @@
"spanish": "Spanish", "spanish": "Spanish",
"starOnGithub": "Star us on Github", "starOnGithub": "Star us on Github",
"support": "Support", "support": "Support",
"swedish": "Swedish",
"volunteerTranslator": "Help translate this site" "volunteerTranslator": "Help translate this site"
} }

128
public/locales/sv/app.json Normal file
View file

@ -0,0 +1,128 @@
{
"12h": "12-timmar",
"24h": "24-timmar",
"addParticipant": "Lägg till deltagare",
"addTimeOption": "Lägg till tidsalternativ",
"alreadyVoted": "Du har redan röstat",
"applyToAllDates": "Tillämpa på alla datum",
"areYouSure": "Är du säker?",
"back": "Tillbaka",
"calendarHelp": "Du kan inte skapa en enkät utan några alternativ. Lägg till minst ett alternativ för att fortsätta.",
"calendarHelpTitle": "Glöm något?",
"cancel": "Avbryt",
"comment": "Kommentera",
"commentPlaceholder": "Lämna en kommentar på denna enkät (synlig för alla)",
"comments": "Kommentarer",
"continue": "Fortsätt",
"copied": "Kopierad",
"copyLink": "Kopiera länk",
"createdBy": "av <b>{{name}}</b>",
"createPoll": "Skapa en enkät",
"creatingDemo": "Skapar demoenkät…",
"delete": "Radera",
"deleteComment": "Radera kommentar",
"deleteDate": "Radera datum",
"deletedPoll": "Raderad enkät",
"deletedPollInfo": "Den här enkäten finns inte längre.",
"deletePoll": "Radera enkät",
"deletePollDescription": "All data relaterad till denna enkät kommer att raderas. För att bekräfta, skriv <s>”{{confirmText}}”</s> i inmatningsrutan nedan:",
"deletingOptionsWarning": "Du tar bort alternativ som deltagarna har röstat på. Deras röster kommer också att raderas.",
"demoPollNotice": "Demoenkäter raderas automatiskt efter 1 dag",
"description": "Beskrivning",
"descriptionPlaceholder": "Hej alla, välj de datum som fungerar för dig!",
"donate": "Donera",
"editDetails": "Redigera detaljer",
"editOptions": "Redigera alternativ",
"email": "E-post",
"emailPlaceholder": "olle.jonsson@email.com",
"endingGuestSessionNotice": "När en gäst session avslutas kan den inte återupptas. Du kommer inte att kunna redigera några röster eller kommentarer som du har gjort med denna session.",
"endSession": "Avsluta session",
"errorCreate": "Oj då! Det gick inte att skapa din enkät. Felet har loggats och vi försöker rätta till det.",
"exportToCsv": "Exportera till CSV",
"finish": "Slutför",
"forgetMe": "Glöm mig",
"goToAdmin": "Gå till Admin",
"guest": "Gäst",
"guestSessionNotice": "Du använder en gästsession. Detta gör att vi kan känna igen dig om du kommer tillbaka senare så att du kan redigera dina röster.",
"guestSessionReadMore": "Läs mer om gästsessioner.",
"hide": "Dölj",
"ifNeedBe": "Om det behövs",
"linkHasExpired": "Din länk har gått ut eller är inte längre giltig",
"loading": "Laddar…",
"loadingParticipants": "Laddar deltagare…",
"location": "Plats",
"locationPlaceholder": "Joe's Café",
"lockPoll": "Lås enkät",
"login": "Logga in",
"loginCheckInbox": "Vänligen kolla din inbox.",
"loginMagicLinkSent": "En magisk länk har skickats till:",
"loginSendMagicLink": "Skicka mig en magisk länk",
"loginViaMagicLink": "Logga in med magisk länk",
"loginViaMagicLinkDescription": "Vi kommer att skicka dig ett mail med en magisk länk som du kan använda för att logga in.",
"loginWithValidEmail": "Skriv in en giltig e-postadress",
"logout": "Logga ut",
"manage": "Hantera",
"menu": "Meny",
"mixedOptionsDescription": "Du kan inte ha både tids- och datumalternativ i samma omröstning. Vilka vill du behålla?",
"mixedOptionsKeepDates": "Behåll datumalternativ",
"mixedOptionsKeepTimes": "Behåll tidsalternativ",
"mixedOptionsTitle": "Vänta en sekund…🤔",
"monday": "Måndag",
"monthView": "Månadsvy",
"name": "Namn",
"namePlaceholder": "Olle Jonsson",
"newPoll": "Ny enkät",
"next": "Nästa",
"nextMonth": "Nästa månad",
"no": "Nej",
"noDatesSelected": "Inga datum valda",
"notificationsDisabled": "Aviseringar har inaktiverats",
"notificationsOff": "Aviseringar är av",
"notificationsOn": "Aviseringar är på",
"notificationsOnDescription": "Ett e-postmeddelande kommer att skickas till <b>{{email}}</b> när det finns aktivitet på denna enkät.",
"notificationsVerifyEmail": "Du måste verifiera din e-post för att aktivera aviseringar",
"ok": "Ok",
"options": "Alternativ",
"participant": "Deltagare",
"participantCount_other": "{{count}} deltagare",
"participantCount": "{{count}} deltagare",
"pollHasBeenLocked": "Denna enkät har låsts",
"pollHasBeenVerified": "Din enkät har blivit verifierad",
"pollOwnerNotice": "Hej {{name}}, ser ut som du är ägare av denna enkät.",
"pollsEmpty": "Inga enkäter skapade",
"possibleAnswers": "Möjliga svar",
"preferences": "Inställningar",
"previousMonth": "Föregående månad",
"profileLogin": "Profil - Inloggning",
"profileUser": "Profil - {{username}}",
"requiredNameError": "Namn är obligatoriskt",
"save": "Spara",
"saveInstruction": "Välj din tillgänglighet och klicka på <b>{{save}}</b>",
"share": "Dela",
"shareDescription": "Ge den här länken till dina <b>deltagare</b> så att de kan delta i din enkät.",
"shareLink": "Dela via länk",
"specifyTimes": "Ange tider",
"specifyTimesDescription": "Inkludera start- och sluttider för varje alternativ",
"stepSummary": "Steg {{current}} av {{total}}",
"sunday": "Söndag",
"timeAndDate": "Tid och datum",
"timeFormat": "Tidsformat:",
"timeZone": "Tidszon:",
"title": "Titel",
"titlePlaceholder": "Månatligt möte",
"today": "Idag",
"unlockPoll": "Lås upp enkät",
"unverifiedMessage": "Ett e-postmeddelande har skickats till <b>{{email}}</b> med en länk för att verifiera e-postadressen.",
"user": "Användare",
"vote": "Rösta",
"voteCount_other": "{{count}} röster",
"voteCount": "{{count}} röst",
"weekStartsOn": "Veckan börjar med",
"weekView": "Veckovy",
"whatsThis": "Vad är detta?",
"yes": "Ja",
"you": "Du",
"yourDetails": "Dina uppgifter",
"yourName": "Ditt namn…",
"yourPolls": "Dina enkäter"
}

View file

@ -0,0 +1,21 @@
{
"blog": "Blogg",
"discussions": "Diskussioner",
"donate": "Donera",
"english": "Engelska",
"footerCredit": "Gjort av <a>@imlukevella</a>",
"footerSponsor": "Detta projekt är användarfinansierat. Överväg att stödja det genom att göra en <a>donation</a>.",
"french": "Franska",
"german": "Tyska",
"home": "Hem",
"italian": "Italienska",
"language": "Språk",
"links": "Länkar",
"poweredBy": "Byggd på",
"privacyPolicy": "Integritetspolicy",
"spanish": "Spanska",
"starOnGithub": "Stjärnmarkera på GitHub",
"support": "Support",
"swedish": "Svenska",
"volunteerTranslator": "Hjälp till att översätta denna webbplats"
}

View file

@ -0,0 +1,36 @@
{
"3Ls": "Ja, med 3 <e>L</e>",
"adFree": "Reklamfritt",
"adFreeDescription": "Du kan låta din annonsblockerare vila - du behöver det inte här.",
"comments": "Kommentarer",
"commentsDescription": "Deltagarna kan kommentera din enkät och kommentarerna kommer att vara synliga för alla.",
"features": "Funktioner",
"featuresSubheading": "Schemaläggning, på det smarta sättet",
"follow": "Följ",
"getStarted": "Kom igång",
"heroSubText": "Hitta rätt datum utan allt fram och tillbaka",
"heroText": "Schemalägg<br/><s>gruppmöten</s><br />enkelt",
"links": "Länkar",
"liveDemo": "Live demo",
"metaDescription": "Skapa enkäter och rösta för att hitta den bästa dagen eller tiden. Ett gratis alternativ till Doodle.",
"metaTitle": "Rallly - Schemalägg gruppmöten",
"mobileFriendly": "Mobil vänlig",
"mobileFriendlyDescription": "Fungerar bra på mobila enheter så att deltagarna kan svara på enkäter var de än befinner sig.",
"new": "Ny",
"noLoginRequired": "Ingen inloggning krävs",
"noLoginRequiredDescription": "Du behöver inte logga in för att skapa eller delta i en enkät",
"notifications": "Aviseringar",
"notificationsDescription": "Håll koll på vem som har svarat. Få aviseringar när deltagarna röstar eller kommenterar på din enkät.",
"openSource": "Öppen källkod",
"openSourceDescription": "Kodebasen är helt öppen källkod och är <a>tillgänglig på GitHub</a>.",
"participant": "Deltagare",
"participantCount_other": "{{count}} deltagare",
"participantCount": "{{count}} deltagare",
"perfect": "Perfekt!",
"principles": "Principer",
"principlesSubheading": "Vi är inte som de andra",
"selfHostable": "Självhostbar",
"selfHostableDescription": "Kör det på din egen server för att ta full kontroll över din data",
"timeSlots": "Tidsluckor",
"timeSlotsDescription": "Ange individuella start- och sluttider för varje alternativ i din enkät. Tiderna kan justeras automatiskt till varje deltagares tidszon eller så kan de ställas in så att tidszoner ignoreras helt."
}

View file

@ -1,5 +1,4 @@
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router";
import { Trans, useTranslation } from "next-i18next"; import { Trans, useTranslation } from "next-i18next";
import * as React from "react"; import * as React from "react";
@ -16,7 +15,6 @@ import { LanguageSelect } from "../poll/language-selector";
const Footer: React.VoidFunctionComponent = () => { const Footer: React.VoidFunctionComponent = () => {
const { t } = useTranslation("common"); const { t } = useTranslation("common");
const router = useRouter();
return ( return (
<div className="mt-16 bg-slate-50/70"> <div className="mt-16 bg-slate-50/70">
<div className="mx-auto max-w-7xl space-y-8 p-8 lg:flex lg:space-x-16 lg:space-y-0"> <div className="mx-auto max-w-7xl space-y-8 p-8 lg:flex lg:space-x-16 lg:space-y-0">
@ -134,12 +132,7 @@ const Footer: React.VoidFunctionComponent = () => {
</div> </div>
<div className="lg:w-2/6"> <div className="lg:w-2/6">
<div className="mb-4 font-medium">{t("language")}</div> <div className="mb-4 font-medium">{t("language")}</div>
<LanguageSelect <LanguageSelect className="mb-4 w-full" />
className="mb-4 w-full"
onChange={(locale) => {
router.push(router.asPath, router.asPath, { locale });
}}
/>
<a <a
href="https://github.com/lukevella/rallly/wiki/Guide-for-translators" href="https://github.com/lukevella/rallly/wiki/Guide-for-translators"
className="inline-flex items-center rounded-md border px-3 py-2 text-xs text-slate-500" className="inline-flex items-center rounded-md border px-3 py-2 text-xs text-slate-500"

View file

@ -17,12 +17,14 @@ export const LanguageSelect: React.VoidFunctionComponent<{
Cookies.set("NEXT_LOCALE", e.target.value, { Cookies.set("NEXT_LOCALE", e.target.value, {
expires: 365, expires: 365,
}); });
router.push(router.asPath, router.asPath, { locale: e.target.value });
onChange?.(e.target.value); onChange?.(e.target.value);
}} }}
> >
<option value="en">{t("english")}</option> <option value="en">{t("english")}</option>
<option value="fr">{t("french")}</option> <option value="fr">{t("french")}</option>
<option value="de">{t("german")}</option> <option value="de">{t("german")}</option>
<option value="sv">{t("swedish")}</option>
</select> </select>
); );
}; };

View file

@ -1,5 +1,4 @@
import clsx from "clsx"; import clsx from "clsx";
import { useRouter } from "next/router";
import { useTranslation } from "next-i18next"; import { useTranslation } from "next-i18next";
import { usePlausible } from "next-plausible"; import { usePlausible } from "next-plausible";
import React from "react"; import React from "react";
@ -13,8 +12,6 @@ const Preferences: React.VoidFunctionComponent = () => {
const { weekStartsOn, setWeekStartsOn, timeFormat, setTimeFormat } = const { weekStartsOn, setWeekStartsOn, timeFormat, setTimeFormat } =
usePreferences(); usePreferences();
const router = useRouter();
const plausible = usePlausible(); const plausible = usePlausible();
return ( return (
<div> <div>
@ -22,7 +19,7 @@ const Preferences: React.VoidFunctionComponent = () => {
<div className="grow text-sm text-slate-500"> <div className="grow text-sm text-slate-500">
{t("common:language")} {t("common:language")}
</div> </div>
<LanguageSelect className="w-full" onChange={() => router.reload()} /> <LanguageSelect className="w-full" />
</div> </div>
<div className="grow space-y-2"> <div className="grow space-y-2">
<div> <div>

View file

@ -2,6 +2,7 @@ import dayjs from "dayjs";
import de from "dayjs/locale/de"; import de from "dayjs/locale/de";
import en from "dayjs/locale/en"; import en from "dayjs/locale/en";
import fr from "dayjs/locale/fr"; import fr from "dayjs/locale/fr";
import sv from "dayjs/locale/sv";
import duration from "dayjs/plugin/duration"; import duration from "dayjs/plugin/duration";
import isBetween from "dayjs/plugin/isBetween"; import isBetween from "dayjs/plugin/isBetween";
import isSameOrBefore from "dayjs/plugin/isSameOrBefore"; import isSameOrBefore from "dayjs/plugin/isSameOrBefore";
@ -22,6 +23,7 @@ const dayJsLocales = {
de, de,
en, en,
fr, fr,
sv,
}; };
dayjs.extend(localizedFormat); dayjs.extend(localizedFormat);

View file

@ -1,6 +1,6 @@
import { NextRequest, NextResponse } from "next/server"; import { NextRequest, NextResponse } from "next/server";
const supportedLocales = ["en", "de", "fr"]; const supportedLocales = ["en", "de", "fr", "sv"];
export function middleware({ headers, cookies, nextUrl }: NextRequest) { export function middleware({ headers, cookies, nextUrl }: NextRequest) {
const locale = const locale =