intl package without routing

This commit is contained in:
peintnermax
2024-10-09 09:56:45 +02:00
parent 374601c200
commit f2262666fb
38 changed files with 143 additions and 210 deletions

View File

@@ -1,7 +0,0 @@
const i18nConfig = {
locales: ["en", "de", "it"],
defaultLocale: "en",
prefixDefault: false,
};
export default i18nConfig;

View File

@@ -0,0 +1,6 @@
{
"loginname": {
"title": "Willkommen zurück!",
"description": "Geben Sie Ihre Anmeldedaten ein."
}
}

View File

@@ -1,4 +0,0 @@
{
"title": "Willkommen zurück!",
"description": "Geben Sie Ihre Anmeldedaten ein."
}

View File

@@ -0,0 +1,6 @@
{
"loginname": {
"title": "Welcome back!",
"description": "Enter your login data."
}
}

View File

@@ -1,4 +0,0 @@
{
"title": "Welcome back!",
"description": "Enter your login data."
}

View File

@@ -1,4 +0,0 @@
{
"title": "Welcome back!",
"description": "Enter your login data."
}

View File

@@ -1,3 +1,7 @@
import createNextIntlPlugin from "next-intl/plugin";
const withNextIntl = createNextIntlPlugin();
/** @type {import('next').NextConfig} */
const secureHeaders = [
@@ -59,4 +63,4 @@ const nextConfig = {
},
};
export default nextConfig;
export default withNextIntl(nextConfig);

View File

@@ -42,18 +42,15 @@
"@zitadel/proto": "workspace:*",
"clsx": "1.2.1",
"copy-to-clipboard": "^3.3.3",
"i18next": "^23.15.2",
"i18next-resources-to-backend": "^1.2.1",
"moment": "^2.29.4",
"next": "14.2.14",
"next-i18n-router": "^5.5.1",
"next-intl": "^3.20.0",
"next-themes": "^0.2.1",
"nice-grpc": "2.0.1",
"qrcode.react": "^3.1.0",
"react": "^18.3.1",
"react-dom": "18.3.1",
"react-hook-form": "7.39.5",
"react-i18next": "^15.0.2",
"swr": "^2.2.0",
"tinycolor2": "1.4.2"
},

View File

@@ -1,41 +0,0 @@
import i18nConfig from "i18nConfig";
import { createInstance } from "i18next";
import resourcesToBackend from "i18next-resources-to-backend";
import { initReactI18next } from "react-i18next/initReactI18next";
export default async function initTranslations(
locale,
namespaces,
i18nInstance,
resources,
) {
i18nInstance = i18nInstance || createInstance();
i18nInstance.use(initReactI18next);
if (!resources) {
i18nInstance.use(
resourcesToBackend(
(language, namespace) =>
import(`/locales/${language}/${namespace}.json`),
),
);
}
await i18nInstance.init({
lng: locale,
resources,
fallbackLng: i18nConfig.defaultLocale,
supportedLngs: i18nConfig.locales,
defaultNS: namespaces[0],
fallbackNS: namespaces[0],
ns: namespaces,
preload: resources ? [] : i18nConfig.locales,
});
return {
i18n: i18nInstance,
resources: i18nInstance.services.resourceStore.data,
t: i18nInstance.t,
};
}

View File

@@ -2,16 +2,13 @@ import "@/styles/globals.scss";
import { AddressBar } from "@/components/address-bar";
import { GlobalNav } from "@/components/global-nav";
import { LanguageSwitcher } from "@/components/language-switcher";
import { Theme } from "@/components/theme";
import { ThemeProvider } from "@/components/theme-provider";
import { TranslationsProvider } from "@/components/translations-provider";
import { Analytics } from "@vercel/analytics/react";
import i18nConfig from "i18nConfig";
import { dir } from "i18next";
import { NextIntlClientProvider } from "next-intl";
import { getLocale, getMessages } from "next-intl/server";
import { Lato } from "next/font/google";
import { ReactNode } from "react";
import initTranslations from "../i18n";
const lato = Lato({
weight: ["400", "700", "900"],
@@ -20,19 +17,13 @@ const lato = Lato({
export const revalidate = 60; // revalidate every minute
export function generateStaticParams() {
return i18nConfig.locales.map((locale) => ({ locale }));
}
export default async function RootLayout({
children,
params: { locale, hl },
}: {
children: ReactNode;
params: { locale: string; hl: string };
}) {
const i18nNamespaces = ["loginname"];
const { t, resources } = await initTranslations(locale, i18nNamespaces);
const locale = await getLocale();
const messages = await getMessages();
// later only shown with dev mode enabled
const showNav = process.env.DEBUG === "true";
@@ -43,18 +34,13 @@ export default async function RootLayout({
return (
<html
lang={locale}
dir={dir(locale)}
className={`${lato.className}`}
suppressHydrationWarning
>
<head />
<body>
<ThemeProvider>
<TranslationsProvider
namespaces={i18nNamespaces}
locale={locale}
resources={resources}
>
<NextIntlClientProvider messages={messages}>
<div
className={`h-screen overflow-y-scroll bg-background-light-600 dark:bg-background-dark-600 ${
showNav
@@ -66,7 +52,7 @@ export default async function RootLayout({
<GlobalNav />
) : (
<div className="absolute bottom-0 right-0 flex flex-row p-4 items-center space-x-4">
<LanguageSwitcher locale={locale} />
{/*<LanguageSwitcher locale={locale} /> */}
<Theme />
</div>
)}
@@ -91,7 +77,7 @@ export default async function RootLayout({
</div>
<Analytics />
</TranslationsProvider>
</NextIntlClientProvider>
</ThemeProvider>
</body>
</html>

View File

@@ -1,4 +1,3 @@
import initTranslations from "@/app/i18n";
import { DynamicTheme } from "@/components/dynamic-theme";
import { SignInWithIdp } from "@/components/sign-in-with-idp";
import { UsernameForm } from "@/components/username-form";
@@ -9,6 +8,7 @@ import {
settingsService,
} from "@/lib/zitadel";
import { makeReqCtx } from "@zitadel/client/v2";
import { getLocale, getTranslations } from "next-intl/server";
function getIdentityProviders(orgId?: string) {
return settingsService
@@ -20,12 +20,12 @@ function getIdentityProviders(orgId?: string) {
export default async function Page({
searchParams,
params: { locale },
}: {
searchParams: Record<string | number | symbol, string | undefined>;
params: { locale: string };
}) {
const { t } = await initTranslations(locale, ["loginname"]);
// const t = useTranslations("loginname");
const locale = getLocale();
const t = await getTranslations({ locale, namespace: "loginname" });
const loginName = searchParams?.loginName;
const authRequestId = searchParams?.authRequestId;

View File

@@ -1,5 +1,6 @@
"use client";
import { setLanguageCookie } from "@/lib/cookies";
import {
Listbox,
ListboxButton,
@@ -8,10 +9,9 @@ import {
Transition,
} from "@headlessui/react";
import { CheckIcon, ChevronUpDownIcon } from "@heroicons/react/24/outline";
import { useTranslations } from "next-intl";
import { usePathname, useRouter } from "next/navigation";
import { Fragment, useState } from "react";
import { useTranslation } from "react-i18next";
import i18nConfig from "../../i18nConfig";
interface Lang {
id: number;
@@ -46,9 +46,9 @@ type Props = {
};
export function LanguageSwitcher({ locale }: Props) {
const { i18n } = useTranslation();
const { i18n } = useTranslations();
const currentLocale = locale || i18n.language || i18nConfig.defaultLocale;
const currentLocale = locale || i18n.language || "en";
const [selected, setSelected] = useState(
LANGS.find((l) => l.code === currentLocale) || LANGS[0],
@@ -57,27 +57,27 @@ export function LanguageSwitcher({ locale }: Props) {
const router = useRouter();
const currentPathname = usePathname();
const handleChange = (language: Lang) => {
const handleChange = async (language: Lang) => {
setSelected(language);
const newLocale = language.code;
// set cookie for next-i18n-router
const days = 30;
const date = new Date();
date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
const expires = date.toUTCString();
document.cookie = `NEXT_LOCALE=${newLocale};expires=${expires};path=/`;
// set cookie
// const days = 30;
// const date = new Date();
// date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
// const expires = date.toUTCString();
// document.cookie = `NEXT_LOCALE=${newLocale};expires=${expires};path=/`;
// redirect to the new locale path
if (
currentLocale === i18nConfig.defaultLocale &&
!i18nConfig.prefixDefault
) {
router.push("/" + newLocale + currentPathname);
} else {
router.push(
currentPathname.replace(`/${currentLocale}`, `/${newLocale}`),
);
}
// if (currentLocale === "en" /*i18nConfig.defaultLocale*/) {
// router.push("/" + newLocale + currentPathname);
// } else {
// router.push(
// currentPathname.replace(`/${currentLocale}`, `/${newLocale}`),
// );
// }
await setLanguageCookie(newLocale);
router.refresh();
};

View File

@@ -1,26 +0,0 @@
"use client";
import { createInstance } from "i18next";
import React from "react";
import { I18nextProvider } from "react-i18next";
import initTranslations from "../app/i18n";
type Props = {
locale: string;
children: React.ReactNode;
namespaces: string[];
resources: Record<string, Record<string, string>>;
};
export function TranslationsProvider({
children,
locale,
namespaces,
resources,
}: Props) {
const i18n = createInstance();
initTranslations(locale, namespaces, i18n, resources);
return <I18nextProvider i18n={i18n}>{children}</I18nextProvider>;
}

View File

@@ -0,0 +1,15 @@
import { getRequestConfig } from "next-intl/server";
import { cookies } from "next/headers";
export default getRequestConfig(async () => {
// Provide a static locale, fetch a user setting,
// read from `cookies()`, `headers()`, etc.
const cookiesList = cookies();
const locale = cookiesList.get("NEXT_LOCALE")?.value ?? "en";
return {
locale,
messages: (await import(`../../locales/${locale}.json`)).default,
};
});

View File

@@ -17,7 +17,7 @@ type SessionCookie<T> = Cookie & T;
function setSessionHttpOnlyCookie<T>(sessions: SessionCookie<T>[]) {
const cookiesList = cookies();
// @ts-ignore
return cookiesList.set({
name: "sessions",
value: JSON.stringify(sessions),
@@ -26,6 +26,17 @@ function setSessionHttpOnlyCookie<T>(sessions: SessionCookie<T>[]) {
});
}
export async function setLanguageCookie(language: string) {
const cookiesList = cookies();
// @ts-ignore
return cookiesList.set({
name: "NEXT_LOCALE",
value: JSON.stringify(language),
httpOnly: true,
path: "/",
});
}
export async function addSessionToCookie<T>(
session: SessionCookie<T>,
cleanup: boolean = false,

View File

@@ -1,15 +1,9 @@
import { i18nRouter } from "next-i18n-router";
import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";
import i18nConfig from "../i18nConfig";
const INSTANCE = process.env.ZITADEL_API_URL;
const SERVICE_USER_ID = process.env.ZITADEL_SERVICE_USER_ID as string;
export const config = {
matcher: "/((?!api|static|.*\\..*|_next).*)",
};
export function middleware(request: NextRequest) {
// OIDC specific routes
if (
@@ -44,6 +38,4 @@ export function middleware(request: NextRequest) {
headers: responseHeaders,
});
}
return i18nRouter(request, i18nConfig);
}

130
pnpm-lock.yaml generated
View File

@@ -77,21 +77,15 @@ importers:
copy-to-clipboard:
specifier: ^3.3.3
version: 3.3.3
i18next:
specifier: ^23.15.2
version: 23.15.2
i18next-resources-to-backend:
specifier: ^1.2.1
version: 1.2.1
moment:
specifier: ^2.29.4
version: 2.30.1
next:
specifier: 14.2.14
version: 14.2.14(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1)
next-i18n-router:
specifier: ^5.5.1
version: 5.5.1
next-intl:
specifier: ^3.20.0
version: 3.20.0(next@14.2.14(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1))(react@18.3.1)
next-themes:
specifier: ^0.2.1
version: 0.2.1(next@14.2.14(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -110,9 +104,6 @@ importers:
react-hook-form:
specifier: 7.39.5
version: 7.39.5(react@18.3.1)
react-i18next:
specifier: ^15.0.2
version: 15.0.2(i18next@23.15.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
swr:
specifier: ^2.2.0
version: 2.2.5(react@18.3.1)
@@ -872,6 +863,18 @@ packages:
'@floating-ui/utils@0.2.8':
resolution: {integrity: sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==}
'@formatjs/ecma402-abstract@2.1.0':
resolution: {integrity: sha512-SE2V2PE03K9U/YQZ3nxEOysRkQ/CfSwLHR789Uk9N0PTiWT6I+17UTDI97zYEwC1mbnjefqmtjbL8nunjPwGjw==}
'@formatjs/fast-memoize@2.2.0':
resolution: {integrity: sha512-hnk/nY8FyrL5YxwP9e4r9dqeM6cAbo8PeU9UjyXojZMNvVad2Z06FAVHyR3Ecw6fza+0GH7vdJgiKIVXTMbSBA==}
'@formatjs/icu-messageformat-parser@2.7.9':
resolution: {integrity: sha512-9Z5buDRMsTbplXknvRlDmnpWhZrayNVcVvkH0+SSz8Ll4XD/7Tcn8m1IjxM3iBJSwQbxwxb7/g0Fkx3d4j2osw==}
'@formatjs/icu-skeleton-parser@1.8.3':
resolution: {integrity: sha512-TsKAP013ayZFbWWR2KWy+f9QVZh0yDFTPK3yE4OqU2gnzafvmKTodRtJLVpfZmpXWJ5y7BWD1AsyT14mcbLzig==}
'@formatjs/intl-localematcher@0.5.4':
resolution: {integrity: sha512-zTwEpWOzZ2CiKcB93BLngUX59hQkuZjT2+SAQEscSm52peDW/getsawMcWF1rGRpMCX6D7nSJA3CzJ8gn13N/g==}
@@ -2563,9 +2566,6 @@ packages:
resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==}
engines: {node: '>=18'}
html-parse-stringify@3.0.1:
resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==}
http-proxy-agent@7.0.2:
resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
engines: {node: '>= 14'}
@@ -2597,12 +2597,6 @@ packages:
resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
engines: {node: '>=16.17.0'}
i18next-resources-to-backend@1.2.1:
resolution: {integrity: sha512-okHbVA+HZ7n1/76MsfhPqDou0fptl2dAlhRDu2ideXloRRduzHsqDOznJBef+R3DFZnbvWoBW+KxJ7fnFjd6Yw==}
i18next@23.15.2:
resolution: {integrity: sha512-zcPSWzCvw6uKnuYHIqs4W7hTuB9e3AFcSdZgvCWoPXIZsBjBd4djN2/2uOHIB+1DFFkQnMBXvhNg7J3WyCuywQ==}
iconv-lite@0.4.24:
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
engines: {node: '>=0.10.0'}
@@ -2655,6 +2649,9 @@ packages:
resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==}
engines: {node: '>= 0.4'}
intl-messageformat@10.6.0:
resolution: {integrity: sha512-AYKl/DY1nl75pJU8EK681JOVL40uQTNJe3yEMXKfydDFoz+5hNrM/PqjchueSMKGKCZKBVgeexqZwy3uC2B36Q==}
is-arguments@1.1.1:
resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==}
engines: {node: '>= 0.4'}
@@ -3187,8 +3184,11 @@ packages:
resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
engines: {node: '>= 0.6'}
next-i18n-router@5.5.1:
resolution: {integrity: sha512-uJGYUAQS33LbRT3Jx+kurR/E79iPQo1jWZUYmc+614UkPt58k2XYyGloSvHR74b21i4K/d6eksdBj6T2WojjdA==}
next-intl@3.20.0:
resolution: {integrity: sha512-0bCZcc38HfAZk/T+PNNcnJZknC+caS5rBK+WYRd1HsOL5O6puEu2H3kya8oT9s8piHjrTf7P0UHeahOFleOnrw==}
peerDependencies:
next: ^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0
react: ^16.8.0 || ^17.0.0 || ^18.0.0
next-themes@0.2.1:
resolution: {integrity: sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A==}
@@ -3691,19 +3691,6 @@ packages:
peerDependencies:
react: ^16.8.0 || ^17 || ^18
react-i18next@15.0.2:
resolution: {integrity: sha512-z0W3/RES9Idv3MmJUcf0mDNeeMOUXe+xoL0kPfQPbDoZHmni/XsIoq5zgT2MCFUiau283GuBUK578uD/mkAbLQ==}
peerDependencies:
i18next: '>= 23.2.3'
react: '>= 16.8.0'
react-dom: '*'
react-native: '*'
peerDependenciesMeta:
react-dom:
optional: true
react-native:
optional: true
react-is@16.13.1:
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
@@ -4396,6 +4383,11 @@ packages:
url-parse@1.5.10:
resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
use-intl@3.20.0:
resolution: {integrity: sha512-5WQs6yZVWI9K7vw3134P0bhKNp4mi8NbmqKOCuhD9nQUMTKdmpBXwjk62+axwvEbj4XrZxj4X93mQMLXU5ZsCg==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
use-sync-external-store@1.2.2:
resolution: {integrity: sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==}
peerDependencies:
@@ -4484,10 +4476,6 @@ packages:
jsdom:
optional: true
void-elements@3.1.0:
resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==}
engines: {node: '>=0.10.0'}
w3c-xmlserializer@5.0.0:
resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
engines: {node: '>=18'}
@@ -5203,6 +5191,27 @@ snapshots:
'@floating-ui/utils@0.2.8': {}
'@formatjs/ecma402-abstract@2.1.0':
dependencies:
'@formatjs/fast-memoize': 2.2.0
'@formatjs/intl-localematcher': 0.5.4
tslib: 2.7.0
'@formatjs/fast-memoize@2.2.0':
dependencies:
tslib: 2.7.0
'@formatjs/icu-messageformat-parser@2.7.9':
dependencies:
'@formatjs/ecma402-abstract': 2.1.0
'@formatjs/icu-skeleton-parser': 1.8.3
tslib: 2.7.0
'@formatjs/icu-skeleton-parser@1.8.3':
dependencies:
'@formatjs/ecma402-abstract': 2.1.0
tslib: 2.7.0
'@formatjs/intl-localematcher@0.5.4':
dependencies:
tslib: 2.7.0
@@ -7174,10 +7183,6 @@ snapshots:
dependencies:
whatwg-encoding: 3.1.1
html-parse-stringify@3.0.1:
dependencies:
void-elements: 3.1.0
http-proxy-agent@7.0.2:
dependencies:
agent-base: 7.1.1
@@ -7213,14 +7218,6 @@ snapshots:
human-signals@5.0.0: {}
i18next-resources-to-backend@1.2.1:
dependencies:
'@babel/runtime': 7.25.7
i18next@23.15.2:
dependencies:
'@babel/runtime': 7.25.7
iconv-lite@0.4.24:
dependencies:
safer-buffer: 2.1.2
@@ -7263,6 +7260,13 @@ snapshots:
hasown: 2.0.2
side-channel: 1.0.6
intl-messageformat@10.6.0:
dependencies:
'@formatjs/ecma402-abstract': 2.1.0
'@formatjs/fast-memoize': 2.2.0
'@formatjs/icu-messageformat-parser': 2.7.9
tslib: 2.7.0
is-arguments@1.1.1:
dependencies:
call-bind: 1.0.7
@@ -7779,10 +7783,13 @@ snapshots:
negotiator@0.6.3: {}
next-i18n-router@5.5.1:
next-intl@3.20.0(next@14.2.14(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1))(react@18.3.1):
dependencies:
'@formatjs/intl-localematcher': 0.5.4
negotiator: 0.6.3
next: 14.2.14(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1)
react: 18.3.1
use-intl: 3.20.0(react@18.3.1)
next-themes@0.2.1(next@14.2.14(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
@@ -8195,15 +8202,6 @@ snapshots:
dependencies:
react: 18.3.1
react-i18next@15.0.2(i18next@23.15.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
'@babel/runtime': 7.25.7
html-parse-stringify: 3.0.1
i18next: 23.15.2
react: 18.3.1
optionalDependencies:
react-dom: 18.3.1(react@18.3.1)
react-is@16.13.1: {}
react-is@17.0.2: {}
@@ -8985,6 +8983,12 @@ snapshots:
querystringify: 2.2.0
requires-port: 1.0.0
use-intl@3.20.0(react@18.3.1):
dependencies:
'@formatjs/fast-memoize': 2.2.0
intl-messageformat: 10.6.0
react: 18.3.1
use-sync-external-store@1.2.2(react@18.3.1):
dependencies:
react: 18.3.1
@@ -9077,8 +9081,6 @@ snapshots:
- supports-color
- terser
void-elements@3.1.0: {}
w3c-xmlserializer@5.0.0:
dependencies:
xml-name-validator: 5.0.0