Add translations

This commit is contained in:
Ondřej 2024-02-06 23:03:26 +01:00
parent 5792decc8f
commit a8903e7279
10 changed files with 102 additions and 12 deletions

View file

@ -1,3 +1,65 @@
export function t(key: string) { import { DEFAULT_LANG } from "./config";
return key; import type { Lang } from "./lang";
type AnyString = string & {};
// Reference
const en = {
website_name: "Let's stop dirty money",
website_description: undefined,
switch_country: "Switch country",
"form.first_name": "First name",
"form.last_name": "Last name",
"form.variant": "I'm most concerned that",
"form.variant.1": "EPH destroys global climate",
"form.variant.2": "EPH fuels energy crisis",
"form.variant.3": "EPH undermines democracy",
"form.gender": undefined,
"form.gender.f": undefined,
"form.gender.m": undefined,
"form.branch": "I'm client of",
"form.letter": "Letter body",
"form.email": "E-mail",
"form.phone": "Phone number",
"form.send": "Send",
"confirm_email.title": "Confirm your e-mail",
"confirm_email.body": "Click the link below to verify your e-mail address.",
"confirm_email.link": "Confirm",
} as const;
type TranslationKey = keyof typeof en;
type Translation = Partial<Record<TranslationKey | AnyString, string | undefined>>;
const cs: Translation = {
website_name: "Zastavme špinavé prachy",
switch_country: "Změnit zemi",
"form.first_name": "Jméno",
"form.last_name": "Příjmení",
"form.variant": "Nejvíc mi vadí, že",
"form.variant.1": "EPH ničí klima",
"form.variant.2": "EPH způsobuje energetickou krizi",
"form.variant.3": "EPH ohrožuje demokracii",
"form.gender": "Preferuju být oslován/a v",
"form.gender.f": "ženském rodě",
"form.gender.m": "mužském rodě",
"form.branch": "Jsem klient/ka pobočky",
"form.letter": "Text dopisu",
"form.email": "E-mail",
"form.phone": "Telefonní číslo",
"form.send": "Odeslat",
"confirm_email.title": "Potvrď svůj e-mail",
"confirm_email.body": "Kliknutím na následující odkaz potvrdíš svou e-mailovou adresu.",
"confirm_email.link": "Potvrdit e-mail",
};
const de: Translation = {};
const translations: Record<Lang, Translation> = { en, cs, de };
export type TranslateFn = (key: TranslationKey | AnyString) => string;
export function makeT(lang: Lang = DEFAULT_LANG): TranslateFn {
return function t(key) {
return translations[lang]?.[key] ?? key;
};
} }

View file

@ -2,6 +2,6 @@ import { LANGUAGES } from "./config.ts";
export type Lang = (typeof LANGUAGES)[number]; export type Lang = (typeof LANGUAGES)[number];
export function isLang(str: string): str is Lang { export function isLang(str: string | undefined): str is Lang {
return (LANGUAGES as ReadonlyArray<string>).includes(str); return !!str && (LANGUAGES as ReadonlyArray<string>).includes(str);
} }

View file

@ -1,5 +1,14 @@
--- ---
import { t } from "../i18n"; import { DEFAULT_LANG } from "../config";
import { makeT } from "../i18n";
import type { Lang } from "../lang";
interface Props {
lang?: Lang;
}
const { lang = DEFAULT_LANG } = Astro.props;
const t = makeT(lang);
--- ---
<html> <html>

View file

@ -1,5 +1,5 @@
--- ---
import { t } from "../i18n"; import { makeT } from "../i18n";
import Button from "../ui/Button.astro"; import Button from "../ui/Button.astro";
import Dialog from "../ui/Dialog.astro"; import Dialog from "../ui/Dialog.astro";
import Checkbox from "../ui/Checkbox.astro"; import Checkbox from "../ui/Checkbox.astro";
@ -14,6 +14,7 @@ interface Props {
} }
const { lang, options = {} } = Astro.props; const { lang, options = {} } = Astro.props;
const t = makeT(lang);
const result = letterOptionsSchema.safeParse(options); const result = letterOptionsSchema.safeParse(options);
--- ---

View file

@ -2,7 +2,7 @@
import Field from "../ui/Field.astro"; import Field from "../ui/Field.astro";
import Radio from "../ui/Radio.astro"; import Radio from "../ui/Radio.astro";
import RadioGroup from "../ui/RadioGroup.astro"; import RadioGroup from "../ui/RadioGroup.astro";
import { t } from "../i18n"; import { makeT } from "../i18n";
import Label from "../ui/Label.astro"; import Label from "../ui/Label.astro";
import Select from "../ui/Select.astro"; import Select from "../ui/Select.astro";
import type { Lang } from "../lang"; import type { Lang } from "../lang";
@ -12,6 +12,7 @@ interface Props {
} }
const { lang } = Astro.props; const { lang } = Astro.props;
const t = makeT(lang);
interface Branch { interface Branch {
id: number; id: number;

View file

@ -27,7 +27,7 @@ const responseSchema = z.object({
data: z.record(z.any()), data: z.record(z.any()),
}); });
function convertObjectKeys<T>( function convertObjectKeys(
obj: Record<string, any>, obj: Record<string, any>,
fn: (key: string) => string fn: (key: string) => string
): Record<string, any> { ): Record<string, any> {

View file

@ -1,12 +1,14 @@
import html from "html-template-tag"; import html from "html-template-tag";
import { t } from "../i18n"; import { makeT } from "../i18n";
import type { Lang } from "../lang";
interface Params { interface Params {
lang: string; lang: Lang;
href: string; href: string;
} }
export default function renderMail({ lang, href }: Params) { export default function renderMail({ lang, href }: Params) {
const t = makeT(lang);
const htmlBody = html`<!DOCTYPE html> const htmlBody = html`<!DOCTYPE html>
<html lang="${lang}"> <html lang="${lang}">
<head> <head>

14
src/middleware.ts Normal file
View file

@ -0,0 +1,14 @@
import type { MiddlewareHandler } from "astro";
import { isLang } from "./lang";
export const onRequest: MiddlewareHandler = ({ params }, next) => {
// Return 404 on unknown languages
// On statically generated routes, this behavior is automatically handled by getStaticPaths.
if (params.lang && !isLang(params.lang)) {
return new Response(null, {
status: 404,
statusText: "Not found",
});
}
return next();
};

View file

@ -1,5 +1,5 @@
--- ---
import { t } from "../../i18n"; import { makeT } from "../../i18n";
import Layout from "../../layouts/Layout.astro"; import Layout from "../../layouts/Layout.astro";
import LetterBodyForm from "../../letter/LetterBodyForm.astro"; import LetterBodyForm from "../../letter/LetterBodyForm.astro";
import LetterOptionsForm from "../../letter/LetterOptionsForm.astro"; import LetterOptionsForm from "../../letter/LetterOptionsForm.astro";
@ -7,6 +7,7 @@ import LetterOptionsForm from "../../letter/LetterOptionsForm.astro";
export { getStaticPaths } from "../../static-paths"; export { getStaticPaths } from "../../static-paths";
const { lang } = Astro.params; const { lang } = Astro.params;
const t = makeT(lang);
--- ---
<Layout> <Layout>

View file

@ -12,7 +12,7 @@ export async function GET({ params: { lang } }: APIContext<never, Params>) {
const { plainBody } = renderMail({ lang, href: "" }); const { plainBody } = renderMail({ lang, href: "" });
return new Response(plainBody, { return new Response(plainBody, {
headers: { headers: {
"Content-Type": "text/plain", "Content-Type": "text/plain;charset=utf-8",
}, },
}); });
} }