refactor: implementation of locale calculated server-side (#11534)
parent
b4c6388ce0
commit
778485b31d
|
@ -1,12 +1,7 @@
|
|||
import { lookup } from "bcp-47-match";
|
||||
import { useSession } from "next-auth/react";
|
||||
import { useTranslation } from "next-i18next";
|
||||
import { useEffect } from "react";
|
||||
|
||||
import { CALCOM_VERSION } from "@calcom/lib/constants";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
|
||||
function useViewerI18n(locale: string) {
|
||||
export function useViewerI18n(locale: string) {
|
||||
return trpc.viewer.public.i18n.useQuery(
|
||||
{ locale, CalComVersion: CALCOM_VERSION },
|
||||
{
|
||||
|
@ -19,46 +14,3 @@ function useViewerI18n(locale: string) {
|
|||
}
|
||||
);
|
||||
}
|
||||
|
||||
function useClientLocale(locales: string[]) {
|
||||
const session = useSession();
|
||||
// If the user is logged in, use their locale
|
||||
if (session.data?.user.locale) return session.data.user.locale;
|
||||
// If the user is not logged in, use the browser locale
|
||||
if (typeof window !== "undefined") {
|
||||
// This is the only way I found to ensure the prefetched locale is used on first render
|
||||
// FIXME: Find a better way to pick the best matching locale from the browser
|
||||
return lookup(locales, window.navigator.language) || window.navigator.language;
|
||||
}
|
||||
// If the browser is not available, use English
|
||||
return "en";
|
||||
}
|
||||
|
||||
export function useClientViewerI18n(locales: string[]) {
|
||||
const clientLocale = useClientLocale(locales);
|
||||
return useViewerI18n(clientLocale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto-switches locale client-side to the logged in user's preference
|
||||
*/
|
||||
const I18nLanguageHandler = (props: { locales: string[] }) => {
|
||||
const { locales } = props;
|
||||
const { i18n } = useTranslation("common");
|
||||
const locale = useClientViewerI18n(locales).data?.locale || i18n.language;
|
||||
|
||||
useEffect(() => {
|
||||
// bail early when i18n = {}
|
||||
if (Object.keys(i18n).length === 0) return;
|
||||
// if locale is ready and the i18n.language does != locale - changeLanguage
|
||||
if (locale && i18n.language !== locale) {
|
||||
i18n.changeLanguage(locale);
|
||||
}
|
||||
// set dir="rtl|ltr"
|
||||
document.dir = i18n.dir();
|
||||
document.documentElement.setAttribute("lang", locale);
|
||||
}, [locale, i18n]);
|
||||
return null;
|
||||
};
|
||||
|
||||
export default I18nLanguageHandler;
|
||||
|
|
|
@ -13,8 +13,6 @@ import type { AppProps } from "@lib/app-providers";
|
|||
import AppProviders from "@lib/app-providers";
|
||||
import { seoConfig } from "@lib/config/next-seo.config";
|
||||
|
||||
import I18nLanguageHandler from "@components/I18nLanguageHandler";
|
||||
|
||||
export interface CalPageWrapper {
|
||||
(props?: AppProps): JSX.Element;
|
||||
PageWrapper?: AppProps["Component"]["PageWrapper"];
|
||||
|
@ -72,7 +70,6 @@ function PageWrapper(props: AppProps) {
|
|||
}
|
||||
{...seoConfig.defaultNextSeo}
|
||||
/>
|
||||
<I18nLanguageHandler locales={props.router.locales || []} />
|
||||
<Script
|
||||
nonce={nonce}
|
||||
id="page-status"
|
||||
|
|
|
@ -7,7 +7,7 @@ import { appWithTranslation } from "next-i18next";
|
|||
import { ThemeProvider } from "next-themes";
|
||||
import type { AppProps as NextAppProps, AppProps as NextJsAppProps } from "next/app";
|
||||
import type { ParsedUrlQuery } from "querystring";
|
||||
import type { ComponentProps, PropsWithChildren, ReactNode } from "react";
|
||||
import type { PropsWithChildren, ReactNode } from "react";
|
||||
|
||||
import { OrgBrandingProvider } from "@calcom/features/ee/organizations/context/provider";
|
||||
import DynamicHelpscoutProvider from "@calcom/features/ee/support/lib/helpscout/providerDynamic";
|
||||
|
@ -17,9 +17,10 @@ import { useFlags } from "@calcom/features/flags/hooks";
|
|||
import { MetaProvider } from "@calcom/ui";
|
||||
|
||||
import useIsBookingPage from "@lib/hooks/useIsBookingPage";
|
||||
import type { WithLocaleProps } from "@lib/withLocale";
|
||||
import type { WithNonceProps } from "@lib/withNonce";
|
||||
|
||||
import { useClientViewerI18n } from "@components/I18nLanguageHandler";
|
||||
import { useViewerI18n } from "@components/I18nLanguageHandler";
|
||||
|
||||
const I18nextAdapter = appWithTranslation<
|
||||
NextJsAppProps<SSRConfig> & {
|
||||
|
@ -30,10 +31,12 @@ const I18nextAdapter = appWithTranslation<
|
|||
// Workaround for https://github.com/vercel/next.js/issues/8592
|
||||
export type AppProps = Omit<
|
||||
NextAppProps<
|
||||
WithNonceProps & {
|
||||
themeBasis?: string;
|
||||
session: Session;
|
||||
} & Record<string, unknown>
|
||||
WithLocaleProps<
|
||||
WithNonceProps<{
|
||||
themeBasis?: string;
|
||||
session: Session;
|
||||
}>
|
||||
>
|
||||
>,
|
||||
"Component"
|
||||
> & {
|
||||
|
@ -68,8 +71,8 @@ const CustomI18nextProvider = (props: AppPropsWithoutNonce) => {
|
|||
/**
|
||||
* i18n should never be clubbed with other queries, so that it's caching can be managed independently.
|
||||
**/
|
||||
const clientViewerI18n = useClientViewerI18n(props.router.locales || []);
|
||||
const { i18n, locale } = clientViewerI18n.data || {};
|
||||
const clientViewerI18n = useViewerI18n(props.pageProps.newLocale);
|
||||
const i18n = clientViewerI18n.data?.i18n;
|
||||
|
||||
const passedProps = {
|
||||
...props,
|
||||
|
@ -77,8 +80,7 @@ const CustomI18nextProvider = (props: AppPropsWithoutNonce) => {
|
|||
...props.pageProps,
|
||||
...i18n,
|
||||
},
|
||||
router: locale ? { locale } : props.router,
|
||||
} as unknown as ComponentProps<typeof I18nextAdapter>;
|
||||
};
|
||||
|
||||
return <I18nextAdapter {...passedProps} />;
|
||||
};
|
||||
|
@ -233,7 +235,9 @@ const AppProviders = (props: AppPropsWithChildren) => {
|
|||
// No need to have intercom on public pages - Good for Page Performance
|
||||
const isBookingPage = useIsBookingPage();
|
||||
const { pageProps, ...rest } = props;
|
||||
const { _nonce, ...restPageProps } = pageProps;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { nonce, ...restPageProps } = pageProps;
|
||||
const propsWithoutNonce = {
|
||||
pageProps: {
|
||||
...restPageProps,
|
||||
|
@ -243,8 +247,8 @@ const AppProviders = (props: AppPropsWithChildren) => {
|
|||
|
||||
const RemainingProviders = (
|
||||
<EventCollectionProvider options={{ apiPath: "/api/collect-events" }}>
|
||||
<SessionProvider session={pageProps.session ?? undefined}>
|
||||
<CustomI18nextProvider {...propsWithoutNonce}>
|
||||
<CustomI18nextProvider {...propsWithoutNonce}>
|
||||
<SessionProvider session={pageProps.session ?? undefined}>
|
||||
<TooltipProvider>
|
||||
{/* color-scheme makes background:transparent not work which is required by embed. We need to ensure next-theme adds color-scheme to `body` instead of `html`(https://github.com/pacocoursey/next-themes/blob/main/src/index.tsx#L74). Once that's done we can enable color-scheme support */}
|
||||
<CalcomThemeProvider
|
||||
|
@ -260,8 +264,8 @@ const AppProviders = (props: AppPropsWithChildren) => {
|
|||
</FeatureFlagsProvider>
|
||||
</CalcomThemeProvider>
|
||||
</TooltipProvider>
|
||||
</CustomI18nextProvider>
|
||||
</SessionProvider>
|
||||
</SessionProvider>
|
||||
</CustomI18nextProvider>
|
||||
</EventCollectionProvider>
|
||||
);
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
export type WithLocaleProps<T extends Record<string, unknown>> = T & {
|
||||
newLocale: string;
|
||||
};
|
|
@ -1,8 +1,8 @@
|
|||
import type { GetServerSideProps, GetServerSidePropsContext } from "next";
|
||||
import type { GetServerSideProps } from "next";
|
||||
|
||||
import { csp } from "@lib/csp";
|
||||
|
||||
export type WithNonceProps = {
|
||||
export type WithNonceProps<T extends Record<string, any>> = T & {
|
||||
nonce?: string;
|
||||
};
|
||||
|
||||
|
@ -11,9 +11,16 @@ export type WithNonceProps = {
|
|||
* Note that if the Components are not adding any script tag then this is not needed. Even in absence of this, Document.getInitialProps would be able to generate nonce itself which it needs to add script tags common to all pages
|
||||
* There is no harm in wrapping a `getServerSideProps` fn with this even if it doesn't add any script tag.
|
||||
*/
|
||||
export default function withNonce(getServerSideProps: GetServerSideProps) {
|
||||
return async (context: GetServerSidePropsContext) => {
|
||||
export default function withNonce<T extends Record<string, any>>(
|
||||
getServerSideProps: GetServerSideProps<T>
|
||||
): GetServerSideProps<WithNonceProps<T>> {
|
||||
return async (context) => {
|
||||
const ssrResponse = await getServerSideProps(context);
|
||||
|
||||
if (!("props" in ssrResponse)) {
|
||||
return ssrResponse;
|
||||
}
|
||||
|
||||
const { nonce } = csp(context.req, context.res);
|
||||
|
||||
// Skip nonce property if it's not available instead of setting it to undefined because undefined can't be serialized.
|
||||
|
@ -23,10 +30,6 @@ export default function withNonce(getServerSideProps: GetServerSideProps) {
|
|||
}
|
||||
: null;
|
||||
|
||||
if (!("props" in ssrResponse)) {
|
||||
return ssrResponse;
|
||||
}
|
||||
|
||||
// Helps in debugging that withNonce was used but a valid nonce couldn't be set
|
||||
context.res.setHeader("x-csp", nonce ? "ssr" : "false");
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import type { IncomingMessage } from "http";
|
||||
import type { AppContextType } from "next/dist/shared/lib/utils";
|
||||
import React from "react";
|
||||
|
||||
import { getLocale } from "@calcom/features/auth/lib/getLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
|
||||
import type { AppProps } from "@lib/app-providers";
|
||||
|
@ -8,8 +11,35 @@ import "../styles/globals.css";
|
|||
|
||||
function MyApp(props: AppProps) {
|
||||
const { Component, pageProps } = props;
|
||||
|
||||
if (Component.PageWrapper !== undefined) return Component.PageWrapper(props);
|
||||
return <Component {...pageProps} />;
|
||||
}
|
||||
|
||||
export default trpc.withTRPC(MyApp);
|
||||
declare global {
|
||||
interface Window {
|
||||
calNewLocale: string;
|
||||
}
|
||||
}
|
||||
|
||||
MyApp.getInitialProps = async (ctx: AppContextType) => {
|
||||
const { req } = ctx.ctx;
|
||||
|
||||
let newLocale = "en";
|
||||
|
||||
if (req) {
|
||||
newLocale = await getLocale(req as IncomingMessage & { cookies: Record<string, any> });
|
||||
} else if (typeof window !== "undefined" && window.calNewLocale) {
|
||||
newLocale = window.calNewLocale;
|
||||
}
|
||||
|
||||
return {
|
||||
pageProps: {
|
||||
newLocale,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const WrappedMyApp = trpc.withTRPC(MyApp);
|
||||
|
||||
export default WrappedMyApp;
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
import type { IncomingMessage } from "http";
|
||||
import type { NextPageContext } from "next";
|
||||
import type { DocumentContext, DocumentProps } from "next/document";
|
||||
import Document, { Head, Html, Main, NextScript } from "next/document";
|
||||
import { z } from "zod";
|
||||
|
||||
import { getLocale } from "@calcom/features/auth/lib/getLocale";
|
||||
import { IS_PRODUCTION } from "@calcom/lib/constants";
|
||||
|
||||
import { csp } from "@lib/csp";
|
||||
|
||||
type Props = Record<string, unknown> & DocumentProps;
|
||||
type Props = Record<string, unknown> & DocumentProps & { newLocale: string };
|
||||
function setHeader(ctx: NextPageContext, name: string, value: string) {
|
||||
try {
|
||||
ctx.res?.setHeader(name, value);
|
||||
|
@ -26,6 +28,10 @@ class MyDocument extends Document<Props> {
|
|||
setHeader(ctx, "x-csp", "initialPropsOnly");
|
||||
}
|
||||
|
||||
const newLocale = ctx.req
|
||||
? await getLocale(ctx.req as IncomingMessage & { cookies: Record<string, any> })
|
||||
: "en";
|
||||
|
||||
const asPath = ctx.asPath || "";
|
||||
// Use a dummy URL as default so that URL parsing works for relative URLs as well. We care about searchParams and pathname only
|
||||
const parsedUrl = new URL(asPath, "https://dummyurl");
|
||||
|
@ -36,17 +42,26 @@ class MyDocument extends Document<Props> {
|
|||
!isEmbedSnippetGeneratorPath;
|
||||
const embedColorScheme = parsedUrl.searchParams.get("ui.color-scheme");
|
||||
const initialProps = await Document.getInitialProps(ctx);
|
||||
return { isEmbed, embedColorScheme, nonce, ...initialProps };
|
||||
return { isEmbed, embedColorScheme, nonce, ...initialProps, newLocale };
|
||||
}
|
||||
|
||||
render() {
|
||||
const { locale } = this.props.__NEXT_DATA__;
|
||||
const { isEmbed, embedColorScheme } = this.props;
|
||||
const { isEmbed, embedColorScheme, newLocale } = this.props;
|
||||
|
||||
const nonceParsed = z.string().safeParse(this.props.nonce);
|
||||
const nonce = nonceParsed.success ? nonceParsed.data : "";
|
||||
return (
|
||||
<Html lang={locale} style={embedColorScheme ? { colorScheme: embedColorScheme as string } : undefined}>
|
||||
<Html
|
||||
lang={newLocale}
|
||||
style={embedColorScheme ? { colorScheme: embedColorScheme as string } : undefined}>
|
||||
<Head nonce={nonce}>
|
||||
<script
|
||||
nonce={nonce}
|
||||
id="newLocale"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `window.calNewLocale = "${newLocale}";`,
|
||||
}}
|
||||
/>
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/api/logo?type=apple-touch-icon" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/api/logo?type=favicon-32" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/api/logo?type=favicon-16" />
|
||||
|
|
|
@ -5,6 +5,7 @@ import Link from "next/link";
|
|||
import type { CSSProperties } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
|
||||
import { getLocale } from "@calcom/features/auth/lib/getLocale";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { Button, PasswordField, Form } from "@calcom/ui";
|
||||
|
@ -162,12 +163,13 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
|
|||
} catch (e) {
|
||||
resetPasswordRequest = null;
|
||||
}
|
||||
const locale = await getLocale(context.req);
|
||||
return {
|
||||
props: {
|
||||
isRequestExpired: !resetPasswordRequest,
|
||||
requestId: id,
|
||||
csrfToken: await getCsrfToken({ req: context.req }),
|
||||
...(await serverSideTranslations(context.locale || "en", ["common"])),
|
||||
...(await serverSideTranslations(locale, ["common"])),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import Link from "next/link";
|
|||
import type { CSSProperties, SyntheticEvent } from "react";
|
||||
import React from "react";
|
||||
|
||||
import { getLocale } from "@calcom/features/auth/lib/getLocale";
|
||||
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { Button, EmailField } from "@calcom/ui";
|
||||
|
@ -154,11 +155,12 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
|||
res.end();
|
||||
return { props: {} };
|
||||
}
|
||||
const locale = await getLocale(context.req);
|
||||
|
||||
return {
|
||||
props: {
|
||||
csrfToken: await getCsrfToken(context),
|
||||
...(await serverSideTranslations(context.locale || "en", ["common"])),
|
||||
...(await serverSideTranslations(locale, ["common"])),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
@ -51,7 +51,8 @@ export default function Login({
|
|||
samlTenantID,
|
||||
samlProductID,
|
||||
totpEmail,
|
||||
}: inferSSRProps<typeof _getServerSideProps> & WithNonceProps) {
|
||||
}: // eslint-disable-next-line @typescript-eslint/ban-types
|
||||
inferSSRProps<typeof _getServerSideProps> & WithNonceProps<{}>) {
|
||||
const searchParams = useSearchParams();
|
||||
const { t } = useLocale();
|
||||
const router = useRouter();
|
||||
|
|
|
@ -6,6 +6,7 @@ import type { CSSProperties } from "react";
|
|||
import { Suspense } from "react";
|
||||
import { z } from "zod";
|
||||
|
||||
import { getLocale } from "@calcom/features/auth/lib/getLocale";
|
||||
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
||||
import { APP_NAME } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
|
@ -219,10 +220,11 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
|||
if (user.completedOnboarding) {
|
||||
return { redirect: { permanent: false, destination: "/event-types" } };
|
||||
}
|
||||
const locale = await getLocale(context.req);
|
||||
|
||||
return {
|
||||
props: {
|
||||
...(await serverSideTranslations(context.locale ?? "", ["common"])),
|
||||
...(await serverSideTranslations(locale, ["common"])),
|
||||
trpcState: ssr.dehydrate(),
|
||||
hasPendingInvites: user.teams.find((team) => team.accepted === false) ?? false,
|
||||
},
|
||||
|
|
|
@ -68,7 +68,11 @@ const GeneralView = ({ localeProp, user }: GeneralViewProps) => {
|
|||
await utils.viewer.me.invalidate();
|
||||
reset(getValues());
|
||||
showToast(t("settings_updated_successfully"), "success");
|
||||
update(res);
|
||||
await update(res);
|
||||
|
||||
if (res.locale) {
|
||||
window.calNewLocale = res.locale;
|
||||
}
|
||||
},
|
||||
onError: () => {
|
||||
showToast(t("error_updating_settings"), "error");
|
||||
|
|
|
@ -2,8 +2,8 @@ import type { GetServerSidePropsContext } from "next";
|
|||
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
|
||||
import superjson from "superjson";
|
||||
|
||||
import { getLocale } from "@calcom/features/auth/lib/getLocale";
|
||||
import { CALCOM_VERSION } from "@calcom/lib/constants";
|
||||
import { getLocaleFromRequest } from "@calcom/lib/getLocaleFromRequest";
|
||||
import { createProxySSGHelpers } from "@calcom/trpc/react/ssg";
|
||||
import { createContext } from "@calcom/trpc/server/createContext";
|
||||
import { appRouter } from "@calcom/trpc/server/routers/_app";
|
||||
|
@ -16,7 +16,7 @@ import { appRouter } from "@calcom/trpc/server/routers/_app";
|
|||
*/
|
||||
export async function ssrInit(context: GetServerSidePropsContext, options?: { noI18nPreload: boolean }) {
|
||||
const ctx = await createContext(context);
|
||||
const locale = await getLocaleFromRequest(context.req);
|
||||
const locale = await getLocale(context.req);
|
||||
const i18n = await serverSideTranslations(locale, ["common", "vital"]);
|
||||
|
||||
const ssr = createProxySSGHelpers({
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
import { parse } from "accept-language-parser";
|
||||
import type { GetTokenParams } from "next-auth/jwt";
|
||||
import { getToken } from "next-auth/jwt";
|
||||
|
||||
/**
|
||||
* This is a slimmed down version of the `getServerSession` function from
|
||||
* `next-auth`.
|
||||
*
|
||||
* Instead of requiring the entire options object for NextAuth, we create
|
||||
* a compatible session using information from the incoming token.
|
||||
*
|
||||
* The downside to this is that we won't refresh sessions if the users
|
||||
* token has expired (30 days). This should be fine as we call `/auth/session`
|
||||
* frequently enough on the client-side to keep the session alive.
|
||||
*/
|
||||
export const getLocale = async (req: GetTokenParams["req"]): Promise<string> => {
|
||||
const token = await getToken({
|
||||
req,
|
||||
});
|
||||
|
||||
const tokenLocale = token?.["locale"];
|
||||
|
||||
if (tokenLocale !== undefined) {
|
||||
return tokenLocale;
|
||||
}
|
||||
|
||||
const acceptLanguage =
|
||||
req.headers instanceof Headers ? req.headers.get("accept-language") : req.headers["accept-language"];
|
||||
|
||||
const languages = acceptLanguage ? parse(acceptLanguage) : [];
|
||||
|
||||
return languages[0]?.code ?? "en";
|
||||
};
|
|
@ -1,22 +0,0 @@
|
|||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
import parser from "accept-language-parser";
|
||||
import type { GetServerSidePropsContext, NextApiRequest } from "next";
|
||||
|
||||
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
||||
import type { Maybe } from "@calcom/trpc/server";
|
||||
|
||||
const { i18n } = require("@calcom/config/next-i18next.config");
|
||||
|
||||
export async function getLocaleFromRequest(
|
||||
req: NextApiRequest | GetServerSidePropsContext["req"]
|
||||
): Promise<string> {
|
||||
const session = await getServerSession({ req });
|
||||
if (session?.user?.locale) return session.user.locale;
|
||||
let preferredLocale: string | null | undefined;
|
||||
if (req.headers["accept-language"]) {
|
||||
preferredLocale = parser.pick(i18n.locales, req.headers["accept-language"], {
|
||||
loose: true,
|
||||
}) as Maybe<string>;
|
||||
}
|
||||
return preferredLocale ?? i18n.defaultLocale;
|
||||
}
|
|
@ -3,7 +3,7 @@ import type { GetServerSidePropsContext, NextApiRequest, NextApiResponse } from
|
|||
import type { Session } from "next-auth";
|
||||
import type { serverSideTranslations } from "next-i18next/serverSideTranslations";
|
||||
|
||||
import { getLocaleFromRequest } from "@calcom/lib/getLocaleFromRequest";
|
||||
import { getLocale } from "@calcom/features/auth/lib/getLocale";
|
||||
import prisma from "@calcom/prisma";
|
||||
import type { SelectedCalendar, User as PrismaUser } from "@calcom/prisma/client";
|
||||
|
||||
|
@ -62,7 +62,7 @@ export async function createContextInner(opts: CreateInnerContextOptions) {
|
|||
* @link https://trpc.io/docs/context
|
||||
*/
|
||||
export const createContext = async ({ req, res }: CreateContextOptions, sessionGetter?: GetSessionFn) => {
|
||||
const locale = await getLocaleFromRequest(req);
|
||||
const locale = await getLocale(req);
|
||||
const session = !!sessionGetter ? await sessionGetter({ req, res }) : null;
|
||||
const contextInner = await createContextInner({ locale, session });
|
||||
return {
|
||||
|
|
|
@ -92,7 +92,7 @@ export async function getUserFromSession(ctx: TRPCContextInner, session: Maybe<S
|
|||
const orgMetadata = teamMetadataSchema.parse(user.organization?.metadata || {});
|
||||
// This helps to prevent reaching the 4MB payload limit by avoiding base64 and instead passing the avatar url
|
||||
|
||||
const locale = user?.locale || ctx.locale;
|
||||
const locale = user?.locale ?? ctx.locale;
|
||||
|
||||
const isOrgAdmin = !!user.organization?.members.length;
|
||||
// Want to reduce the amount of data being sent
|
||||
|
|
|
@ -1,13 +1,6 @@
|
|||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
import type { WithLocale } from "../../createContext";
|
||||
import type { I18nInputSchema } from "./i18n.schema";
|
||||
|
||||
type I18nOptions = {
|
||||
ctx: WithLocale & {
|
||||
req: NextApiRequest | undefined;
|
||||
res: NextApiResponse | undefined;
|
||||
};
|
||||
input: I18nInputSchema;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue