diff --git a/src/api/index.ts b/src/api/index.ts index c502355..f6ffa84 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -3,4 +3,5 @@ export * from "./contact"; export * from "./gallery"; export * from "./home"; export * from "./menu"; +export * from "./settings"; diff --git a/src/api/settings.ts b/src/api/settings.ts new file mode 100644 index 0000000..e7ebf8e --- /dev/null +++ b/src/api/settings.ts @@ -0,0 +1,7 @@ +import type { Options } from "node_modules/payload/dist/globals/operations/local/findOne"; +import { getPayload } from "@/utils/payload"; + +export const getSettings = async (opts: Omit, "slug"> = {}) => { + const payload = await getPayload(); + return await payload.findGlobal({ slug: "settings", ...opts }); +}; diff --git a/src/app/(frontend)/[locale]/layout.tsx b/src/app/(frontend)/[locale]/layout.tsx index 93c2f48..9706faf 100644 --- a/src/app/(frontend)/[locale]/layout.tsx +++ b/src/app/(frontend)/[locale]/layout.tsx @@ -1,5 +1,7 @@ import "../../globals.css"; +import { Locale, locales } from "@/i18n/settings"; + import Footer from "@/components/layout/footer"; import { I18nProviderClient } from "@/i18n/client"; import { Metadata } from "next"; @@ -7,7 +9,6 @@ import Navbar from "@/components/layout/navbar"; import { Params } from "./shared"; import { getAbout } from "@/api"; import localFont from "next/font/local"; -import { locales } from "@/i18n/settings"; import { styled } from "@styled-system/jsx"; const moderustic = localFont({ @@ -37,8 +38,10 @@ export default async function RootLayout({ ); } -export async function generateStaticParams() { - return locales.map((locale) => ({ locale })); +export async function generateStaticParams(): Promise<{ locale: Locale }[]> { + return locales.map(({ code }) => ({ + locale: code, + })); } export async function generateMetadata(): Promise { diff --git a/src/components/layout/language-picker.tsx b/src/components/layout/language-picker.tsx index 75c01ed..3ab64be 100644 --- a/src/components/layout/language-picker.tsx +++ b/src/components/layout/language-picker.tsx @@ -1,10 +1,10 @@ "use client"; +import { defaultLocale, locales } from "@/i18n/settings"; import { useChangeLocale, useCurrentLocale, useI18n } from "@/i18n/client"; import { Button } from "@/components/ui/button"; import { Menu } from "@/components/ui/menu"; -import { locales } from "@/i18n/settings"; export default function LanguagePicker(props: Menu.RootProps) { const changeLocale = useChangeLocale(); @@ -22,8 +22,13 @@ export default function LanguagePicker(props: Menu.RootProps) { {locales.map((locale) => ( - changeLocale(locale)}> - + changeLocale(locale.code)} + > + ))} diff --git a/src/globals/Settings.ts b/src/globals/Settings.ts new file mode 100644 index 0000000..71559a7 --- /dev/null +++ b/src/globals/Settings.ts @@ -0,0 +1,22 @@ +import { defaultLocale, locales } from "@/i18n/settings"; + +import type { GlobalConfig } from "payload"; + +export const Settings: GlobalConfig = { + slug: "settings", + access: {}, + fields: [ + { + name: "adminLanguage", + type: "select", + options: locales.map((l) => ({ + value: l.code, + label: l.label[l.code] ?? l.label[defaultLocale], + })), + }, + { + name: "contactEmailsTo", + type: "email", + }, + ], +}; diff --git a/src/i18n/client.ts b/src/i18n/client.ts index a3fb9c4..cdd89f7 100644 --- a/src/i18n/client.ts +++ b/src/i18n/client.ts @@ -1,9 +1,7 @@ "use client"; import { createI18nClient } from "next-international/client"; +import { importedLocales } from "./settings"; export const { useI18n, useScopedI18n, I18nProviderClient, useChangeLocale, useCurrentLocale } = - createI18nClient({ - de: () => import("./de"), - en: () => import("./en"), - }); + createI18nClient(importedLocales); diff --git a/src/i18n/de.ts b/src/i18n/de.ts index 8325b8a..d386872 100644 --- a/src/i18n/de.ts +++ b/src/i18n/de.ts @@ -38,4 +38,11 @@ export default { reservation: { guests: "Gäste", }, + email: { + contactConfirmationSubject: "Vielen Dank für Ihre Kontaktanfrage", + contactConfirmationText: + "Wir haben Ihre Kontaktanfrage erhalten und melden uns innerhalb kurzer Zeit bei Ihnen.", + contactSubject: "Kontaktanfrage von {name}", + contactTitle: "Sie haben eine Kontaktanfrage von {name} erhalten:", + }, } as const; diff --git a/src/i18n/server.ts b/src/i18n/server.ts index e2339dc..f01f1ae 100644 --- a/src/i18n/server.ts +++ b/src/i18n/server.ts @@ -1,6 +1,5 @@ import { createI18nServer } from "next-international/server"; +import { importedLocales } from "./settings"; -export const { getI18n, getScopedI18n, getStaticParams } = createI18nServer({ - de: () => import("./de"), - en: () => import("./en"), -}); +export const { getI18n, getScopedI18n, getStaticParams, getCurrentLocale } = + createI18nServer(importedLocales); diff --git a/src/i18n/settings.ts b/src/i18n/settings.ts index 007b49c..1479dc8 100644 --- a/src/i18n/settings.ts +++ b/src/i18n/settings.ts @@ -1,4 +1,49 @@ -export const defaultLocale = "de" as const; -export const locales = [defaultLocale, "en"] as const; +export const locales = [ + { + label: { + de: "Deutsch", + en: "German", + fr: "Allemand", + it: "Tedesco", + }, + code: "de", + }, + { + label: { + fr: "Français", + en: "French", + de: "Französisch", + it: "Francese", + }, + code: "fr", + }, + { + label: { + it: "Italiano", + de: "Italienisch", + en: "Italian", + fr: "Italien", + }, + code: "it", + }, + { + label: { + de: "Englisch", + en: "English", + it: "Inglese", + fr: "Anglais", + }, + code: "en", + }, +] as const; -export type Locale = (typeof locales)[number]; +export type Locale = (typeof locales)[number]["code"]; + +export const defaultLocale: Locale = "de"; + +export const importedLocales = { + de: () => import("./de"), + en: () => import("./en"), + it: () => import("./it"), + fr: () => import("./fr"), +} as const; diff --git a/src/middleware.ts b/src/middleware.ts index bb6a94d..250c537 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -4,7 +4,7 @@ import { NextRequest } from "next/server"; import { createI18nMiddleware } from "next-international/middleware"; const I18nMiddleware = createI18nMiddleware({ - locales, + locales: locales.map(({ code }) => code), defaultLocale, urlMappingStrategy: "rewriteDefault", }); diff --git a/src/payload-types.ts b/src/payload-types.ts index 9d52665..683ab27 100644 --- a/src/payload-types.ts +++ b/src/payload-types.ts @@ -32,6 +32,7 @@ export interface Config { about: About; contact: Contact; menu: Menu; + settings: Setting; }; locale: 'de' | 'fr' | 'it' | 'en'; user: User & { @@ -359,6 +360,17 @@ export interface Menu { updatedAt?: string | null; createdAt?: string | null; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "settings". + */ +export interface Setting { + id: string; + adminLanguage?: ('de' | 'fr' | 'it' | 'en') | null; + contactEmailsTo?: string | null; + updatedAt?: string | null; + createdAt?: string | null; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "auth". diff --git a/src/payload.config.ts b/src/payload.config.ts index cb19d1e..a426836 100644 --- a/src/payload.config.ts +++ b/src/payload.config.ts @@ -1,20 +1,22 @@ import { DefaultTranslationsObject, Language } from "@payloadcms/translations"; +import { Locale, buildConfig } from "payload"; +import { defaultLocale, locales } from "@/i18n/settings"; -import { About } from "./globals/About"; -import { Contact } from "./globals/Contact"; -import { FoodDeclaration } from "./collections/FoodDeclaration"; +import { About } from "@/globals/About"; +import { Contact } from "@/globals/Contact"; +import { FoodDeclaration } from "@/collections/FoodDeclaration"; import { Gallery } from "@/globals/Gallery"; -import { Holiday } from "./collections/Holiday"; -import { Home } from "./globals/Home"; -import { Media } from "./collections/Media"; -import { Menu } from "./globals/Menu"; -import { MenuCategory } from "./collections/MenuCategory"; -import { MenuItem } from "./collections/MenuItem"; -import { MenuItemTag } from "./collections/MenuItemTag"; -import { OpeningTime } from "./collections/OpeningTime"; -import { Users } from "./collections/Users"; -import { Vacation } from "./collections/Vacation"; -import { buildConfig } from "payload"; +import { Holiday } from "@/collections/Holiday"; +import { Home } from "@/globals/Home"; +import { Media } from "@/collections/Media"; +import { Menu } from "@/globals/Menu"; +import { MenuCategory } from "@/collections/MenuCategory"; +import { MenuItem } from "@/collections/MenuItem"; +import { MenuItemTag } from "@/collections/MenuItemTag"; +import { OpeningTime } from "@/collections/OpeningTime"; +import { Settings } from "@/globals/Settings"; +import { Users } from "@/collections/Users"; +import { Vacation } from "@/collections/Vacation"; import { de } from "@payloadcms/translations/languages/de"; import { en } from "@payloadcms/translations/languages/en"; import { fileURLToPath } from "url"; @@ -47,7 +49,7 @@ export default buildConfig({ Vacation, Holiday, ], - globals: [Home, Gallery, About, Contact, Menu], + globals: [Home, Gallery, About, Contact, Menu, Settings], editor: lexicalEditor(), secret: process.env.PAYLOAD_SECRET || "", typescript: { @@ -70,39 +72,8 @@ export default buildConfig({ }, }, localization: { - locales: [ - { - label: { - de: "Deutsch", - en: "German", - }, - code: "de", - }, - { - label: { - fr: "Français", - en: "French", - de: "Französisch", - }, - code: "fr", - }, - { - label: { - it: "Italiano", - de: "Italienisch", - en: "Italian", - }, - code: "it", - }, - { - label: { - de: "Englisch", - en: "English", - }, - code: "en", - }, - ], - defaultLocale: "de", + locales: locales as unknown as Locale[], + defaultLocale, fallback: true, }, });