mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-08-26 13:22:50 -05:00
build(deps): bump remix-i18next from 7.5.0 to 8.0.0 (#3215)
Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Kalle <38327916+Sendouc@users.noreply.github.com>
This commit is contained in:
@@ -1,21 +1,19 @@
|
||||
import { PassThrough } from "node:stream";
|
||||
import { createReadableStreamFromReadable } from "@react-router/node";
|
||||
import * as Sentry from "@sentry/react-router";
|
||||
import { createInstance } from "i18next";
|
||||
import { isbot } from "isbot";
|
||||
import cron from "node-cron";
|
||||
import { renderToPipeableStream } from "react-dom/server";
|
||||
import { I18nextProvider, initReactI18next } from "react-i18next";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
import {
|
||||
type EntryContext,
|
||||
type HandleErrorFunction,
|
||||
type RouterContextProvider,
|
||||
ServerRouter,
|
||||
} from "react-router";
|
||||
import { Config } from "~/config";
|
||||
import { ServerConfig } from "~/config.server";
|
||||
import { config } from "~/modules/i18n/config"; // your i18n configuration file
|
||||
import { i18next } from "~/modules/i18n/i18next.server";
|
||||
import { resources } from "./modules/i18n/resources.server";
|
||||
import { getI18nInstance } from "~/modules/i18n/i18next.server";
|
||||
import {
|
||||
daily,
|
||||
everyHourAt00,
|
||||
@@ -34,23 +32,13 @@ async function handleRequest(
|
||||
responseStatusCode: number,
|
||||
responseHeaders: Headers,
|
||||
reactRouterContext: EntryContext,
|
||||
loadContext: RouterContextProvider,
|
||||
) {
|
||||
const callbackName = isbot(request.headers.get("user-agent"))
|
||||
? "onAllReady"
|
||||
: "onShellReady";
|
||||
|
||||
const instance = createInstance();
|
||||
const lng = await i18next.getLocale(request);
|
||||
const ns = i18next.getRouteNamespaces(reactRouterContext);
|
||||
|
||||
await instance
|
||||
.use(initReactI18next) // Tell our instance to use react-i18next
|
||||
.init({
|
||||
...config, // spread the configuration
|
||||
lng, // The locale we detected above
|
||||
ns, // The namespaces the routes about to render wants to use
|
||||
resources,
|
||||
});
|
||||
const instance = getI18nInstance(loadContext);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let didError = false;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { LoaderFunctionArgs } from "react-router";
|
||||
import { z } from "zod";
|
||||
import * as SQMatchRepository from "~/features/sendouq-match/SQMatchRepository.server";
|
||||
import { i18next } from "~/modules/i18n/i18next.server";
|
||||
import { getFixedTForLanguage } from "~/modules/i18n/i18next.server";
|
||||
import { notFoundIfFalsy, parseParams } from "~/utils/remix.server";
|
||||
import { id } from "~/utils/zod";
|
||||
import type { GetSendouqMatchResponse, MapListMap } from "../schema";
|
||||
@@ -18,7 +18,7 @@ export const loader = async ({ params }: LoaderFunctionArgs) => {
|
||||
|
||||
const match = notFoundIfFalsy(await SQMatchRepository.findById(matchId));
|
||||
|
||||
const t = await i18next.getFixedT("en", ["game-misc"]);
|
||||
const t = await getFixedTForLanguage("en", ["game-misc"]);
|
||||
|
||||
const userIdToRank = (userId: number) => {
|
||||
const memento = match.memento;
|
||||
|
||||
@@ -6,7 +6,7 @@ import * as TournamentRepository from "~/features/tournament/TournamentRepositor
|
||||
import * as TournamentTeamRepository from "~/features/tournament/TournamentTeamRepository.server";
|
||||
import { tournamentFromDBCached } from "~/features/tournament-bracket/core/Tournament.server";
|
||||
import { resolveMapList } from "~/features/tournament-match/core/mapList.server";
|
||||
import { i18next } from "~/modules/i18n/i18next.server";
|
||||
import { getFixedTForLanguage } from "~/modules/i18n/i18next.server";
|
||||
import { logger } from "~/utils/logger";
|
||||
import { notFoundIfFalsy, parseParams } from "~/utils/remix.server";
|
||||
import { id } from "~/utils/zod";
|
||||
@@ -17,7 +17,7 @@ const paramsSchema = z.object({
|
||||
});
|
||||
|
||||
export const loader = async ({ params }: LoaderFunctionArgs) => {
|
||||
const t = await i18next.getFixedT("en", ["game-misc"]);
|
||||
const t = await getFixedTForLanguage("en", ["game-misc"]);
|
||||
const { id } = parseParams({
|
||||
params,
|
||||
schema: paramsSchema,
|
||||
|
||||
@@ -5,7 +5,7 @@ import { z } from "zod";
|
||||
import { db } from "~/db/sql";
|
||||
import { ordinalToSp } from "~/features/mmr/mmr-utils";
|
||||
import * as TournamentRepository from "~/features/tournament/TournamentRepository.server";
|
||||
import { i18next } from "~/modules/i18n/i18next.server";
|
||||
import { getFixedTForLanguage } from "~/modules/i18n/i18next.server";
|
||||
import { nullifyingAvg } from "~/utils/arrays";
|
||||
import { databaseTimestampToDate } from "~/utils/dates";
|
||||
import { concatUserSubmittedImagePrefix } from "~/utils/kysely.server";
|
||||
@@ -18,7 +18,7 @@ const paramsSchema = z.object({
|
||||
});
|
||||
|
||||
export const loader = async ({ params }: LoaderFunctionArgs) => {
|
||||
const t = await i18next.getFixedT("en", ["game-misc"]);
|
||||
const t = await getFixedTForLanguage("en", ["game-misc"]);
|
||||
const { id } = parseParams({
|
||||
params,
|
||||
schema: paramsSchema,
|
||||
|
||||
@@ -6,7 +6,7 @@ import * as Seasons from "~/features/mmr/core/Seasons";
|
||||
import { userSkills as _userSkills } from "~/features/mmr/tiered.server";
|
||||
import { peakXpOverallSql } from "~/features/top-search/XRankPlacementRepository.server";
|
||||
import * as UserRepository from "~/features/user-page/UserRepository.server";
|
||||
import { i18next } from "~/modules/i18n/i18next.server";
|
||||
import { getFixedTForLanguage } from "~/modules/i18n/i18next.server";
|
||||
import { safeNumberParse } from "~/utils/number";
|
||||
import { notFoundIfFalsy, parseParams } from "~/utils/remix.server";
|
||||
import { badgeUrl } from "~/utils/urls";
|
||||
@@ -17,7 +17,7 @@ const paramsSchema = z.object({
|
||||
});
|
||||
|
||||
export const loader = async ({ params }: LoaderFunctionArgs) => {
|
||||
const t = await i18next.getFixedT("en", ["weapons"]);
|
||||
const t = await getFixedTForLanguage("en", ["weapons"]);
|
||||
const { identifier } = parseParams({ params, schema: paramsSchema });
|
||||
|
||||
const user = notFoundIfFalsy(
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { cachified } from "@epic-web/cachified";
|
||||
import type { LoaderFunctionArgs } from "react-router";
|
||||
import * as BuildRepository from "~/features/builds/BuildRepository.server";
|
||||
import { i18next } from "~/modules/i18n/i18next.server";
|
||||
import { getServerTFunction } from "~/modules/i18n/i18next.server";
|
||||
import { weaponIdToType } from "~/modules/in-game-lists/weapon-ids";
|
||||
import { cache, IN_MILLISECONDS, ttl } from "~/utils/cache.server";
|
||||
import { notFoundIfNullLike } from "~/utils/remix.server";
|
||||
import { weaponNameSlugToId } from "~/utils/unslugify.server";
|
||||
import { popularBuilds } from "../build-stats-utils";
|
||||
|
||||
export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
||||
const t = await i18next.getFixedT(request, ["builds", "weapons"]);
|
||||
export const loader = async ({ params }: LoaderFunctionArgs) => {
|
||||
const t = getServerTFunction(["builds", "weapons"]);
|
||||
const slug = params.slug;
|
||||
const weaponId = notFoundIfNullLike(weaponNameSlugToId(slug));
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { cachified } from "@epic-web/cachified";
|
||||
import type { LoaderFunctionArgs } from "react-router";
|
||||
import * as BuildRepository from "~/features/builds/BuildRepository.server";
|
||||
import { i18next } from "~/modules/i18n/i18next.server";
|
||||
import { getServerTFunction } from "~/modules/i18n/i18next.server";
|
||||
import { weaponIdToType } from "~/modules/in-game-lists/weapon-ids";
|
||||
import { cache } from "~/utils/cache.server";
|
||||
import { notFoundIfNullLike } from "~/utils/remix.server";
|
||||
import { weaponNameSlugToId } from "~/utils/unslugify.server";
|
||||
import { abilityPointCountsToAverages } from "../build-stats-utils";
|
||||
|
||||
export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
||||
const t = await i18next.getFixedT(request, ["builds", "weapons"]);
|
||||
export const loader = async ({ params }: LoaderFunctionArgs) => {
|
||||
const t = getServerTFunction(["builds", "weapons"]);
|
||||
const weaponId = notFoundIfNullLike(weaponNameSlugToId(params.slug));
|
||||
|
||||
if (weaponIdToType(weaponId) === "ALT_SKIN") {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { LoaderFunctionArgs } from "react-router";
|
||||
import { getUser } from "~/features/auth/core/user.server";
|
||||
import { i18next } from "~/modules/i18n/i18next.server";
|
||||
import { getFixedTForLanguage } from "~/modules/i18n/i18next.server";
|
||||
import { weaponIdToType } from "~/modules/in-game-lists/weapon-ids";
|
||||
import { weaponNameSlugToId } from "~/utils/unslugify.server";
|
||||
import { mySlugify } from "~/utils/urls";
|
||||
@@ -15,11 +15,9 @@ import {
|
||||
} from "../builds-schemas";
|
||||
import { filterBuilds } from "../core/filter.server";
|
||||
|
||||
export const loader = async ({ request, params, url }: LoaderFunctionArgs) => {
|
||||
export const loader = async ({ params, url }: LoaderFunctionArgs) => {
|
||||
const user = getUser();
|
||||
const t = await i18next.getFixedT(request, ["weapons", "common"], {
|
||||
lng: "en",
|
||||
});
|
||||
const t = await getFixedTForLanguage("en", ["weapons", "common"]);
|
||||
const weaponId = weaponNameSlugToId(params.slug);
|
||||
|
||||
if (typeof weaponId !== "number" || weaponIdToType(weaponId) === "ALT_SKIN") {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { type Urgency, WebPushError } from "web-push";
|
||||
import { IS_E2E_TEST_RUN } from "~/utils/e2e";
|
||||
import { APP_ICON_URL } from "~/utils/urls";
|
||||
import type { NotificationSubscription } from "../../../db/tables";
|
||||
import { i18next } from "../../../modules/i18n/i18next.server";
|
||||
import { getFixedTForLanguage } from "../../../modules/i18n/i18next.server";
|
||||
import { logger } from "../../../utils/logger";
|
||||
import * as NotificationRepository from "../NotificationRepository.server";
|
||||
import type { Notification } from "../notifications-types";
|
||||
@@ -76,7 +76,7 @@ export async function notify({
|
||||
dededuplicatedUserIds,
|
||||
);
|
||||
if (subscriptions.length > 0) {
|
||||
const t = await i18next.getFixedT("en-US", ["common"]);
|
||||
const t = await getFixedTForLanguage("en-US", ["common"]);
|
||||
|
||||
const limit = pLimit(50);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { LoaderFunctionArgs } from "react-router";
|
||||
import { mainWeaponParams } from "~/features/build-analyzer/core/utils";
|
||||
import { i18next } from "~/modules/i18n/i18next.server";
|
||||
import { getFixedTForLanguage } from "~/modules/i18n/i18next.server";
|
||||
import type {
|
||||
MainWeaponId,
|
||||
SpecialWeaponId,
|
||||
@@ -35,10 +35,8 @@ const subParamsData = subWeaponParamsData as WeaponParams.AllVersionParams;
|
||||
const specialParamsData =
|
||||
specialWeaponParamsData as WeaponParams.AllVersionParams;
|
||||
|
||||
export const loader = async ({ request, params }: LoaderFunctionArgs) => {
|
||||
const t = await i18next.getFixedT(request, ["weapons"], {
|
||||
lng: "en",
|
||||
});
|
||||
export const loader = async ({ params }: LoaderFunctionArgs) => {
|
||||
const t = await getFixedTForLanguage("en", ["weapons"]);
|
||||
|
||||
const mainWeaponId = weaponNameSlugToId(params.slug);
|
||||
if (typeof mainWeaponId === "number") {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { requireUser } from "~/features/auth/core/user.server";
|
||||
import * as ShowcaseTournaments from "~/features/front-page/core/ShowcaseTournaments.server";
|
||||
import { clearTournamentDataCache } from "~/features/tournament-bracket/core/Tournament.server";
|
||||
import { parseFormDataWithImages } from "~/form/parse.server";
|
||||
import { i18next } from "~/modules/i18n/i18next.server";
|
||||
import { getServerTFunction } from "~/modules/i18n/i18next.server";
|
||||
import { requirePermission } from "~/modules/permissions/guards.server";
|
||||
import { actionError } from "~/utils/remix.server";
|
||||
import { tournamentOrganizationPage } from "~/utils/urls";
|
||||
@@ -24,7 +24,7 @@ export const action = async ({ request, params }: ActionFunctionArgs) => {
|
||||
|
||||
const data = result.data;
|
||||
|
||||
const t = await i18next.getFixedT(request, ["org"]);
|
||||
const t = getServerTFunction(["org"]);
|
||||
|
||||
const organization = await organizationFromParams(params);
|
||||
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
import { createCookie } from "react-router";
|
||||
import { RemixI18Next } from "remix-i18next/server";
|
||||
import { AsyncLocalStorage } from "node:async_hooks";
|
||||
import {
|
||||
createInstance,
|
||||
type DefaultNamespace,
|
||||
type FlatNamespace,
|
||||
type i18n,
|
||||
type Namespace,
|
||||
type TFunction,
|
||||
} from "i18next";
|
||||
import { type FallbackNs, initReactI18next } from "react-i18next";
|
||||
import {
|
||||
createCookie,
|
||||
type MiddlewareFunction,
|
||||
type RouterContextProvider,
|
||||
} from "react-router";
|
||||
import { createI18nextMiddleware } from "remix-i18next";
|
||||
import invariant from "~/utils/invariant";
|
||||
import { config } from "./config";
|
||||
import { resources } from "./resources.server";
|
||||
|
||||
@@ -11,14 +26,95 @@ export const i18nCookie = createCookie("i18n", {
|
||||
maxAge: TEN_YEARS_IN_SECONDS,
|
||||
});
|
||||
|
||||
export const i18next = new RemixI18Next({
|
||||
detection: {
|
||||
cookie: i18nCookie,
|
||||
supportedLanguages: config.supportedLngs,
|
||||
fallbackLanguage: config.fallbackLng,
|
||||
},
|
||||
i18next: {
|
||||
...config,
|
||||
resources: resources,
|
||||
},
|
||||
});
|
||||
const [remixI18nextMiddleware, getLocaleFromContext, getInstanceFromContext] =
|
||||
createI18nextMiddleware({
|
||||
detection: {
|
||||
cookie: i18nCookie,
|
||||
supportedLanguages: config.supportedLngs,
|
||||
fallbackLanguage: config.fallbackLng,
|
||||
},
|
||||
i18next: {
|
||||
...config,
|
||||
resources,
|
||||
},
|
||||
plugins: [initReactI18next],
|
||||
});
|
||||
|
||||
interface I18nStore {
|
||||
locale: string;
|
||||
instance: i18n;
|
||||
}
|
||||
|
||||
const i18nAsyncLocalStorage = new AsyncLocalStorage<I18nStore>();
|
||||
|
||||
/**
|
||||
* Detects the request locale, initializes a request-scoped i18next instance and
|
||||
* makes both available to server helpers ({@link getLocale},
|
||||
* {@link getServerTFunction}) for the duration of the request.
|
||||
*/
|
||||
export const i18nMiddleware: MiddlewareFunction<Response> = (args, next) =>
|
||||
remixI18nextMiddleware(args, () =>
|
||||
i18nAsyncLocalStorage.run(
|
||||
{
|
||||
locale: getLocaleFromContext(args.context),
|
||||
instance: getInstanceFromContext(args.context),
|
||||
},
|
||||
() => next(),
|
||||
),
|
||||
);
|
||||
|
||||
/** The locale detected for the current request. */
|
||||
export function getLocale(): string {
|
||||
return currentStore().locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* A `TFunction` bound to the current request's locale and the given namespaces.
|
||||
* Namespaces are already available in-memory so no async loading is needed.
|
||||
*/
|
||||
export function getServerTFunction<
|
||||
N extends
|
||||
| FlatNamespace
|
||||
| readonly [FlatNamespace, ...FlatNamespace[]] = DefaultNamespace,
|
||||
>(namespaces?: N): TFunction<FallbackNs<N>> {
|
||||
const { instance, locale } = currentStore();
|
||||
return instance.getFixedT(
|
||||
locale,
|
||||
namespaces as Namespace,
|
||||
) as unknown as TFunction<FallbackNs<N>>;
|
||||
}
|
||||
|
||||
/**
|
||||
* The request-scoped i18next instance, used to provide translations while
|
||||
* server-side rendering. Reads from the React Router context so it can be called
|
||||
* from `entry.server` where the request context is passed explicitly.
|
||||
*/
|
||||
export function getI18nInstance(
|
||||
context: Readonly<RouterContextProvider>,
|
||||
): i18n {
|
||||
return getInstanceFromContext(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* A `TFunction` bound to a fixed language, independent of the current request.
|
||||
* Use this when translating outside of a request (e.g. notifications) or when a
|
||||
* specific language is required regardless of the user's locale.
|
||||
*/
|
||||
export async function getFixedTForLanguage<
|
||||
N extends
|
||||
| FlatNamespace
|
||||
| readonly [FlatNamespace, ...FlatNamespace[]] = DefaultNamespace,
|
||||
>(language: string, namespaces?: N): Promise<TFunction<FallbackNs<N>>> {
|
||||
const instance = createInstance();
|
||||
await instance.init({ ...config, resources, lng: language });
|
||||
return instance.getFixedT(
|
||||
language,
|
||||
namespaces as Namespace,
|
||||
) as unknown as TFunction<FallbackNs<N>>;
|
||||
}
|
||||
|
||||
function currentStore(): I18nStore {
|
||||
const store = i18nAsyncLocalStorage.getStore();
|
||||
invariant(store, "i18n store not found, is i18nMiddleware registered?");
|
||||
return store;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import i18next from "i18next";
|
||||
import LanguageDetector from "i18next-browser-languagedetector";
|
||||
import Backend from "i18next-http-backend";
|
||||
import { initReactI18next } from "react-i18next";
|
||||
import { getInitialNamespaces } from "remix-i18next/client";
|
||||
import { config } from "./config";
|
||||
|
||||
export function i18nLoader() {
|
||||
@@ -30,3 +29,32 @@ export function i18nLoader() {
|
||||
initAsync: false,
|
||||
});
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
__reactRouterRouteModules: Record<string, { handle?: unknown } | undefined>;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of namespaces used by the application server-side so they can be
|
||||
* set on i18next init options and preloaded before hydration.
|
||||
*
|
||||
* Vendored from remix-i18next (removed in v8).
|
||||
*/
|
||||
function getInitialNamespaces(): string[] {
|
||||
return Object.values(window.__reactRouterRouteModules).flatMap((route) => {
|
||||
const handle = route?.handle;
|
||||
if (typeof handle !== "object" || handle === null) return [];
|
||||
if (!("i18n" in handle)) return [];
|
||||
const namespaces = (handle as { i18n: unknown }).i18n;
|
||||
if (typeof namespaces === "string") return [namespaces];
|
||||
if (
|
||||
Array.isArray(namespaces) &&
|
||||
namespaces.every((value) => typeof value === "string")
|
||||
) {
|
||||
return namespaces as string[];
|
||||
}
|
||||
return [];
|
||||
});
|
||||
}
|
||||
|
||||
15
app/modules/i18n/useChangeLanguage.ts
Normal file
15
app/modules/i18n/useChangeLanguage.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import * as React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
/**
|
||||
* Detect when the locale returned by the root route loader changes and call
|
||||
* `i18n.changeLanguage` with the new locale so translations load automatically.
|
||||
*
|
||||
* Vendored from remix-i18next (removed in v8).
|
||||
*/
|
||||
export function useChangeLanguage(locale: string) {
|
||||
const { i18n } = useTranslation();
|
||||
React.useEffect(() => {
|
||||
if (i18n.language !== locale) i18n.changeLanguage(locale);
|
||||
}, [locale, i18n]);
|
||||
}
|
||||
11
app/root.tsx
11
app/root.tsx
@@ -27,7 +27,6 @@ import {
|
||||
useRevalidator,
|
||||
useSearchParams,
|
||||
} from "react-router";
|
||||
import { useChangeLanguage } from "remix-i18next/react";
|
||||
import { Config } from "~/config";
|
||||
import type { CustomTheme } from "~/db/tables";
|
||||
import * as NotificationRepository from "~/features/notifications/NotificationRepository.server";
|
||||
@@ -56,7 +55,12 @@ import { getThemeSession } from "./features/theme/core/theme-session.server";
|
||||
import { useUserIntlPreference } from "./hooks/intl/useUserIntlPreference";
|
||||
import { useHydrated } from "./hooks/useHydrated";
|
||||
import { DEFAULT_LANGUAGE } from "./modules/i18n/config";
|
||||
import { i18nCookie, i18next } from "./modules/i18n/i18next.server";
|
||||
import {
|
||||
getLocale,
|
||||
i18nCookie,
|
||||
i18nMiddleware,
|
||||
} from "./modules/i18n/i18next.server";
|
||||
import { useChangeLanguage } from "./modules/i18n/useChangeLanguage";
|
||||
import { isSupporter } from "./modules/permissions/utils";
|
||||
import { IS_E2E_TEST_RUN } from "./utils/e2e";
|
||||
import { allI18nNamespaces } from "./utils/i18n";
|
||||
@@ -68,6 +72,7 @@ export const middleware: Route.MiddlewareFunction[] = [
|
||||
requestContextMiddleware,
|
||||
sessionIdMiddleware,
|
||||
userMiddleware,
|
||||
i18nMiddleware,
|
||||
];
|
||||
|
||||
import "~/styles/vars.css";
|
||||
@@ -110,7 +115,7 @@ export type LoggedInUser = NonNullable<RootLoaderData["user"]>;
|
||||
|
||||
export const loader = async ({ request }: LoaderFunctionArgs) => {
|
||||
const user = getUser();
|
||||
const locale = await i18next.getLocale(request);
|
||||
const locale = getLocale();
|
||||
const themeSession = await getThemeSession(request);
|
||||
const sidenavSession = await getSidenavSession(request);
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
"remeda": "2.39.0",
|
||||
"remix-auth": "4.2.0",
|
||||
"remix-auth-oauth2": "3.4.1",
|
||||
"remix-i18next": "7.5.0",
|
||||
"remix-i18next": "8.0.0",
|
||||
"slugify": "1.6.9",
|
||||
"swr": "2.4.2",
|
||||
"web-haptics": "0.0.6",
|
||||
|
||||
18
pnpm-lock.yaml
generated
18
pnpm-lock.yaml
generated
@@ -172,8 +172,8 @@ importers:
|
||||
specifier: 3.4.1
|
||||
version: 3.4.1(remix-auth@4.2.0)
|
||||
remix-i18next:
|
||||
specifier: 7.5.0
|
||||
version: 7.5.0(i18next@26.3.4(typescript@6.0.3))(react-i18next@17.0.8(i18next@26.3.4(typescript@6.0.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@6.0.3))(react-router@8.1.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7)
|
||||
specifier: 8.0.0
|
||||
version: 8.0.0(i18next@26.3.4(typescript@6.0.3))(react-router@8.1.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7))
|
||||
slugify:
|
||||
specifier: 1.6.9
|
||||
version: 1.6.9
|
||||
@@ -4089,14 +4089,12 @@ packages:
|
||||
resolution: {integrity: sha512-3LSfWEvSgG2CgbG/p4ge5hbV8tTXWNnnYIGbTr9oSSiHz9dD7wh6S0MEyo3pwh7MlKezB2WIlevGeyqUZykk7g==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
|
||||
remix-i18next@7.5.0:
|
||||
resolution: {integrity: sha512-7vAwnNkAXzr/YQwFkV1FHrY+3utgGrDwn7oP/aM2gFHrwbGT0+uVtuUx3USpTrJvhzAN+2YU/mnmgyBi9EhYyw==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
remix-i18next@8.0.0:
|
||||
resolution: {integrity: sha512-+QbCBo3VP6JH2zCbPoRPhgYErY89vDnr4Sy66tlzANwyRnEIHEA2o6HlEuz0iCoDn9f8I88cknNrHGsc4n77zg==}
|
||||
engines: {node: '>=22.22.0'}
|
||||
peerDependencies:
|
||||
i18next: ^24.0.0 || ^25.0.0 || ^26.0.0
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react-i18next: ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
|
||||
react-router: ^7.0.0
|
||||
react-router: ^8.0.0
|
||||
|
||||
require-directory@2.1.1:
|
||||
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
|
||||
@@ -8700,11 +8698,9 @@ snapshots:
|
||||
|
||||
remix-auth@4.2.0: {}
|
||||
|
||||
remix-i18next@7.5.0(i18next@26.3.4(typescript@6.0.3))(react-i18next@17.0.8(i18next@26.3.4(typescript@6.0.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@6.0.3))(react-router@8.1.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7):
|
||||
remix-i18next@8.0.0(i18next@26.3.4(typescript@6.0.3))(react-router@8.1.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7)):
|
||||
dependencies:
|
||||
i18next: 26.3.4(typescript@6.0.3)
|
||||
react: 19.2.7
|
||||
react-i18next: 17.0.8(i18next@26.3.4(typescript@6.0.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@6.0.3)
|
||||
react-router: 8.1.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
|
||||
require-directory@2.1.1: {}
|
||||
|
||||
Reference in New Issue
Block a user