From bff2dd3a20d6926e10da126d0e5cb1732a88fcf4 Mon Sep 17 00:00:00 2001 From: Luke Vella Date: Sat, 1 Mar 2025 15:56:56 +0000 Subject: [PATCH] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Upgrade=20i18next=20(#1592?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/landing/declarations/i18next.d.ts | 16 +++++------ apps/landing/next-env.d.ts | 1 - apps/landing/package.json | 4 +-- .../[locale]/(seo)/availability-poll/page.tsx | 2 +- apps/landing/src/app/[locale]/page.tsx | 17 +++++++----- .../landing/src/app/[locale]/pricing/page.tsx | 4 +-- apps/landing/src/components/home/bonus.tsx | 2 +- apps/landing/src/i18n/server.ts | 9 ++++--- apps/landing/src/i18n/settings.ts | 4 +-- apps/web/package.json | 4 +-- .../remove-deleted-polls/route.ts | 22 +++------------ apps/web/src/i18n/settings.ts | 4 +-- packages/emails/src/i18n.ts | 3 --- packages/emails/src/types.ts | 2 +- yarn.lock | 27 ++++++++++++------- 15 files changed, 56 insertions(+), 65 deletions(-) diff --git a/apps/landing/declarations/i18next.d.ts b/apps/landing/declarations/i18next.d.ts index 0f61e7901..464477825 100644 --- a/apps/landing/declarations/i18next.d.ts +++ b/apps/landing/declarations/i18next.d.ts @@ -1,21 +1,19 @@ -import "react-i18next"; +import "i18next"; import type blog from "../public/locales/en/blog.json"; import type common from "../public/locales/en/common.json"; import type home from "../public/locales/en/home.json"; import type pricing from "../public/locales/en/pricing.json"; -interface I18nNamespaces { - common: typeof common; - home: typeof home; - pricing: typeof pricing; - blog: typeof blog; -} - declare module "i18next" { interface CustomTypeOptions { defaultNS: "common"; - resources: I18nNamespaces; + resources: { + common: typeof common; + home: typeof home; + pricing: typeof pricing; + blog: typeof blog; + }; returnNull: false; } } diff --git a/apps/landing/next-env.d.ts b/apps/landing/next-env.d.ts index 725dd6f24..40c3d6809 100644 --- a/apps/landing/next-env.d.ts +++ b/apps/landing/next-env.d.ts @@ -1,6 +1,5 @@ /// /// -/// // NOTE: This file should not be edited // see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information. diff --git a/apps/landing/package.json b/apps/landing/package.json index a883c0eaa..1e8a6744a 100644 --- a/apps/landing/package.json +++ b/apps/landing/package.json @@ -23,7 +23,7 @@ "accept-language-parser": "^1.5.0", "dayjs": "^1.11.10", "gray-matter": "^4.0.3", - "i18next": "^22.4.9", + "i18next": "^24.2.2", "i18next-icu": "^2.3.0", "intl-messageformat": "^10.3.4", "lodash": "^4.17.21", @@ -31,7 +31,7 @@ "next-i18next": "^13.0.3", "next-mdx-remote": "^5.0.0", "next-seo": "^6.1.0", - "react-i18next": "^12.1.4", + "react-i18next": "^15.4.1", "react-use": "^17.4.0" }, "devDependencies": { diff --git a/apps/landing/src/app/[locale]/(seo)/availability-poll/page.tsx b/apps/landing/src/app/[locale]/(seo)/availability-poll/page.tsx index ba6c781d4..967a9da6f 100644 --- a/apps/landing/src/app/[locale]/(seo)/availability-poll/page.tsx +++ b/apps/landing/src/app/[locale]/(seo)/availability-poll/page.tsx @@ -6,7 +6,7 @@ import { BigTestimonial, Marketing, MentionedBy } from "@/components/marketing"; import { getTranslation } from "@/i18n/server"; export default async function Page({ params }: { params: { locale: string } }) { - const { t } = await getTranslation(params.locale, ["common", "home"]); + const { t } = await getTranslation(params.locale, "home"); return ( @@ -30,10 +34,11 @@ export async function generateMetadata({ }) { const { t } = await getTranslation(params.locale, "home"); return { - title: t("home:metaTitle", { + title: t("metaTitle", { defaultValue: "Rallly: Group Scheduling Tool", + ns: "home", }), - description: t("home:metaDescription", { + description: t("metaDescription", { defaultValue: "Create polls and vote to find the best day or time. A free alternative to Doodle.", }), diff --git a/apps/landing/src/app/[locale]/pricing/page.tsx b/apps/landing/src/app/[locale]/pricing/page.tsx index 27f979acd..b02a0f051 100644 --- a/apps/landing/src/app/[locale]/pricing/page.tsx +++ b/apps/landing/src/app/[locale]/pricing/page.tsx @@ -8,7 +8,7 @@ import { linkToApp } from "@/lib/linkToApp"; import { PriceTables } from "./pricing-table"; -const FAQ = async ({ t }: { t: TFunction }) => { +const FAQ = async ({ t }: { t: TFunction<"pricing"> }) => { return (

@@ -123,7 +123,7 @@ const FAQ = async ({ t }: { t: TFunction }) => { }; export default async function Page({ params }: { params: { locale: string } }) { - const { t } = await getTranslation(params.locale, ["common", "pricing"]); + const { t } = await getTranslation(params.locale, "pricing"); return (
diff --git a/apps/landing/src/components/home/bonus.tsx b/apps/landing/src/components/home/bonus.tsx index d439cdc03..1e7712ccc 100644 --- a/apps/landing/src/components/home/bonus.tsx +++ b/apps/landing/src/components/home/bonus.tsx @@ -10,7 +10,7 @@ import { Trans } from "react-i18next/TransWithoutContext"; import { BonusItem } from "@/components/home/bonus-item"; -export async function Bonus({ t }: { t: TFunction }) { +export async function Bonus({ t }: { t: TFunction<"home" | "common"> }) { const userCount = await prisma.user.count(); return (
diff --git a/apps/landing/src/i18n/server.ts b/apps/landing/src/i18n/server.ts index 2f48c385f..5e7cd2977 100644 --- a/apps/landing/src/i18n/server.ts +++ b/apps/landing/src/i18n/server.ts @@ -21,13 +21,14 @@ const initI18next = async (lng: string, ns: Namespace) => { return i18nInstance; }; -export async function getTranslation( +export async function getTranslation( locale: string, - ns: Namespace = defaultNS, + ns?: Ns, ) { - const i18nextInstance = await initI18next(locale, ns); + const fixedNs = ns ?? defaultNS; + const i18nextInstance = await initI18next(locale, fixedNs); return { - t: i18nextInstance.getFixedT(locale, Array.isArray(ns) ? ns[0] : ns), + t: i18nextInstance.getFixedT(locale), i18n: i18nextInstance, }; } diff --git a/apps/landing/src/i18n/settings.ts b/apps/landing/src/i18n/settings.ts index 9b6213a62..b265a0372 100644 --- a/apps/landing/src/i18n/settings.ts +++ b/apps/landing/src/i18n/settings.ts @@ -1,5 +1,5 @@ import allLanguages from "@rallly/languages"; -import type { InitOptions } from "i18next"; +import type { InitOptions, Namespace } from "i18next"; export const fallbackLng = "en"; export const languages = Object.keys(allLanguages); @@ -7,7 +7,7 @@ export const defaultNS = "common"; export function getOptions( lng = fallbackLng, - ns: string | string[] = defaultNS, + ns: Namespace = defaultNS, ): InitOptions { return { // debug: true, diff --git a/apps/web/package.json b/apps/web/package.json index b943668c1..46e0e458c 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -54,7 +54,7 @@ "cookie": "^0.7.0", "crypto": "^1.0.1", "dayjs": "^1.11.10", - "i18next": "^22.4.9", + "i18next": "^24.2.2", "i18next-icu": "^2.3.0", "i18next-resources-to-backend": "^1.1.4", "ics": "^3.1.0", @@ -75,7 +75,7 @@ "react-big-calendar": "^1.8.1", "react-hook-form": "^7.42.1", "react-hook-form-persist": "^3.0.0", - "react-i18next": "^12.1.4", + "react-i18next": "^15.4.1", "react-remove-scroll": "^2.5.6", "react-use": "^17.4.0", "smoothscroll-polyfill": "^0.4.4", diff --git a/apps/web/src/app/api/house-keeping/remove-deleted-polls/route.ts b/apps/web/src/app/api/house-keeping/remove-deleted-polls/route.ts index c420883e6..26d44626a 100644 --- a/apps/web/src/app/api/house-keeping/remove-deleted-polls/route.ts +++ b/apps/web/src/app/api/house-keeping/remove-deleted-polls/route.ts @@ -6,41 +6,25 @@ import { checkApiAuthorization } from "@/utils/api-auth"; /** * Remove polls and corresponding data that have been marked deleted for more than 7 days. */ -export async function POST(req: Request) { +export async function POST() { const unauthorized = checkApiAuthorization(); if (unauthorized) return unauthorized; - const options = (await req.json()) as { take?: number } | undefined; - // First get the ids of all the polls that have been marked as deleted for at least 7 days - const deletedPolls = await prisma.poll.findMany({ - select: { - id: true, - }, + const deletedPolls = await prisma.poll.deleteMany({ where: { deleted: true, deletedAt: { lt: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), }, }, - take: options?.take ?? 1000, - }); - - const deletedPollIds = deletedPolls.map((poll) => poll.id); - - const { count: deletedPollCount } = await prisma.poll.deleteMany({ - where: { - id: { - in: deletedPollIds, - }, - }, }); return NextResponse.json({ success: true, summary: { deleted: { - polls: deletedPollCount, + polls: deletedPolls.count, }, }, }); diff --git a/apps/web/src/i18n/settings.ts b/apps/web/src/i18n/settings.ts index 66d91dbab..f18fe5164 100644 --- a/apps/web/src/i18n/settings.ts +++ b/apps/web/src/i18n/settings.ts @@ -1,5 +1,5 @@ import allLanguages from "@rallly/languages"; -import type { InitOptions } from "i18next"; +import type { InitOptions, Namespace } from "i18next"; export const fallbackLng = "en"; export const languages = Object.keys(allLanguages); @@ -7,7 +7,7 @@ export const defaultNS = "app"; export function getOptions( lng = fallbackLng, - ns: string | string[] = defaultNS, + ns: Namespace = defaultNS, ): InitOptions { return { supportedLngs: languages, diff --git a/packages/emails/src/i18n.ts b/packages/emails/src/i18n.ts index 9b7512eb6..59135b0db 100644 --- a/packages/emails/src/i18n.ts +++ b/packages/emails/src/i18n.ts @@ -20,9 +20,6 @@ const i18nDefaultConfig: InitOptions = { ns: ["emails"], fallbackNS: "emails", defaultNS: "emails", - interpolation: { - escapeValue: false, - }, } as const; export type I18nInstance = typeof i18nInstance; diff --git a/packages/emails/src/types.ts b/packages/emails/src/types.ts index f32429bb6..855b9470c 100644 --- a/packages/emails/src/types.ts +++ b/packages/emails/src/types.ts @@ -9,7 +9,7 @@ export type EmailContext = { domain: string; supportEmail: string; i18n: I18nInstance; - t: TFunction<"emails", undefined, "emails">; + t: TFunction; }; export type TemplateName = keyof EmailTemplates; diff --git a/yarn.lock b/yarn.lock index ea819cef7..0826b11ae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2271,6 +2271,13 @@ dependencies: regenerator-runtime "^0.14.0" +"@babel/runtime@^7.23.2", "@babel/runtime@^7.25.0": + version "7.26.9" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.9.tgz#aa4c6facc65b9cb3f87d75125ffd47781b475433" + integrity sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/runtime@^7.23.5": version "7.23.9" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.9.tgz#47791a15e4603bb5f905bc0753801cf21d6345f7" @@ -10011,12 +10018,12 @@ i18next@*: dependencies: "@babel/runtime" "^7.20.6" -i18next@^22.4.9: - version "22.4.10" - resolved "https://registry.npmjs.org/i18next/-/i18next-22.4.10.tgz" - integrity sha512-3EqgGK6fAJRjnGgfkNSStl4mYLCjUoJID338yVyLMj5APT67HUtWoqSayZewiiC5elzMUB1VEUwcmSCoeQcNEA== +i18next@^24.2.2: + version "24.2.2" + resolved "https://registry.yarnpkg.com/i18next/-/i18next-24.2.2.tgz#3ba3d213302068d569142737f03f30929de696de" + integrity sha512-NE6i86lBCKRYZa5TaUDkU5S4HFgLIEJRLr3Whf2psgaxBleQ2LC1YW1Vc+SCgkAW7VEzndT6al6+CzegSUHcTQ== dependencies: - "@babel/runtime" "^7.20.6" + "@babel/runtime" "^7.23.2" iconv-lite@0.4.24: version "0.4.24" @@ -12578,12 +12585,12 @@ react-hook-form@^7.42.1: resolved "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.43.2.tgz" integrity sha512-NvD3Oe2Y9hhqo2R4I4iJigDzSLpdMnzUpNMxlnzTbdiT7NT3BW0GxWCzEtwPudZMUPbZhNcSy1EcGAygyhDORg== -react-i18next@^12.1.4: - version "12.2.0" - resolved "https://registry.npmjs.org/react-i18next/-/react-i18next-12.2.0.tgz" - integrity sha512-5XeVgSygaGfyFmDd2WcXvINRw2WEC1XviW1LXY/xLOEMzsCFRwKqfnHN+hUjla8ZipbVJR27GCMSuTr0BhBBBQ== +react-i18next@^15.4.1: + version "15.4.1" + resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-15.4.1.tgz#33f3e89c2f6c68e2bfcbf9aa59986ad42fe78758" + integrity sha512-ahGab+IaSgZmNPYXdV1n+OYky95TGpFwnKRflX/16dY04DsYYKHtVLjeny7sBSCREEcoMbAgSkFiGLF5g5Oofw== dependencies: - "@babel/runtime" "^7.20.6" + "@babel/runtime" "^7.25.0" html-parse-stringify "^3.0.1" react-is@^16.13.1, react-is@^16.7.0: