diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 5dbd5aeffd..603be2c1fd 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -202,7 +202,7 @@ jobs: - '!.github/CODEOWNERS' - '!docs/**' - '!help/**' - - '!apps/web/public/static/locales/**/common.json' + - '!packages/i18n/locales/**/common.json' - '!i18n.lock' - name: Check for specific path changes uses: dorny/paths-filter@v3 diff --git a/AGENTS.md b/AGENTS.md index 471787e123..5032e5b617 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -12,7 +12,7 @@ You are a senior Cal.com engineer working in a Yarn/Turbo monorepo. You prioriti - Create PRs in draft mode by default - Run `yarn type-check:ci --force` before concluding CI failures are unrelated to your changes - Import directly from source files, not barrel files (e.g., `@calcom/ui/components/button` not `@calcom/ui`) -- Add translations to `apps/web/public/static/locales/en/common.json` for all UI strings +- Add translations to `packages/i18n/locales/en/common.json` for all UI strings - Use `date-fns` or native `Date` instead of Day.js when timezone awareness isn't needed - Put permission checks in `page.tsx`, never in `layout.tsx` - Use `ast-grep` for searching if available; otherwise use `rg` (ripgrep), then fall back to `grep` @@ -126,7 +126,7 @@ packages/lib/ # Shared utilities - Routes: `apps/web/app/` (App Router) - Database schema: `packages/prisma/schema.prisma` - tRPC routers: `packages/trpc/server/routers/` -- Translations: `apps/web/public/static/locales/en/common.json` +- Translations: `packages/i18n/locales/en/common.json` - Workflow constants: `packages/features/ee/workflows/lib/constants.ts` ## Tech Stack diff --git a/agents/rules/reference-file-locations.md b/agents/rules/reference-file-locations.md index 3d5f06194f..e9287372cb 100644 --- a/agents/rules/reference-file-locations.md +++ b/agents/rules/reference-file-locations.md @@ -33,7 +33,7 @@ tags: reference, navigation, file-locations ## Translations -- English: `apps/web/public/static/locales/en/common.json` +- English: `packages/i18n/locales/en/common.json` ## App Store diff --git a/apps/api/v1/next-i18next.config.js b/apps/api/v1/next-i18next.config.js deleted file mode 100644 index 945540adf2..0000000000 --- a/apps/api/v1/next-i18next.config.js +++ /dev/null @@ -1,10 +0,0 @@ -const path = require("node:path"); -const i18nConfig = require("@calcom/config/next-i18next.config"); - -/** @type {import("next-i18next").UserConfig} */ -const config = { - ...i18nConfig, - localePath: path.resolve("../../web/public/static/locales"), -}; - -module.exports = config; diff --git a/apps/api/v1/test/lib/bookings/_post.test.ts b/apps/api/v1/test/lib/bookings/_post.test.ts index 69038b2305..b22756bda4 100644 --- a/apps/api/v1/test/lib/bookings/_post.test.ts +++ b/apps/api/v1/test/lib/bookings/_post.test.ts @@ -173,7 +173,7 @@ vi.mock("@calcom/features/ee/workflows/lib/getAllWorkflowsFromEventType", () => getAllWorkflowsFromEventType: vi.fn().mockResolvedValue([]), })); -vi.mock("@calcom/lib/server/i18n", () => { +vi.mock("@calcom/i18n/server", () => { const mockT = (key: string, options?: any) => { if (key === "event_between_users") { return `${options?.eventName} between ${options?.host} and ${options?.attendeeName}`; diff --git a/apps/api/v1/test/lib/users/_post.test.ts b/apps/api/v1/test/lib/users/_post.test.ts index 42f84bf329..b3e150c96f 100644 --- a/apps/api/v1/test/lib/users/_post.test.ts +++ b/apps/api/v1/test/lib/users/_post.test.ts @@ -14,7 +14,7 @@ import handler from "../../../pages/api/users/_post"; type CustomNextApiRequest = NextApiRequest & Request; type CustomNextApiResponse = NextApiResponse & Response; -vi.mock("@calcom/lib/server/i18n", () => { +vi.mock("@calcom/i18n/server", () => { return { getTranslation: (key: string) => { return () => key; diff --git a/apps/api/v2/next-i18next.config.js b/apps/api/v2/next-i18next.config.js deleted file mode 100644 index 91c24916bb..0000000000 --- a/apps/api/v2/next-i18next.config.js +++ /dev/null @@ -1,11 +0,0 @@ -/* eslint-disable @typescript-eslint/no-var-requires */ -const path = require("node:path"); -const i18nConfig = require("@calcom/config/next-i18next.config"); - -/** @type {import("next-i18next").UserConfig} */ -const config = { - ...i18nConfig, - localePath: path.resolve("../../web/public/static/locales"), -}; - -module.exports = config; diff --git a/apps/web/app/(booking-page-wrapper)/[user]/[type]/embed/page.tsx b/apps/web/app/(booking-page-wrapper)/[user]/[type]/embed/page.tsx index a44b05edc1..dee7aa70e2 100644 --- a/apps/web/app/(booking-page-wrapper)/[user]/[type]/embed/page.tsx +++ b/apps/web/app/(booking-page-wrapper)/[user]/[type]/embed/page.tsx @@ -3,7 +3,7 @@ import withEmbedSsrAppDir from "app/WithEmbedSSR"; import type { PageProps as ServerPageProps } from "app/_types"; import { cookies, headers } from "next/headers"; -import { loadTranslations } from "@calcom/lib/server/i18n"; +import { loadTranslations } from "@calcom/i18n/server"; import { buildLegacyCtx } from "@lib/buildLegacyCtx"; diff --git a/apps/web/app/(booking-page-wrapper)/[user]/[type]/page.tsx b/apps/web/app/(booking-page-wrapper)/[user]/[type]/page.tsx index a72a40904a..e2da8c5b70 100644 --- a/apps/web/app/(booking-page-wrapper)/[user]/[type]/page.tsx +++ b/apps/web/app/(booking-page-wrapper)/[user]/[type]/page.tsx @@ -5,7 +5,7 @@ import { generateMeetingMetadata } from "app/_utils"; import { headers, cookies } from "next/headers"; import { getOrgFullOrigin } from "@calcom/features/ee/organizations/lib/orgDomains"; -import { loadTranslations } from "@calcom/lib/server/i18n"; +import { loadTranslations } from "@calcom/i18n/server"; import { buildLegacyCtx, decodeParams } from "@lib/buildLegacyCtx"; diff --git a/apps/web/app/(booking-page-wrapper)/booking/[uid]/embed/page.tsx b/apps/web/app/(booking-page-wrapper)/booking/[uid]/embed/page.tsx index 28ae0e5d52..8c8f037b62 100644 --- a/apps/web/app/(booking-page-wrapper)/booking/[uid]/embed/page.tsx +++ b/apps/web/app/(booking-page-wrapper)/booking/[uid]/embed/page.tsx @@ -3,7 +3,7 @@ import withEmbedSsrAppDir from "app/WithEmbedSSR"; import type { PageProps as ServerPageProps } from "app/_types"; import { cookies, headers } from "next/headers"; -import { loadTranslations } from "@calcom/lib/server/i18n"; +import { loadTranslations } from "@calcom/i18n/server"; import { buildLegacyCtx } from "@lib/buildLegacyCtx"; diff --git a/apps/web/app/(booking-page-wrapper)/booking/[uid]/page.tsx b/apps/web/app/(booking-page-wrapper)/booking/[uid]/page.tsx index 534d6ab9f6..340fcfee9d 100644 --- a/apps/web/app/(booking-page-wrapper)/booking/[uid]/page.tsx +++ b/apps/web/app/(booking-page-wrapper)/booking/[uid]/page.tsx @@ -5,7 +5,7 @@ import { _generateMetadata } from "app/_utils"; import { cookies, headers } from "next/headers"; import { getOrgFullOrigin } from "@calcom/features/ee/organizations/lib/orgDomains"; -import { loadTranslations } from "@calcom/lib/server/i18n"; +import { loadTranslations } from "@calcom/i18n/server"; import { BookingStatus } from "@calcom/prisma/enums"; import { buildLegacyCtx } from "@lib/buildLegacyCtx"; diff --git a/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/[type]/embed/page.tsx b/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/[type]/embed/page.tsx index 8468d13020..c3c954b4c4 100644 --- a/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/[type]/embed/page.tsx +++ b/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/[type]/embed/page.tsx @@ -3,7 +3,7 @@ import withEmbedSsrAppDir from "app/WithEmbedSSR"; import type { PageProps as ServerPageProps } from "app/_types"; import { cookies, headers } from "next/headers"; -import { loadTranslations } from "@calcom/lib/server/i18n"; +import { loadTranslations } from "@calcom/i18n/server"; import { buildLegacyCtx } from "@lib/buildLegacyCtx"; import { getServerSideProps } from "@lib/org/[orgSlug]/[user]/[type]/getServerSideProps"; diff --git a/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/[type]/page.tsx b/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/[type]/page.tsx index a53bb39ad9..313e642349 100644 --- a/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/[type]/page.tsx +++ b/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/[type]/page.tsx @@ -5,7 +5,7 @@ import { generateMeetingMetadata } from "app/_utils"; import { cookies, headers } from "next/headers"; import { getOrgFullOrigin } from "@calcom/features/ee/organizations/lib/orgDomains"; -import { loadTranslations } from "@calcom/lib/server/i18n"; +import { loadTranslations } from "@calcom/i18n/server"; import { buildLegacyCtx, decodeParams } from "@lib/buildLegacyCtx"; import { getServerSideProps } from "@lib/org/[orgSlug]/[user]/[type]/getServerSideProps"; diff --git a/apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/embed/page.tsx b/apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/embed/page.tsx index accdf2efb2..be318f651d 100644 --- a/apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/embed/page.tsx +++ b/apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/embed/page.tsx @@ -3,7 +3,7 @@ import withEmbedSsrAppDir from "app/WithEmbedSSR"; import type { PageProps as ServerPageProps } from "app/_types"; import { cookies, headers } from "next/headers"; -import { loadTranslations } from "@calcom/lib/server/i18n"; +import { loadTranslations } from "@calcom/i18n/server"; import { buildLegacyCtx } from "@lib/buildLegacyCtx"; import { getServerSideProps } from "@lib/team/[slug]/[type]/getServerSideProps"; diff --git a/apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/page.tsx b/apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/page.tsx index 6d9885d51f..dd6e59d3d5 100644 --- a/apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/page.tsx +++ b/apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/page.tsx @@ -6,7 +6,7 @@ import { cookies, headers } from "next/headers"; import { getOrgFullOrigin } from "@calcom/features/ee/organizations/lib/orgDomains"; import { FeaturesRepository } from "@calcom/features/flags/features.repository"; -import { loadTranslations } from "@calcom/lib/server/i18n"; +import { loadTranslations } from "@calcom/i18n/server"; import { prisma } from "@calcom/prisma"; import { buildLegacyCtx, decodeParams } from "@lib/buildLegacyCtx"; diff --git a/apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/pageWithCachedData.tsx b/apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/pageWithCachedData.tsx index a783783532..2e488238dc 100644 --- a/apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/pageWithCachedData.tsx +++ b/apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/pageWithCachedData.tsx @@ -11,7 +11,7 @@ import { getOrgFullOrigin, orgDomainConfig } from "@calcom/features/ee/organizat import { getOrganizationSEOSettings } from "@calcom/features/ee/organizations/lib/orgSettings"; import type { TeamData } from "@calcom/features/ee/teams/lib/getTeamData"; import { shouldHideBrandingForTeamEvent } from "@calcom/features/profile/lib/hideBranding"; -import { loadTranslations } from "@calcom/lib/server/i18n"; +import { loadTranslations } from "@calcom/i18n/server"; import slugify from "@calcom/lib/slugify"; import { BookingStatus, RedirectType } from "@calcom/prisma/enums"; diff --git a/apps/web/app/_utils.tsx b/apps/web/app/_utils.tsx index 8efbd21dc2..d750f5180e 100644 --- a/apps/web/app/_utils.tsx +++ b/apps/web/app/_utils.tsx @@ -7,7 +7,7 @@ import { constructAppImage, constructGenericImage, constructMeetingImage } from import { IS_CALCOM, WEBAPP_URL, APP_NAME, SEO_IMG_OGIMG, CAL_URL } from "@calcom/lib/constants"; import { getCalcomUrl } from "@calcom/lib/getCalcomUrl"; import { buildCanonical } from "@calcom/lib/next-seo.config"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { truncateOnWord } from "@calcom/lib/text"; import { buildLegacyRequest } from "@lib/buildLegacyCtx"; diff --git a/apps/web/app/api/cron/bookingReminder/route.ts b/apps/web/app/api/cron/bookingReminder/route.ts index 373e3abd41..7046c463bd 100644 --- a/apps/web/app/api/cron/bookingReminder/route.ts +++ b/apps/web/app/api/cron/bookingReminder/route.ts @@ -7,7 +7,7 @@ import { sendOrganizerRequestReminderEmail } from "@calcom/emails/email-manager" import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses"; import { isPrismaObjOrUndefined } from "@calcom/lib/isPrismaObj"; import { parseRecurringEvent } from "@calcom/lib/isRecurringEvent"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import prisma, { bookingMinimalSelect } from "@calcom/prisma"; import { BookingStatus, ReminderType } from "@calcom/prisma/enums"; import type { EventTypeMetadata } from "@calcom/prisma/zod-utils"; diff --git a/apps/web/app/api/cron/monthlyDigestEmail/route.ts b/apps/web/app/api/cron/monthlyDigestEmail/route.ts index ce20c55262..1ab497e368 100644 --- a/apps/web/app/api/cron/monthlyDigestEmail/route.ts +++ b/apps/web/app/api/cron/monthlyDigestEmail/route.ts @@ -6,7 +6,7 @@ import { z } from "zod"; import dayjs from "@calcom/dayjs"; import { sendMonthlyDigestEmail } from "@calcom/emails/workflow-email-service"; import { EventsInsights } from "@calcom/features/insights/server/events"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import prisma from "@calcom/prisma"; import type { Prisma } from "@calcom/prisma/client"; diff --git a/apps/web/app/api/email/route.ts b/apps/web/app/api/email/route.ts index 6e48c5f859..d827daf66d 100644 --- a/apps/web/app/api/email/route.ts +++ b/apps/web/app/api/email/route.ts @@ -3,7 +3,7 @@ import { NextResponse } from "next/server"; import renderEmail from "@calcom/emails/src/renderEmail"; import { IS_PRODUCTION } from "@calcom/lib/constants"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; /** * This API endpoint is used for development purposes to preview email templates diff --git a/apps/web/app/layout.tsx b/apps/web/app/layout.tsx index d0003aca8f..3b2b77063a 100644 --- a/apps/web/app/layout.tsx +++ b/apps/web/app/layout.tsx @@ -1,5 +1,5 @@ import { getLocale } from "@calcom/features/auth/lib/getLocale"; -import { loadTranslations } from "@calcom/lib/server/i18n"; +import { loadTranslations } from "@calcom/i18n/server"; import { IconSprites } from "@calcom/ui/components/icon"; import { buildLegacyRequest } from "@lib/buildLegacyCtx"; import { dir } from "i18next"; diff --git a/apps/web/lib/daily-webhook/getCalendarEvent.ts b/apps/web/lib/daily-webhook/getCalendarEvent.ts index f28682a179..f474712883 100644 --- a/apps/web/lib/daily-webhook/getCalendarEvent.ts +++ b/apps/web/lib/daily-webhook/getCalendarEvent.ts @@ -1,4 +1,4 @@ -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import type { CalendarEvent } from "@calcom/types/Calendar"; import type { getBookingResponse } from "./getBooking"; diff --git a/apps/web/next-i18next.config.ts b/apps/web/next-i18next.config.ts deleted file mode 100644 index 1bd5c594ba..0000000000 --- a/apps/web/next-i18next.config.ts +++ /dev/null @@ -1,12 +0,0 @@ -import path from "node:path"; - -import i18nConfig from "@calcom/config/next-i18next.config"; - -import type { UserConfig } from "next-i18next"; - -const config: UserConfig = { - ...i18nConfig, - localePath: path.resolve("./public/static/locales"), -}; - -export default config; diff --git a/apps/web/next.config.ts b/apps/web/next.config.ts index 599d8ff108..e216d116e7 100644 --- a/apps/web/next.config.ts +++ b/apps/web/next.config.ts @@ -3,7 +3,7 @@ import { config as dotenvConfig } from "dotenv"; import type { NextConfig } from "next"; import type { RouteHas } from "next/dist/lib/load-custom-routes"; import { withAxiom } from "next-axiom"; -import i18nConfig from "./next-i18next.config"; +import i18nConfig from "@calcom/i18n/next-i18next.config"; import packageJson from "./package.json"; import { nextJsOrgRewriteConfig, diff --git a/apps/web/playwright/lib/localize.ts b/apps/web/playwright/lib/localize.ts index 2afc3d46d3..76831160e1 100644 --- a/apps/web/playwright/lib/localize.ts +++ b/apps/web/playwright/lib/localize.ts @@ -2,7 +2,7 @@ import { loadJSON } from "./loadJSON"; // Provide an standalone localize utility not managed by next-i18n export async function localize(locale: string) { - const localeModule = `../../public/static/locales/${locale}/common.json`; + const localeModule = `../../../../packages/i18n/locales/${locale}/common.json`; const localeMap = loadJSON(localeModule); return (message: string) => { if (message in localeMap) return localeMap[message]; diff --git a/apps/web/public/robots.txt b/apps/web/public/robots.txt index bcc8a1c0c0..6b66f98e6a 100644 --- a/apps/web/public/robots.txt +++ b/apps/web/public/robots.txt @@ -1,7 +1,6 @@ User-agent: * Disallow: /sandbox Disallow: /api -Disallow: /static/locales Disallow: /settings Disallow: /settings/my-account diff --git a/apps/web/scripts/check-missing-translations.ts b/apps/web/scripts/check-missing-translations.ts index d16a1e06c0..e90e6d66a2 100644 --- a/apps/web/scripts/check-missing-translations.ts +++ b/apps/web/scripts/check-missing-translations.ts @@ -1,9 +1,10 @@ -import { readFileSync, readdirSync, writeFileSync } from "node:fs"; +import { readdirSync, readFileSync, writeFileSync } from "node:fs"; import { join } from "node:path"; +import process from "node:process"; const TEMPLATE_LANGUAGE = "en"; const SPECIFIC_LOCALES = process.argv.slice(2) || []; -const LOCALES_PATH = join(__dirname, "../public/static/locales"); +const LOCALES_PATH = join(__dirname, "../../../packages/i18n/locales"); const ALL_LOCALES = readdirSync(LOCALES_PATH); @@ -11,7 +12,7 @@ const templateJsonPath = join(LOCALES_PATH, `${TEMPLATE_LANGUAGE}/common.json`); const templateJson: { [key: string]: string } = JSON.parse(readFileSync(templateJsonPath, "utf-8")); const missingTranslationLocales: string[] = []; -// If locales are not specified, then check all folders under `public/static/locales` +// If locales are not specified, then check all folders under the locales directory (SPECIFIC_LOCALES.length ? SPECIFIC_LOCALES : ALL_LOCALES).forEach((locale: string) => { if (locale === TEMPLATE_LANGUAGE) return; if (!ALL_LOCALES.includes(locale)) { diff --git a/apps/web/test/lib/handleChildrenEventTypes.test.ts b/apps/web/test/lib/handleChildrenEventTypes.test.ts index e4e98f4b3a..f519bbb911 100644 --- a/apps/web/test/lib/handleChildrenEventTypes.test.ts +++ b/apps/web/test/lib/handleChildrenEventTypes.test.ts @@ -47,7 +47,7 @@ vi.mock("@calcom/emails/integration-email-service", () => { }; }); -vi.mock("@calcom/lib/server/i18n", () => { +vi.mock("@calcom/i18n/server", () => { return { getTranslation: async (locale: string, namespace: string) => { const t = (key: string) => key; diff --git a/i18n-unused.config.js b/i18n-unused.config.js index 2b7f3a837d..2fa597efb6 100644 --- a/i18n-unused.config.js +++ b/i18n-unused.config.js @@ -23,7 +23,7 @@ const translationKeyRegex = /(? ({ getBookerBaseUrl: vi.fn(async () => "https://cal.com"), })); -vi.mock("@calcom/lib/server/i18n", () => ({ +vi.mock("@calcom/i18n/server", () => ({ getTranslation: vi.fn(async () => vi.fn(() => "translated")), })); diff --git a/packages/features/CalendarEventBuilder.ts b/packages/features/CalendarEventBuilder.ts index 41aba2b776..4dce693bda 100644 --- a/packages/features/CalendarEventBuilder.ts +++ b/packages/features/CalendarEventBuilder.ts @@ -6,7 +6,7 @@ import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventR import type { BookingRepository } from "@calcom/features/bookings/repositories/BookingRepository"; import { getBookerBaseUrl } from "@calcom/features/ee/organizations/lib/getBookerUrlServer"; import { parseRecurringEvent } from "@calcom/lib/isRecurringEvent"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { getTimeFormatStringFromUserTimeFormat, type TimeFormat } from "@calcom/lib/timeFormat"; import type { Attendee, BookingSeat, DestinationCalendar, Prisma, User } from "@calcom/prisma/client"; import { SchedulingType } from "@calcom/prisma/enums"; diff --git a/packages/features/auth/lib/getLocale.ts b/packages/features/auth/lib/getLocale.ts index 4f5bbe9cec..c4048d5767 100644 --- a/packages/features/auth/lib/getLocale.ts +++ b/packages/features/auth/lib/getLocale.ts @@ -3,7 +3,7 @@ import { lookup } from "bcp-47-match"; import type { GetTokenParams } from "next-auth/jwt"; import { getToken } from "next-auth/jwt"; -import { i18n } from "@calcom/config/next-i18next.config"; +import { i18n } from "@calcom/i18n/next-i18next.config"; type ReadonlyHeaders = Awaited>; type ReadonlyRequestCookies = Awaited>; diff --git a/packages/features/auth/lib/getLocaleFromRequest.ts b/packages/features/auth/lib/getLocaleFromRequest.ts index 957ddb29ce..d1f716ae4c 100644 --- a/packages/features/auth/lib/getLocaleFromRequest.ts +++ b/packages/features/auth/lib/getLocaleFromRequest.ts @@ -5,7 +5,7 @@ import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; type Maybe = T | null | undefined; -const { i18n } = require("@calcom/config/next-i18next.config"); +const { i18n } = require("@calcom/i18n/next-i18next.config"); export async function getLocaleFromRequest( req: NextApiRequest | GetServerSidePropsContext["req"] diff --git a/packages/features/auth/lib/passwordResetRequest.ts b/packages/features/auth/lib/passwordResetRequest.ts index 74b069023a..a3bc199cce 100644 --- a/packages/features/auth/lib/passwordResetRequest.ts +++ b/packages/features/auth/lib/passwordResetRequest.ts @@ -1,5 +1,5 @@ import dayjs from "@calcom/dayjs"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import prisma from "@calcom/prisma"; import type { User } from "@calcom/prisma/client"; diff --git a/packages/features/auth/lib/verifyEmail.ts b/packages/features/auth/lib/verifyEmail.ts index 411858f8e1..f35b9d389a 100644 --- a/packages/features/auth/lib/verifyEmail.ts +++ b/packages/features/auth/lib/verifyEmail.ts @@ -13,7 +13,7 @@ import { checkRateLimitAndThrowError } from "@calcom/lib/checkRateLimitAndThrowE import { WEBAPP_URL } from "@calcom/lib/constants"; import logger from "@calcom/lib/logger"; import { hashEmail } from "@calcom/lib/server/PiiHasher"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { prisma } from "@calcom/prisma"; const log = logger.getSubLogger({ prefix: [`[[Auth] `] }); diff --git a/packages/features/auth/package.json b/packages/features/auth/package.json index 0e6560b553..7006a4f00d 100644 --- a/packages/features/auth/package.json +++ b/packages/features/auth/package.json @@ -8,6 +8,7 @@ "main": "index.ts", "dependencies": { "@calcom/dayjs": "workspace:*", + "@calcom/i18n": "workspace:*", "@calcom/lib": "workspace:*", "@calcom/prisma": "workspace:*", "@calcom/trpc": "workspace:*", diff --git a/packages/features/booking-audit/lib/actions/LocationChangedAuditActionService.ts b/packages/features/booking-audit/lib/actions/LocationChangedAuditActionService.ts index 0e7b869c62..70380ac0d9 100644 --- a/packages/features/booking-audit/lib/actions/LocationChangedAuditActionService.ts +++ b/packages/features/booking-audit/lib/actions/LocationChangedAuditActionService.ts @@ -9,7 +9,7 @@ import type { TranslationWithParams, GetDisplayTitleParams, } from "./IAuditActionService"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; /** * Location Changed Audit Action Service * Handles LOCATION_CHANGED action with per-action versioning diff --git a/packages/features/bookings/lib/BookingEmailSmsHandler.ts b/packages/features/bookings/lib/BookingEmailSmsHandler.ts index 6add256673..95da16025f 100644 --- a/packages/features/bookings/lib/BookingEmailSmsHandler.ts +++ b/packages/features/bookings/lib/BookingEmailSmsHandler.ts @@ -8,7 +8,7 @@ import type { BookingType } from "@calcom/features/bookings/lib/handleNewBooking import type { EventNameObjectType } from "@calcom/features/eventtypes/lib/eventNaming"; import { getPiiFreeCalendarEvent } from "@calcom/lib/piiFreeData"; import { safeStringify } from "@calcom/lib/safeStringify"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat"; import type { Prisma, User } from "@calcom/prisma/client"; import type { SchedulingType } from "@calcom/prisma/enums"; diff --git a/packages/features/bookings/lib/handleCancelBooking.ts b/packages/features/bookings/lib/handleCancelBooking.ts index 827ee3e434..9291e3244f 100644 --- a/packages/features/bookings/lib/handleCancelBooking.ts +++ b/packages/features/bookings/lib/handleCancelBooking.ts @@ -41,7 +41,7 @@ import { isPrismaObjOrUndefined } from "@calcom/lib/isPrismaObj"; import { parseRecurringEvent } from "@calcom/lib/isRecurringEvent"; import logger from "@calcom/lib/logger"; import { safeStringify } from "@calcom/lib/safeStringify"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat"; // TODO: Prisma import would be used from DI in a followup PR when we remove `handler` export import prisma from "@calcom/prisma"; diff --git a/packages/features/bookings/lib/handleNewBooking/test/buildEventForTeamEventType.test.ts b/packages/features/bookings/lib/handleNewBooking/test/buildEventForTeamEventType.test.ts index 1a8b6e68e6..efb5445b62 100644 --- a/packages/features/bookings/lib/handleNewBooking/test/buildEventForTeamEventType.test.ts +++ b/packages/features/bookings/lib/handleNewBooking/test/buildEventForTeamEventType.test.ts @@ -5,7 +5,7 @@ import { SchedulingType } from "@calcom/prisma/enums"; import { buildEventForTeamEventType } from "../../service/RegularBookingService"; -vi.mock("@calcom/lib/server/i18n", () => ({ +vi.mock("@calcom/i18n/server", () => ({ getTranslation: vi.fn().mockResolvedValue("translated"), })); diff --git a/packages/features/bookings/lib/handleSeats/cancel/cancelAttendeeSeat.ts b/packages/features/bookings/lib/handleSeats/cancel/cancelAttendeeSeat.ts index 1d3d14f818..4bf293101d 100644 --- a/packages/features/bookings/lib/handleSeats/cancel/cancelAttendeeSeat.ts +++ b/packages/features/bookings/lib/handleSeats/cancel/cancelAttendeeSeat.ts @@ -13,7 +13,7 @@ import { getRichDescription } from "@calcom/lib/CalEventParser"; import { HttpError } from "@calcom/lib/http-error"; import logger from "@calcom/lib/logger"; import { safeStringify } from "@calcom/lib/safeStringify"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import prisma from "@calcom/prisma"; import { WebhookTriggerEvents } from "@calcom/prisma/enums"; import type { EventTypeMetadata } from "@calcom/prisma/zod-utils"; diff --git a/packages/features/bookings/lib/handleSeats/reschedule/attendee/attendeeRescheduleSeatedBooking.ts b/packages/features/bookings/lib/handleSeats/reschedule/attendee/attendeeRescheduleSeatedBooking.ts index 2907fe8471..0a0d4319d8 100644 --- a/packages/features/bookings/lib/handleSeats/reschedule/attendee/attendeeRescheduleSeatedBooking.ts +++ b/packages/features/bookings/lib/handleSeats/reschedule/attendee/attendeeRescheduleSeatedBooking.ts @@ -3,7 +3,7 @@ import { cloneDeep } from "lodash"; import { sendRescheduledSeatEmailAndSMS } from "@calcom/emails/email-manager"; import type EventManager from "@calcom/features/bookings/lib/EventManager"; import { addVideoCallDataToEvent } from "@calcom/features/bookings/lib/handleNewBooking/addVideoCallDataToEvent"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import prisma from "@calcom/prisma"; import type { Person, CalendarEvent } from "@calcom/types/Calendar"; diff --git a/packages/features/bookings/lib/payment/getBooking.ts b/packages/features/bookings/lib/payment/getBooking.ts index b5c556fc1f..53cacd33cf 100644 --- a/packages/features/bookings/lib/payment/getBooking.ts +++ b/packages/features/bookings/lib/payment/getBooking.ts @@ -5,7 +5,7 @@ import { getBookerBaseUrl } from "@calcom/features/ee/organizations/lib/getBooke import { HttpError as HttpCode } from "@calcom/lib/http-error"; import { isPrismaObjOrUndefined } from "@calcom/lib/isPrismaObj"; import { parseRecurringEvent } from "@calcom/lib/isRecurringEvent"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat"; import { bookingMinimalSelect, prisma } from "@calcom/prisma"; import { credentialForCalendarServiceSelect } from "@calcom/prisma/selects/credential"; diff --git a/packages/features/bookings/lib/payment/handleNoShowFee.test.ts b/packages/features/bookings/lib/payment/handleNoShowFee.test.ts index dfcaf3e54a..99d0b4d722 100644 --- a/packages/features/bookings/lib/payment/handleNoShowFee.test.ts +++ b/packages/features/bookings/lib/payment/handleNoShowFee.test.ts @@ -6,7 +6,7 @@ import { CredentialRepository } from "@calcom/features/credentials/repositories/ import { TeamRepository } from "@calcom/features/ee/teams/repositories/TeamRepository"; import { ErrorCode } from "@calcom/lib/errorCodes"; import { ErrorWithCode } from "@calcom/lib/errors"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { handleNoShowFee } from "./handleNoShowFee"; @@ -26,7 +26,7 @@ vi.mock("@calcom/emails/billing-email-service", () => ({ sendNoShowFeeChargedEmail: vi.fn(), })); -vi.mock("@calcom/lib/server/i18n", () => ({ +vi.mock("@calcom/i18n/server", () => ({ getTranslation: vi.fn().mockResolvedValue((key: string) => key), })); diff --git a/packages/features/bookings/lib/payment/handleNoShowFee.ts b/packages/features/bookings/lib/payment/handleNoShowFee.ts index 67892f7dff..fd68034069 100644 --- a/packages/features/bookings/lib/payment/handleNoShowFee.ts +++ b/packages/features/bookings/lib/payment/handleNoShowFee.ts @@ -8,7 +8,7 @@ import { MembershipRepository } from "@calcom/features/membership/repositories/M import { ErrorCode } from "@calcom/lib/errorCodes"; import { ErrorWithCode } from "@calcom/lib/errors"; import logger from "@calcom/lib/logger"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import prisma from "@calcom/prisma"; import type { Prisma } from "@calcom/prisma/client"; import type { CalendarEvent } from "@calcom/types/Calendar"; diff --git a/packages/features/bookings/lib/service/InstantBookingCreateService.ts b/packages/features/bookings/lib/service/InstantBookingCreateService.ts index 0b46539772..797c2ab6a6 100644 --- a/packages/features/bookings/lib/service/InstantBookingCreateService.ts +++ b/packages/features/bookings/lib/service/InstantBookingCreateService.ts @@ -21,7 +21,7 @@ import { WEBAPP_URL } from "@calcom/lib/constants"; import getOrgIdFromMemberOrTeamId from "@calcom/lib/getOrgIdFromMemberOrTeamId"; import { isPrismaObjOrUndefined } from "@calcom/lib/isPrismaObj"; import logger from "@calcom/lib/logger"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import type { PrismaClient } from "@calcom/prisma"; import { Prisma } from "@calcom/prisma/client"; import { BookingStatus, WebhookTriggerEvents } from "@calcom/prisma/enums"; diff --git a/packages/features/bookings/lib/service/RegularBookingService.ts b/packages/features/bookings/lib/service/RegularBookingService.ts index 63ad85dc65..819a0bc421 100644 --- a/packages/features/bookings/lib/service/RegularBookingService.ts +++ b/packages/features/bookings/lib/service/RegularBookingService.ts @@ -78,7 +78,7 @@ import { criticalLogger } from "@calcom/lib/logger.server"; import { getPiiFreeCalendarEvent, getPiiFreeEventType } from "@calcom/lib/piiFreeData"; import { safeStringify } from "@calcom/lib/safeStringify"; import { getServerErrorFromUnknown } from "@calcom/lib/server/getServerErrorFromUnknown"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat"; import { distributedTracing } from "@calcom/lib/tracing/factory"; import type { PrismaClient } from "@calcom/prisma"; diff --git a/packages/features/bookings/services/WrongAssignmentReportService.ts b/packages/features/bookings/services/WrongAssignmentReportService.ts index 9f2b875bf2..840b4b7491 100644 --- a/packages/features/bookings/services/WrongAssignmentReportService.ts +++ b/packages/features/bookings/services/WrongAssignmentReportService.ts @@ -3,7 +3,7 @@ import getWebhooks from "@calcom/features/webhooks/lib/getWebhooks"; import { sendGenericWebhookPayload } from "@calcom/features/webhooks/lib/sendPayload"; import { ErrorWithCode } from "@calcom/lib/errors"; import logger from "@calcom/lib/logger"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { Prisma } from "@calcom/prisma/client"; import { WebhookTriggerEvents } from "@calcom/prisma/enums"; import type { WrongAssignmentReportStatus } from "@calcom/prisma/enums"; diff --git a/packages/features/credentials/handleDeleteCredential.ts b/packages/features/credentials/handleDeleteCredential.ts index ee9b7f71cf..61958bd082 100644 --- a/packages/features/credentials/handleDeleteCredential.ts +++ b/packages/features/credentials/handleDeleteCredential.ts @@ -15,7 +15,7 @@ import { deleteWebhookScheduledTriggers } from "@calcom/features/webhooks/lib/sc import { buildNonDelegationCredential } from "@calcom/lib/delegationCredential"; import { isPrismaObjOrUndefined } from "@calcom/lib/isPrismaObj"; import { parseRecurringEvent } from "@calcom/lib/isRecurringEvent"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { bookingMinimalSelect, prisma } from "@calcom/prisma"; import type { Prisma } from "@calcom/prisma/client"; import { AppCategories, BookingStatus } from "@calcom/prisma/enums"; diff --git a/packages/features/ee/billing/credit-service.test.ts b/packages/features/ee/billing/credit-service.test.ts index 957e531b6b..34dd85e74d 100644 --- a/packages/features/ee/billing/credit-service.test.ts +++ b/packages/features/ee/billing/credit-service.test.ts @@ -58,7 +58,7 @@ vi.mock("@calcom/features/ee/payments/server/stripe", () => ({ default: mockStripe, })); -vi.mock("@calcom/lib/server/i18n", () => { +vi.mock("@calcom/i18n/server", () => { return { getTranslation: async (locale: string, namespace: string) => { const t = (key: string) => key; diff --git a/packages/features/ee/billing/credit-service.ts b/packages/features/ee/billing/credit-service.ts index 75979f362a..4a62918c6c 100644 --- a/packages/features/ee/billing/credit-service.ts +++ b/packages/features/ee/billing/credit-service.ts @@ -512,7 +512,7 @@ export class CreditService { return null; // user has limit already reached or team has already reached limit this month } - const { getTranslation } = await import("@calcom/lib/server/i18n"); + const { getTranslation } = await import("@calcom/i18n/server"); const teamWithAdmins = creditBalance?.team ? { diff --git a/packages/features/ee/billing/helpers/getUserAndTeamWithBillingPermission.ts b/packages/features/ee/billing/helpers/getUserAndTeamWithBillingPermission.ts index 31dea651a7..a01aa92eaa 100644 --- a/packages/features/ee/billing/helpers/getUserAndTeamWithBillingPermission.ts +++ b/packages/features/ee/billing/helpers/getUserAndTeamWithBillingPermission.ts @@ -2,7 +2,7 @@ import type { TFunction } from "i18next"; import { TeamRepository } from "@calcom/features/ee/teams/repositories/TeamRepository"; import { UserRepository } from "@calcom/features/users/repositories/UserRepository"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import type { PrismaClient } from "@calcom/prisma"; import { MembershipRole } from "@calcom/prisma/enums"; diff --git a/packages/features/ee/billing/package.json b/packages/features/ee/billing/package.json index cfd8577471..4de07dd53d 100644 --- a/packages/features/ee/billing/package.json +++ b/packages/features/ee/billing/package.json @@ -4,5 +4,7 @@ "authors": "zomars", "version": "1.0.0", "main": "./index.js", - "dependencies": {} + "dependencies": { + "@calcom/i18n": "workspace:*" + } } diff --git a/packages/features/ee/dsync/lib/handleGroupEvents.ts b/packages/features/ee/dsync/lib/handleGroupEvents.ts index a51b1d228c..69ae6efb16 100644 --- a/packages/features/ee/dsync/lib/handleGroupEvents.ts +++ b/packages/features/ee/dsync/lib/handleGroupEvents.ts @@ -8,7 +8,7 @@ import { addNewMembersToEventTypes } from "@calcom/features/ee/teams/lib/queries import { ProfileRepository } from "@calcom/features/profile/repositories/ProfileRepository"; import logger from "@calcom/lib/logger"; import { safeStringify } from "@calcom/lib/safeStringify"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import prisma from "@calcom/prisma"; import { IdentityProvider, MembershipRole } from "@calcom/prisma/enums"; import createUsersAndConnectToOrg from "./users/createUsersAndConnectToOrg"; diff --git a/packages/features/ee/dsync/lib/handleUserEvents.test.ts b/packages/features/ee/dsync/lib/handleUserEvents.test.ts index a13fe2071f..f534607659 100644 --- a/packages/features/ee/dsync/lib/handleUserEvents.test.ts +++ b/packages/features/ee/dsync/lib/handleUserEvents.test.ts @@ -17,7 +17,7 @@ vi.mock("@calcom/lib/logger", () => ({ }, })); -vi.mock("@calcom/lib/server/i18n", () => ({ +vi.mock("@calcom/i18n/server", () => ({ getTranslation: vi.fn().mockResolvedValue((key: string) => key), })); diff --git a/packages/features/ee/dsync/lib/handleUserEvents.ts b/packages/features/ee/dsync/lib/handleUserEvents.ts index 10d9a16a93..dbadf63404 100644 --- a/packages/features/ee/dsync/lib/handleUserEvents.ts +++ b/packages/features/ee/dsync/lib/handleUserEvents.ts @@ -9,7 +9,7 @@ import { import { UserRepository } from "@calcom/features/users/repositories/UserRepository"; import logger from "@calcom/lib/logger"; import { safeStringify } from "@calcom/lib/safeStringify"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import prisma from "@calcom/prisma"; import { IdentityProvider } from "@calcom/prisma/enums"; import { assignValueToUserInOrgBulk } from "./assignValueToUser"; diff --git a/packages/features/ee/managed-event-types/lib/handleChildrenEventTypes.ts b/packages/features/ee/managed-event-types/lib/handleChildrenEventTypes.ts index 09f889ceac..af52cf579d 100644 --- a/packages/features/ee/managed-event-types/lib/handleChildrenEventTypes.ts +++ b/packages/features/ee/managed-event-types/lib/handleChildrenEventTypes.ts @@ -3,7 +3,7 @@ import type { DeepMockProxy } from "vitest-mock-extended"; import { eventTypeMetaDataSchemaWithTypedApps } from "@calcom/app-store/zod-utils"; import { sendSlugReplacementEmail } from "@calcom/emails/integration-email-service"; import logger from "@calcom/lib/logger"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import type { PrismaClient } from "@calcom/prisma"; import type { EventType, Prisma } from "@calcom/prisma/client"; import { SchedulingType } from "@calcom/prisma/enums"; diff --git a/packages/features/ee/managed-event-types/reassignment/services/ManagedEventManualReassignmentService.ts b/packages/features/ee/managed-event-types/reassignment/services/ManagedEventManualReassignmentService.ts index b462c6818d..34928bae29 100644 --- a/packages/features/ee/managed-event-types/reassignment/services/ManagedEventManualReassignmentService.ts +++ b/packages/features/ee/managed-event-types/reassignment/services/ManagedEventManualReassignmentService.ts @@ -285,7 +285,7 @@ export class ManagedEventManualReassignmentService { throw new Error("Original booking not found"); } - const { getTranslation } = await import("@calcom/lib/server/i18n"); + const { getTranslation } = await import("@calcom/i18n/server"); const newUserT = await getTranslation(newUser.locale ?? "en", "common"); const originalUserT = await getTranslation(originalUser.locale ?? "en", "common"); @@ -351,7 +351,7 @@ export class ManagedEventManualReassignmentService { originalBookingFull: NonNullable< Awaited> >; - originalUserT: Awaited>; + originalUserT: Awaited>; apps: ReturnType; logger: ReturnType; }) { @@ -405,7 +405,7 @@ export class ManagedEventManualReassignmentService { logger, }: { newUser: NonNullable>>; - newUserT: Awaited>; + newUserT: Awaited>; targetEventTypeDetails: NonNullable>>; newBooking: ManagedEventReassignmentCreatedBooking; originalBookingFull: NonNullable< @@ -656,9 +656,9 @@ export class ManagedEventManualReassignmentService { targetEventTypeDetails: NonNullable>>; parentEventType: Awaited>["parentEventType"]; newUser: NonNullable>>; - newUserT: Awaited>; + newUserT: Awaited>; originalUser: NonNullable>>; - originalUserT: Awaited>; + originalUserT: Awaited>; bookingLocation: string | null; videoCallData: CalendarEvent["videoCallData"]; additionalInformation: AdditionalInformation; diff --git a/packages/features/ee/managed-event-types/reassignment/utils/buildNewBookingPlan.ts b/packages/features/ee/managed-event-types/reassignment/utils/buildNewBookingPlan.ts index 5712c114e4..51f9bba983 100644 --- a/packages/features/ee/managed-event-types/reassignment/utils/buildNewBookingPlan.ts +++ b/packages/features/ee/managed-event-types/reassignment/utils/buildNewBookingPlan.ts @@ -16,7 +16,7 @@ interface BuildNewBookingPlanParams { >; targetEventTypeDetails: NonNullable>>; newUser: NonNullable>>; - newUserT: Awaited>; + newUserT: Awaited>; reassignedById: number; } diff --git a/packages/features/ee/organizations/lib/service/onboarding/BaseOnboardingService.ts b/packages/features/ee/organizations/lib/service/onboarding/BaseOnboardingService.ts index f8f3b86ed5..4aef118750 100644 --- a/packages/features/ee/organizations/lib/service/onboarding/BaseOnboardingService.ts +++ b/packages/features/ee/organizations/lib/service/onboarding/BaseOnboardingService.ts @@ -17,7 +17,7 @@ import { WEBAPP_URL } from "@calcom/lib/constants"; import logger from "@calcom/lib/logger"; import { safeStringify } from "@calcom/lib/safeStringify"; import { uploadLogo } from "@calcom/lib/server/avatar"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { isBase64Image, resizeBase64Image } from "@calcom/lib/server/resizeBase64Image"; import slugify from "@calcom/lib/slugify"; import { prisma } from "@calcom/prisma"; diff --git a/packages/features/ee/organizations/lib/service/onboarding/BillingEnabledOrgOnboardingService.ts b/packages/features/ee/organizations/lib/service/onboarding/BillingEnabledOrgOnboardingService.ts index 9f5d0b2390..940f82034c 100644 --- a/packages/features/ee/organizations/lib/service/onboarding/BillingEnabledOrgOnboardingService.ts +++ b/packages/features/ee/organizations/lib/service/onboarding/BillingEnabledOrgOnboardingService.ts @@ -4,7 +4,7 @@ import { OrganizationOnboardingRepository } from "@calcom/features/organizations import { IS_SELF_HOSTED } from "@calcom/lib/constants"; import logger from "@calcom/lib/logger"; import { safeStringify } from "@calcom/lib/safeStringify"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import type { Team, User } from "@calcom/prisma/client"; import { orgOnboardingInvitedMembersSchema, orgOnboardingTeamsSchema } from "@calcom/prisma/zod-utils"; diff --git a/packages/features/ee/organizations/lib/service/onboarding/SelfHostedOnboardingService.ts b/packages/features/ee/organizations/lib/service/onboarding/SelfHostedOnboardingService.ts index ecfdbd0b93..a48f939f6f 100644 --- a/packages/features/ee/organizations/lib/service/onboarding/SelfHostedOnboardingService.ts +++ b/packages/features/ee/organizations/lib/service/onboarding/SelfHostedOnboardingService.ts @@ -6,7 +6,7 @@ import { OrganizationOnboardingRepository } from "@calcom/features/organizations import { IS_SELF_HOSTED } from "@calcom/lib/constants"; import logger from "@calcom/lib/logger"; import { safeStringify } from "@calcom/lib/safeStringify"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { prisma } from "@calcom/prisma"; import type { Team, User } from "@calcom/prisma/client"; import { BillingPeriod } from "@calcom/prisma/enums"; diff --git a/packages/features/ee/organizations/lib/service/onboarding/__tests__/BillingEnabledOrgOnboardingService.test.ts b/packages/features/ee/organizations/lib/service/onboarding/__tests__/BillingEnabledOrgOnboardingService.test.ts index db271dc081..4e86840973 100644 --- a/packages/features/ee/organizations/lib/service/onboarding/__tests__/BillingEnabledOrgOnboardingService.test.ts +++ b/packages/features/ee/organizations/lib/service/onboarding/__tests__/BillingEnabledOrgOnboardingService.test.ts @@ -33,7 +33,7 @@ vi.mock("@calcom/lib/domainManager/organization", () => ({ createDomain: vi.fn(), })); -vi.mock("@calcom/lib/server/i18n", () => { +vi.mock("@calcom/i18n/server", () => { return { getTranslation: async (locale: string, namespace: string) => { const t = (key: string) => key; diff --git a/packages/features/ee/organizations/lib/service/onboarding/__tests__/SelfHostedOnboardingService.test.ts b/packages/features/ee/organizations/lib/service/onboarding/__tests__/SelfHostedOnboardingService.test.ts index 284dd45d5f..54dce512b9 100644 --- a/packages/features/ee/organizations/lib/service/onboarding/__tests__/SelfHostedOnboardingService.test.ts +++ b/packages/features/ee/organizations/lib/service/onboarding/__tests__/SelfHostedOnboardingService.test.ts @@ -40,7 +40,7 @@ vi.mock("@calcom/lib/domainManager/organization", () => ({ createDomain: vi.fn(), })); -vi.mock("@calcom/lib/server/i18n", () => { +vi.mock("@calcom/i18n/server", () => { return { getTranslation: async (locale: string, namespace: string) => { const t = (key: string) => key; diff --git a/packages/features/ee/package.json b/packages/features/ee/package.json index 02b069dd24..8bf5d96ec8 100644 --- a/packages/features/ee/package.json +++ b/packages/features/ee/package.json @@ -6,6 +6,7 @@ "license": "See license in LICENSE", "main": "./index.ts", "dependencies": { + "@calcom/i18n": "workspace:*", "@calcom/lib": "workspace:*", "@calcom/ui": "workspace:*", "@hookform/error-message": "2.0.0", diff --git a/packages/features/ee/round-robin/handleRescheduleEventManager.ts b/packages/features/ee/round-robin/handleRescheduleEventManager.ts index 071a3135fe..7dc38ddc03 100644 --- a/packages/features/ee/round-robin/handleRescheduleEventManager.ts +++ b/packages/features/ee/round-robin/handleRescheduleEventManager.ts @@ -9,7 +9,7 @@ import type { EventType } from "@calcom/features/bookings/lib/getAllCredentialsF import { getVideoCallDetails } from "@calcom/features/bookings/lib/handleNewBooking/getVideoCallDetails"; import { getVideoCallUrlFromCalEvent } from "@calcom/lib/CalEventParser"; import logger from "@calcom/lib/logger"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { prisma } from "@calcom/prisma"; import type { DestinationCalendar } from "@calcom/prisma/client"; import type { Prisma } from "@calcom/prisma/client"; diff --git a/packages/features/ee/round-robin/roundRobinManualReassignment.ts b/packages/features/ee/round-robin/roundRobinManualReassignment.ts index 4f9965227b..27d1ddf8ec 100644 --- a/packages/features/ee/round-robin/roundRobinManualReassignment.ts +++ b/packages/features/ee/round-robin/roundRobinManualReassignment.ts @@ -32,7 +32,7 @@ import { SENDER_NAME } from "@calcom/lib/constants"; import { IdempotencyKeyService } from "@calcom/lib/idempotencyKey/idempotencyKeyService"; import { isPrismaObjOrUndefined } from "@calcom/lib/isPrismaObj"; import logger from "@calcom/lib/logger"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat"; import { prisma } from "@calcom/prisma"; import { WorkflowActions, WorkflowMethods, WorkflowTriggerEvents } from "@calcom/prisma/enums"; diff --git a/packages/features/ee/round-robin/roundRobinReassignment.ts b/packages/features/ee/round-robin/roundRobinReassignment.ts index d32c4e05ba..57c896b69a 100644 --- a/packages/features/ee/round-robin/roundRobinReassignment.ts +++ b/packages/features/ee/round-robin/roundRobinReassignment.ts @@ -30,7 +30,7 @@ import { ErrorCode } from "@calcom/lib/errorCodes"; import { IdempotencyKeyService } from "@calcom/lib/idempotencyKey/idempotencyKeyService"; import { isPrismaObjOrUndefined } from "@calcom/lib/isPrismaObj"; import logger from "@calcom/lib/logger"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat"; import { prisma } from "@calcom/prisma"; import type { EventTypeMetadata, PlatformClientParams } from "@calcom/prisma/zod-utils"; diff --git a/packages/features/ee/round-robin/utils/getTeamMembers.ts b/packages/features/ee/round-robin/utils/getTeamMembers.ts index 6ef67d556b..c4e594dbf8 100644 --- a/packages/features/ee/round-robin/utils/getTeamMembers.ts +++ b/packages/features/ee/round-robin/utils/getTeamMembers.ts @@ -1,6 +1,6 @@ import type { getEventTypeResponse } from "@calcom/features/bookings/lib/handleNewBooking/getEventTypesFromDB"; import type { IsFixedAwareUser } from "@calcom/features/bookings/lib/handleNewBooking/types"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import type { BookingSelectResult } from "./bookingSelect"; diff --git a/packages/features/ee/workflows/api/scheduleEmailReminders.ts b/packages/features/ee/workflows/api/scheduleEmailReminders.ts index a51c17a266..cb8e26c3c8 100644 --- a/packages/features/ee/workflows/api/scheduleEmailReminders.ts +++ b/packages/features/ee/workflows/api/scheduleEmailReminders.ts @@ -10,7 +10,7 @@ import { BookingSeatRepository } from "@calcom/features/bookings/repositories/Bo import { getBookerBaseUrl } from "@calcom/features/ee/organizations/lib/getBookerUrlServer"; import logger from "@calcom/lib/logger"; import { safeStringify } from "@calcom/lib/safeStringify"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat"; import prisma from "@calcom/prisma"; import { SchedulingType, WorkflowActions, WorkflowTemplates } from "@calcom/prisma/enums"; diff --git a/packages/features/ee/workflows/api/scheduleSMSReminders.ts b/packages/features/ee/workflows/api/scheduleSMSReminders.ts index f8ddb99c08..212b6cbbb9 100644 --- a/packages/features/ee/workflows/api/scheduleSMSReminders.ts +++ b/packages/features/ee/workflows/api/scheduleSMSReminders.ts @@ -10,7 +10,7 @@ import { CreditService } from "@calcom/features/ee/billing/credit-service"; import { getBookerBaseUrl } from "@calcom/features/ee/organizations/lib/getBookerUrlServer"; import { isAttendeeAction } from "@calcom/features/ee/workflows/lib/actionHelperFunctions"; import { scheduleSmsOrFallbackEmail } from "@calcom/features/ee/workflows/lib/reminders/messageDispatcher"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat"; import prisma from "@calcom/prisma"; import { WorkflowActions, WorkflowMethods, WorkflowTemplates } from "@calcom/prisma/enums"; diff --git a/packages/features/ee/workflows/api/scheduleWhatsappReminders.ts b/packages/features/ee/workflows/api/scheduleWhatsappReminders.ts index 25b59d3d83..306ea8212b 100644 --- a/packages/features/ee/workflows/api/scheduleWhatsappReminders.ts +++ b/packages/features/ee/workflows/api/scheduleWhatsappReminders.ts @@ -5,7 +5,7 @@ import { NextResponse } from "next/server"; import dayjs from "@calcom/dayjs"; import { BookingSeatRepository } from "@calcom/features/bookings/repositories/BookingSeatRepository"; import { CreditService } from "@calcom/features/ee/billing/credit-service"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat"; import prisma from "@calcom/prisma"; import { WorkflowActions, WorkflowMethods } from "@calcom/prisma/enums"; diff --git a/packages/features/ee/workflows/lib/reminders/reminderScheduler.test.ts b/packages/features/ee/workflows/lib/reminders/reminderScheduler.test.ts index f3d82c98f2..3e598cd897 100644 --- a/packages/features/ee/workflows/lib/reminders/reminderScheduler.test.ts +++ b/packages/features/ee/workflows/lib/reminders/reminderScheduler.test.ts @@ -17,7 +17,7 @@ vi.mock("@calcom/features/ee/workflows/lib/reminders/providers/emailProvider", ( sendOrScheduleWorkflowEmails: vi.fn(), })); -vi.mock("@calcom/lib/server/i18n", () => { +vi.mock("@calcom/i18n/server", () => { return { getTranslation: async (locale: string, namespace: string) => { const t = (key: string) => key; diff --git a/packages/features/ee/workflows/lib/reminders/reminderScheduler.ts b/packages/features/ee/workflows/lib/reminders/reminderScheduler.ts index 7cae2f734d..661ee21ce0 100644 --- a/packages/features/ee/workflows/lib/reminders/reminderScheduler.ts +++ b/packages/features/ee/workflows/lib/reminders/reminderScheduler.ts @@ -14,7 +14,7 @@ import type { Workflow, WorkflowStep } from "@calcom/features/ee/workflows/lib/t import { WorkflowReminderRepository } from "@calcom/features/ee/workflows/repositories/WorkflowReminderRepository"; import { formatCalEventExtended } from "@calcom/lib/formatCalendarEvent"; import { withReporting } from "@calcom/lib/sentryWrapper"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { checkSMSRateLimit } from "@calcom/lib/smsLockState"; import { prisma } from "@calcom/prisma"; import { SchedulingType } from "@calcom/prisma/enums"; diff --git a/packages/features/ee/workflows/lib/reminders/smsReminderManager.ts b/packages/features/ee/workflows/lib/reminders/smsReminderManager.ts index 42b2accd25..c757c1e6d1 100644 --- a/packages/features/ee/workflows/lib/reminders/smsReminderManager.ts +++ b/packages/features/ee/workflows/lib/reminders/smsReminderManager.ts @@ -9,7 +9,7 @@ import { getSubmitterEmail } from "@calcom/features/tasker/tasks/triggerFormSubm import { SENDER_ID } from "@calcom/lib/constants"; import logger from "@calcom/lib/logger"; import { safeStringify } from "@calcom/lib/safeStringify"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat"; import type { PrismaClient } from "@calcom/prisma"; import prisma from "@calcom/prisma"; diff --git a/packages/features/ee/workflows/lib/reminders/whatsappReminderManager.ts b/packages/features/ee/workflows/lib/reminders/whatsappReminderManager.ts index 80c1ac7eee..f15aba8b7a 100644 --- a/packages/features/ee/workflows/lib/reminders/whatsappReminderManager.ts +++ b/packages/features/ee/workflows/lib/reminders/whatsappReminderManager.ts @@ -1,6 +1,6 @@ import dayjs from "@calcom/dayjs"; import logger from "@calcom/lib/logger"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import prisma from "@calcom/prisma"; import { WorkflowTriggerEvents, diff --git a/packages/features/ee/workflows/lib/service/EmailWorkflowService.test.ts b/packages/features/ee/workflows/lib/service/EmailWorkflowService.test.ts index 0ecc0d3ba1..18db7cb0d3 100644 --- a/packages/features/ee/workflows/lib/service/EmailWorkflowService.test.ts +++ b/packages/features/ee/workflows/lib/service/EmailWorkflowService.test.ts @@ -22,7 +22,7 @@ vi.mock("@calcom/features/profile/lib/hideBranding", () => ({ getHideBranding: vi.fn().mockResolvedValue(false), })); -vi.mock("@calcom/lib/server/i18n", () => ({ +vi.mock("@calcom/i18n/server", () => ({ getTranslation: vi.fn().mockResolvedValue((key: string) => key), })); diff --git a/packages/features/ee/workflows/lib/service/EmailWorkflowService.ts b/packages/features/ee/workflows/lib/service/EmailWorkflowService.ts index 22c6483b05..f8d8b2e4c3 100644 --- a/packages/features/ee/workflows/lib/service/EmailWorkflowService.ts +++ b/packages/features/ee/workflows/lib/service/EmailWorkflowService.ts @@ -13,7 +13,7 @@ import { getVideoCallUrlFromCalEvent } from "@calcom/lib/CalEventParser"; import { SENDER_NAME, WEBSITE_URL } from "@calcom/lib/constants"; import logger from "@calcom/lib/logger"; import { TimeFormat } from "@calcom/lib/timeFormat"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { prisma } from "@calcom/prisma"; import { WorkflowActions, WorkflowTemplates } from "@calcom/prisma/enums"; import { SchedulingType, WorkflowTriggerEvents } from "@calcom/prisma/enums"; diff --git a/packages/features/ee/workflows/lib/service/workflowOptOutService.ts b/packages/features/ee/workflows/lib/service/workflowOptOutService.ts index c8c73f0a71..7239433269 100644 --- a/packages/features/ee/workflows/lib/service/workflowOptOutService.ts +++ b/packages/features/ee/workflows/lib/service/workflowOptOutService.ts @@ -1,4 +1,4 @@ -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { deleteMultipleScheduledSMS } from "../reminders/providers/twilioProvider"; import { WorkflowOptOutContactRepository } from "../repository/workflowOptOutContact"; diff --git a/packages/features/ee/workflows/lib/test/compareReminderBodyToTemplate.test.ts b/packages/features/ee/workflows/lib/test/compareReminderBodyToTemplate.test.ts index a193e9406d..ed29f6b521 100644 --- a/packages/features/ee/workflows/lib/test/compareReminderBodyToTemplate.test.ts +++ b/packages/features/ee/workflows/lib/test/compareReminderBodyToTemplate.test.ts @@ -1,6 +1,6 @@ import { vi, expect, test, describe } from "vitest"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { TimeFormat } from "@calcom/lib/timeFormat"; import { WorkflowActions, WorkflowTemplates } from "@calcom/prisma/enums"; @@ -28,7 +28,7 @@ const tMock = (key: string) => { return mocks[key] || key; }; -vi.mock("@calcom/lib/server/i18n", () => { +vi.mock("@calcom/i18n/server", () => { return { getTranslation: async (locale: string, namespace: string) => { const t = tMock as any; diff --git a/packages/features/eventtypes/lib/getEventTypeById.integration-test.ts b/packages/features/eventtypes/lib/getEventTypeById.integration-test.ts index 03c3e3f614..ad5d27dc34 100644 --- a/packages/features/eventtypes/lib/getEventTypeById.integration-test.ts +++ b/packages/features/eventtypes/lib/getEventTypeById.integration-test.ts @@ -18,7 +18,7 @@ export function mockNoTranslations() { }); } -vi.mock("@calcom/lib/server/i18n", () => ({ +vi.mock("@calcom/i18n/server", () => ({ getTranslation: (key: string) => () => key, })); diff --git a/packages/features/eventtypes/lib/getEventTypeById.ts b/packages/features/eventtypes/lib/getEventTypeById.ts index 8897a347c0..e94509e10f 100644 --- a/packages/features/eventtypes/lib/getEventTypeById.ts +++ b/packages/features/eventtypes/lib/getEventTypeById.ts @@ -15,7 +15,7 @@ import { parseBookingLimit } from "@calcom/lib/intervalLimits/isBookingLimits"; import { parseDurationLimit } from "@calcom/lib/intervalLimits/isDurationLimits"; import { parseEventTypeColor } from "@calcom/lib/isEventTypeColor"; import { parseRecurringEvent } from "@calcom/lib/isRecurringEvent"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import type { PrismaClient } from "@calcom/prisma"; import type { Prisma } from "@calcom/prisma/client"; import { MembershipRole, SchedulingType } from "@calcom/prisma/enums"; diff --git a/packages/features/handleMarkNoShow.test.ts b/packages/features/handleMarkNoShow.test.ts index 90d1d11da3..f0e157c3bf 100644 --- a/packages/features/handleMarkNoShow.test.ts +++ b/packages/features/handleMarkNoShow.test.ts @@ -113,7 +113,7 @@ vi.mock("@calcom/lib/getOrgIdFromMemberOrTeamId", () => ({ default: vi.fn().mockResolvedValue(null), })); -vi.mock("@calcom/lib/server/i18n", () => ({ +vi.mock("@calcom/i18n/server", () => ({ getTranslation: vi .fn() .mockResolvedValue((key: string, opts?: { x?: string }) => (opts?.x ? `${opts.x} ${key}` : key)), diff --git a/packages/features/handleMarkNoShow.ts b/packages/features/handleMarkNoShow.ts index 1d42815f20..9ccc992240 100644 --- a/packages/features/handleMarkNoShow.ts +++ b/packages/features/handleMarkNoShow.ts @@ -21,7 +21,7 @@ import { WebhookService } from "@calcom/features/webhooks/lib/WebhookService"; import getOrgIdFromMemberOrTeamId from "@calcom/lib/getOrgIdFromMemberOrTeamId"; import { HttpError } from "@calcom/lib/http-error"; import logger from "@calcom/lib/logger"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat"; import { prisma } from "@calcom/prisma"; import { WebhookTriggerEvents, WorkflowTriggerEvents } from "@calcom/prisma/enums"; diff --git a/packages/features/package.json b/packages/features/package.json index 1e9cbf29b9..e2dd8b6e3a 100644 --- a/packages/features/package.json +++ b/packages/features/package.json @@ -16,6 +16,7 @@ "dependencies": { "@calcom/atoms": "workspace:*", "@calcom/dayjs": "workspace:*", + "@calcom/i18n": "workspace:*", "@calcom/lib": "workspace:*", "@calcom/trpc": "workspace:*", "@calcom/ui": "workspace:*", diff --git a/packages/features/slots/handleNotificationWhenNoSlots.ts b/packages/features/slots/handleNotificationWhenNoSlots.ts index be23930e21..bd97c02b1e 100644 --- a/packages/features/slots/handleNotificationWhenNoSlots.ts +++ b/packages/features/slots/handleNotificationWhenNoSlots.ts @@ -4,7 +4,7 @@ import type { TeamRepository } from "@calcom/features/ee/teams/repositories/Team import type { MembershipRepository } from "@calcom/features/membership/repositories/MembershipRepository"; import type { IRedisService } from "@calcom/features/redis/IRedisService"; import { IS_PRODUCTION, WEBAPP_URL } from "@calcom/lib/constants"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; type EventDetails = { username: string; diff --git a/packages/features/tasker/tasks/crm/lib/buildCalendarEvent.ts b/packages/features/tasker/tasks/crm/lib/buildCalendarEvent.ts index 71f1e59d31..955ff0b125 100644 --- a/packages/features/tasker/tasks/crm/lib/buildCalendarEvent.ts +++ b/packages/features/tasker/tasks/crm/lib/buildCalendarEvent.ts @@ -1,6 +1,6 @@ import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses"; import { addVideoCallDataToEvent } from "@calcom/features/bookings/lib/handleNewBooking/addVideoCallDataToEvent"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import prisma from "@calcom/prisma"; import type { CalendarEvent } from "@calcom/types/Calendar"; diff --git a/packages/features/tasker/tasks/scanWorkflowBody.ts b/packages/features/tasker/tasks/scanWorkflowBody.ts index ab194bf3dc..f89dbe0cb3 100644 --- a/packages/features/tasker/tasks/scanWorkflowBody.ts +++ b/packages/features/tasker/tasks/scanWorkflowBody.ts @@ -6,7 +6,7 @@ import { scheduleWorkflowNotifications } from "@calcom/features/ee/workflows/lib import { Task } from "@calcom/features/tasker/repository"; import { URL_SCANNING_ENABLED } from "@calcom/lib/constants"; import logger from "@calcom/lib/logger"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat"; import prisma from "@calcom/prisma"; diff --git a/packages/features/tasker/tasks/test/scanWorkflowBody.test.ts b/packages/features/tasker/tasks/test/scanWorkflowBody.test.ts index 295544434e..9107c8ab0e 100644 --- a/packages/features/tasker/tasks/test/scanWorkflowBody.test.ts +++ b/packages/features/tasker/tasks/test/scanWorkflowBody.test.ts @@ -36,7 +36,7 @@ vi.mock("@calcom/features/ee/workflows/lib/compareReminderBodyToTemplate", () => })); // Mock the i18n -vi.mock("@calcom/lib/server/i18n", () => ({ +vi.mock("@calcom/i18n/server", () => ({ getTranslation: vi.fn().mockResolvedValue((key: string) => key), })); diff --git a/packages/features/users/repositories/UserRepository.test.ts b/packages/features/users/repositories/UserRepository.test.ts index ac50054c35..76eee67925 100644 --- a/packages/features/users/repositories/UserRepository.test.ts +++ b/packages/features/users/repositories/UserRepository.test.ts @@ -5,7 +5,7 @@ import { describe, test, vi, expect, beforeEach } from "vitest"; import { UserRepository } from "@calcom/features/users/repositories/UserRepository"; import { CreationSource } from "@calcom/prisma/enums"; -vi.mock("@calcom/lib/server/i18n", () => { +vi.mock("@calcom/i18n/server", () => { return { getTranslation: async (locale: string, namespace: string) => { const t = (key: string) => key; diff --git a/packages/features/users/repositories/UserRepository.ts b/packages/features/users/repositories/UserRepository.ts index 2cb3e61ffb..057169030f 100644 --- a/packages/features/users/repositories/UserRepository.ts +++ b/packages/features/users/repositories/UserRepository.ts @@ -5,7 +5,7 @@ import { DEFAULT_SCHEDULE, getAvailabilityFromSchedule } from "@calcom/lib/avail import { buildNonDelegationCredentials } from "@calcom/lib/delegationCredential"; import logger from "@calcom/lib/logger"; import { safeStringify } from "@calcom/lib/safeStringify"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { withSelectedCalendars } from "@calcom/lib/server/withSelectedCalendars"; import type { PrismaClient } from "@calcom/prisma"; import { availabilityUserSelect } from "@calcom/prisma"; diff --git a/packages/features/users/services/userCreationService.test.ts b/packages/features/users/services/userCreationService.test.ts index 11496e9ae2..941faaee0e 100644 --- a/packages/features/users/services/userCreationService.test.ts +++ b/packages/features/users/services/userCreationService.test.ts @@ -6,7 +6,7 @@ import { CreationSource } from "@calcom/prisma/enums"; import { UserCreationService } from "./userCreationService"; -vi.mock("@calcom/lib/server/i18n", () => { +vi.mock("@calcom/i18n/server", () => { return { getTranslation: async (locale: string, namespace: string) => { const t = (key: string) => key; diff --git a/packages/features/webhooks/lib/scheduleTrigger.ts b/packages/features/webhooks/lib/scheduleTrigger.ts index 13b5ee5bd3..46d4ca179f 100644 --- a/packages/features/webhooks/lib/scheduleTrigger.ts +++ b/packages/features/webhooks/lib/scheduleTrigger.ts @@ -8,7 +8,7 @@ import tasker from "@calcom/features/tasker"; import logger from "@calcom/lib/logger"; import { safeStringify } from "@calcom/lib/safeStringify"; import { withReporting } from "@calcom/lib/sentryWrapper"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { prisma } from "@calcom/prisma"; import type { Prisma, Webhook, Booking, ApiKey } from "@calcom/prisma/client"; import { BookingStatus, WebhookTriggerEvents } from "@calcom/prisma/enums"; diff --git a/apps/web/public/static/locales/ar/common.json b/packages/i18n/locales/ar/common.json similarity index 100% rename from apps/web/public/static/locales/ar/common.json rename to packages/i18n/locales/ar/common.json diff --git a/apps/web/public/static/locales/az/common.json b/packages/i18n/locales/az/common.json similarity index 100% rename from apps/web/public/static/locales/az/common.json rename to packages/i18n/locales/az/common.json diff --git a/apps/web/public/static/locales/bg/common.json b/packages/i18n/locales/bg/common.json similarity index 100% rename from apps/web/public/static/locales/bg/common.json rename to packages/i18n/locales/bg/common.json diff --git a/apps/web/public/static/locales/bn/common.json b/packages/i18n/locales/bn/common.json similarity index 100% rename from apps/web/public/static/locales/bn/common.json rename to packages/i18n/locales/bn/common.json diff --git a/apps/web/public/static/locales/ca/common.json b/packages/i18n/locales/ca/common.json similarity index 100% rename from apps/web/public/static/locales/ca/common.json rename to packages/i18n/locales/ca/common.json diff --git a/apps/web/public/static/locales/cs/common.json b/packages/i18n/locales/cs/common.json similarity index 100% rename from apps/web/public/static/locales/cs/common.json rename to packages/i18n/locales/cs/common.json diff --git a/apps/web/public/static/locales/da/common.json b/packages/i18n/locales/da/common.json similarity index 100% rename from apps/web/public/static/locales/da/common.json rename to packages/i18n/locales/da/common.json diff --git a/apps/web/public/static/locales/de/common.json b/packages/i18n/locales/de/common.json similarity index 100% rename from apps/web/public/static/locales/de/common.json rename to packages/i18n/locales/de/common.json diff --git a/apps/web/public/static/locales/el/common.json b/packages/i18n/locales/el/common.json similarity index 100% rename from apps/web/public/static/locales/el/common.json rename to packages/i18n/locales/el/common.json diff --git a/apps/web/public/static/locales/en/common.json b/packages/i18n/locales/en/common.json similarity index 100% rename from apps/web/public/static/locales/en/common.json rename to packages/i18n/locales/en/common.json diff --git a/apps/web/public/static/locales/es-419/common.json b/packages/i18n/locales/es-419/common.json similarity index 100% rename from apps/web/public/static/locales/es-419/common.json rename to packages/i18n/locales/es-419/common.json diff --git a/apps/web/public/static/locales/es/common.json b/packages/i18n/locales/es/common.json similarity index 100% rename from apps/web/public/static/locales/es/common.json rename to packages/i18n/locales/es/common.json diff --git a/apps/web/public/static/locales/et/common.json b/packages/i18n/locales/et/common.json similarity index 100% rename from apps/web/public/static/locales/et/common.json rename to packages/i18n/locales/et/common.json diff --git a/apps/web/public/static/locales/eu/common.json b/packages/i18n/locales/eu/common.json similarity index 100% rename from apps/web/public/static/locales/eu/common.json rename to packages/i18n/locales/eu/common.json diff --git a/apps/web/public/static/locales/fi/common.json b/packages/i18n/locales/fi/common.json similarity index 100% rename from apps/web/public/static/locales/fi/common.json rename to packages/i18n/locales/fi/common.json diff --git a/apps/web/public/static/locales/fr/common.json b/packages/i18n/locales/fr/common.json similarity index 100% rename from apps/web/public/static/locales/fr/common.json rename to packages/i18n/locales/fr/common.json diff --git a/apps/web/public/static/locales/he/common.json b/packages/i18n/locales/he/common.json similarity index 100% rename from apps/web/public/static/locales/he/common.json rename to packages/i18n/locales/he/common.json diff --git a/apps/web/public/static/locales/hr/common.json b/packages/i18n/locales/hr/common.json similarity index 100% rename from apps/web/public/static/locales/hr/common.json rename to packages/i18n/locales/hr/common.json diff --git a/apps/web/public/static/locales/hu/common.json b/packages/i18n/locales/hu/common.json similarity index 100% rename from apps/web/public/static/locales/hu/common.json rename to packages/i18n/locales/hu/common.json diff --git a/apps/web/public/static/locales/id/common.json b/packages/i18n/locales/id/common.json similarity index 100% rename from apps/web/public/static/locales/id/common.json rename to packages/i18n/locales/id/common.json diff --git a/apps/web/public/static/locales/it/common.json b/packages/i18n/locales/it/common.json similarity index 100% rename from apps/web/public/static/locales/it/common.json rename to packages/i18n/locales/it/common.json diff --git a/apps/web/public/static/locales/iw/common.json b/packages/i18n/locales/iw/common.json similarity index 100% rename from apps/web/public/static/locales/iw/common.json rename to packages/i18n/locales/iw/common.json diff --git a/apps/web/public/static/locales/ja/common.json b/packages/i18n/locales/ja/common.json similarity index 100% rename from apps/web/public/static/locales/ja/common.json rename to packages/i18n/locales/ja/common.json diff --git a/apps/web/public/static/locales/km/common.json b/packages/i18n/locales/km/common.json similarity index 100% rename from apps/web/public/static/locales/km/common.json rename to packages/i18n/locales/km/common.json diff --git a/apps/web/public/static/locales/ko/common.json b/packages/i18n/locales/ko/common.json similarity index 100% rename from apps/web/public/static/locales/ko/common.json rename to packages/i18n/locales/ko/common.json diff --git a/apps/web/public/static/locales/lv/common.json b/packages/i18n/locales/lv/common.json similarity index 100% rename from apps/web/public/static/locales/lv/common.json rename to packages/i18n/locales/lv/common.json diff --git a/apps/web/public/static/locales/nl/common.json b/packages/i18n/locales/nl/common.json similarity index 100% rename from apps/web/public/static/locales/nl/common.json rename to packages/i18n/locales/nl/common.json diff --git a/apps/web/public/static/locales/no/common.json b/packages/i18n/locales/no/common.json similarity index 100% rename from apps/web/public/static/locales/no/common.json rename to packages/i18n/locales/no/common.json diff --git a/apps/web/public/static/locales/pl/common.json b/packages/i18n/locales/pl/common.json similarity index 100% rename from apps/web/public/static/locales/pl/common.json rename to packages/i18n/locales/pl/common.json diff --git a/apps/web/public/static/locales/pt-BR/common.json b/packages/i18n/locales/pt-BR/common.json similarity index 100% rename from apps/web/public/static/locales/pt-BR/common.json rename to packages/i18n/locales/pt-BR/common.json diff --git a/apps/web/public/static/locales/pt/common.json b/packages/i18n/locales/pt/common.json similarity index 100% rename from apps/web/public/static/locales/pt/common.json rename to packages/i18n/locales/pt/common.json diff --git a/apps/web/public/static/locales/ro/common.json b/packages/i18n/locales/ro/common.json similarity index 100% rename from apps/web/public/static/locales/ro/common.json rename to packages/i18n/locales/ro/common.json diff --git a/apps/web/public/static/locales/ru/common.json b/packages/i18n/locales/ru/common.json similarity index 100% rename from apps/web/public/static/locales/ru/common.json rename to packages/i18n/locales/ru/common.json diff --git a/apps/web/public/static/locales/sk-SK/common.json b/packages/i18n/locales/sk-SK/common.json similarity index 100% rename from apps/web/public/static/locales/sk-SK/common.json rename to packages/i18n/locales/sk-SK/common.json diff --git a/apps/web/public/static/locales/sk/common.json b/packages/i18n/locales/sk/common.json similarity index 100% rename from apps/web/public/static/locales/sk/common.json rename to packages/i18n/locales/sk/common.json diff --git a/apps/web/public/static/locales/sr/common.json b/packages/i18n/locales/sr/common.json similarity index 100% rename from apps/web/public/static/locales/sr/common.json rename to packages/i18n/locales/sr/common.json diff --git a/apps/web/public/static/locales/sv/common.json b/packages/i18n/locales/sv/common.json similarity index 100% rename from apps/web/public/static/locales/sv/common.json rename to packages/i18n/locales/sv/common.json diff --git a/apps/web/public/static/locales/ta/common.json b/packages/i18n/locales/ta/common.json similarity index 100% rename from apps/web/public/static/locales/ta/common.json rename to packages/i18n/locales/ta/common.json diff --git a/apps/web/public/static/locales/th/common.json b/packages/i18n/locales/th/common.json similarity index 100% rename from apps/web/public/static/locales/th/common.json rename to packages/i18n/locales/th/common.json diff --git a/apps/web/public/static/locales/tr/common.json b/packages/i18n/locales/tr/common.json similarity index 100% rename from apps/web/public/static/locales/tr/common.json rename to packages/i18n/locales/tr/common.json diff --git a/apps/web/public/static/locales/uk/common.json b/packages/i18n/locales/uk/common.json similarity index 100% rename from apps/web/public/static/locales/uk/common.json rename to packages/i18n/locales/uk/common.json diff --git a/apps/web/public/static/locales/vi/common.json b/packages/i18n/locales/vi/common.json similarity index 100% rename from apps/web/public/static/locales/vi/common.json rename to packages/i18n/locales/vi/common.json diff --git a/apps/web/public/static/locales/zh-CN/common.json b/packages/i18n/locales/zh-CN/common.json similarity index 100% rename from apps/web/public/static/locales/zh-CN/common.json rename to packages/i18n/locales/zh-CN/common.json diff --git a/apps/web/public/static/locales/zh-TW/common.json b/packages/i18n/locales/zh-TW/common.json similarity index 100% rename from apps/web/public/static/locales/zh-TW/common.json rename to packages/i18n/locales/zh-TW/common.json diff --git a/packages/config/next-i18next.config.d.ts b/packages/i18n/next-i18next.config.d.ts similarity index 59% rename from packages/config/next-i18next.config.d.ts rename to packages/i18n/next-i18next.config.d.ts index 70ffb39e3d..24442cdf2a 100644 --- a/packages/config/next-i18next.config.d.ts +++ b/packages/i18n/next-i18next.config.d.ts @@ -1,4 +1,4 @@ -declare module "@calcom/config/next-i18next.config" { +declare module "@calcom/i18n/next-i18next.config" { export const i18n: { locales: string[]; defaultLocale: string; diff --git a/packages/config/next-i18next.config.js b/packages/i18n/next-i18next.config.js similarity index 81% rename from packages/config/next-i18next.config.js rename to packages/i18n/next-i18next.config.js index 60901b042c..8ac4274c20 100644 --- a/packages/config/next-i18next.config.js +++ b/packages/i18n/next-i18next.config.js @@ -1,3 +1,4 @@ +const path = require("node:path"); const i18n = require("../../i18n.json"); /** @type {import("next-i18next").UserConfig} */ @@ -11,6 +12,7 @@ const config = { zh: ["zh-CN"], }, reloadOnPrerender: process.env.NODE_ENV !== "production", + localePath: path.resolve(__dirname, "./locales"), }; module.exports = config; diff --git a/packages/i18n/next-i18next.config.test.ts b/packages/i18n/next-i18next.config.test.ts new file mode 100644 index 0000000000..d4b927809e --- /dev/null +++ b/packages/i18n/next-i18next.config.test.ts @@ -0,0 +1,52 @@ +import fs from "node:fs"; +import path from "node:path"; +import { describe, expect, it } from "vitest"; + +const i18nJson = require("../../i18n.json"); +const config = require("./next-i18next.config"); + +describe("@calcom/i18n/next-i18next.config", () => { + it("exports i18n with defaultLocale and locales", () => { + expect(config.i18n).toBeDefined(); + expect(config.i18n.defaultLocale).toBe("en"); + expect(Array.isArray(config.i18n.locales)).toBe(true); + expect(config.i18n.locales).toContain("en"); + }); + + it("includes all target locales from i18n.json plus the source locale", () => { + const expectedLocales = [...i18nJson.locale.targets, i18nJson.locale.source]; + for (const locale of expectedLocales) { + expect(config.i18n.locales).toContain(locale); + } + expect(config.i18n.locales.length).toBe(expectedLocales.length); + }); + + it("has localePath pointing to existing locales directory", () => { + expect(config.localePath).toBeDefined(); + expect(typeof config.localePath).toBe("string"); + expect(fs.existsSync(config.localePath)).toBe(true); + }); + + it("has fallbackLng configured", () => { + expect(config.fallbackLng).toBeDefined(); + expect(config.fallbackLng.default).toEqual(["en"]); + expect(config.fallbackLng.zh).toEqual(["zh-CN"]); + }); + + it("every locale in config has a corresponding locale directory with common.json", () => { + const localesDir = config.localePath; + for (const locale of config.i18n.locales) { + const localeDir = path.join(localesDir, locale); + const commonJson = path.join(localeDir, "common.json"); + expect(fs.existsSync(localeDir)).toBe(true); + expect(fs.existsSync(commonJson)).toBe(true); + } + }); + + it("english common.json is valid JSON with translation keys", () => { + const enPath = path.join(config.localePath, "en", "common.json"); + const enTranslations = JSON.parse(fs.readFileSync(enPath, "utf-8")); + expect(typeof enTranslations).toBe("object"); + expect(Object.keys(enTranslations).length).toBeGreaterThan(0); + }); +}); diff --git a/packages/i18n/package.json b/packages/i18n/package.json new file mode 100644 index 0000000000..39eec9ea05 --- /dev/null +++ b/packages/i18n/package.json @@ -0,0 +1,21 @@ +{ + "name": "@calcom/i18n", + "sideEffects": false, + "private": true, + "version": "0.0.0", + "main": "index.js", + "license": "MIT", + "description": "Internationalization (i18n) utilities and translations for Cal.com", + "exports": { + "./server": "./server.ts", + "./next-i18next.config": "./next-i18next.config.js", + "./locales/*": "./locales/*" + }, + "dependencies": { + "i18next": "23.2.3" + }, + "devDependencies": { + "@calcom/tsconfig": "workspace:*", + "typescript": "5.9.3" + } +} diff --git a/packages/i18n/server.test.ts b/packages/i18n/server.test.ts new file mode 100644 index 0000000000..039662006e --- /dev/null +++ b/packages/i18n/server.test.ts @@ -0,0 +1,177 @@ +import { describe, expect, it } from "vitest"; + +import { getTranslation, loadTranslations, mergeWithEnglishFallback } from "./server"; + +describe("mergeWithEnglishFallback", () => { + it("should merge locale translations with English fallback", () => { + const localeTranslations = { + // Override some existing English keys + hello: "Bonjour", + goodbye: "Au revoir", + // Add new locale-specific keys + locale_only: "French only text", + }; + + const result = mergeWithEnglishFallback(localeTranslations); + + // Check that locale translations override English + expect(result.hello).toBe("Bonjour"); + expect(result.goodbye).toBe("Au revoir"); + + // Check that locale-specific keys are preserved + expect(result.locale_only).toBe("French only text"); + + // Check that English fallback keys are present (using actual keys from the real file) + expect(result).toHaveProperty("welcome"); + expect(result).toHaveProperty("cancel"); + + // Verify the structure - should have both English and locale keys + expect(Object.keys(result)).toContain("hello"); // overridden + expect(Object.keys(result)).toContain("locale_only"); // locale-specific + expect(Object.keys(result).length).toBeGreaterThan(3); // Should have many keys from English + }); + + it("should use English translations as fallback when locale translations are empty", () => { + const localeTranslations = {}; + + const result = mergeWithEnglishFallback(localeTranslations); + + // Should return all English translations + expect(result).toHaveProperty("welcome"); + expect(result).toHaveProperty("cancel"); + expect(Object.keys(result).length).toBeGreaterThan(100); // English file has many keys + }); + + it("should prioritize locale translations over English when keys overlap", () => { + const localeTranslations = { + welcome: "Bienvenido", + cancel: "Cancelar", + }; + + const result = mergeWithEnglishFallback(localeTranslations); + + // Spanish should override English + expect(result.welcome).toBe("Bienvenido"); + expect(result.cancel).toBe("Cancelar"); + + // Should still have other English keys + expect(Object.keys(result).length).toBeGreaterThan(100); + }); + + it("should handle locale translations with additional keys not in English", () => { + const localeTranslations = { + // Override existing English key + welcome: "Ciao", + // Add new keys not in English + italian_greeting: "Buongiorno", + italian_phrase: "Come stai?", + }; + + const result = mergeWithEnglishFallback(localeTranslations); + + // Check overridden key + expect(result.welcome).toBe("Ciao"); + + // Check Italian-specific keys + expect(result.italian_greeting).toBe("Buongiorno"); + expect(result.italian_phrase).toBe("Come stai?"); + + // Should have English keys plus the new Italian ones + expect(Object.keys(result).length).toBeGreaterThan(100); + expect(Object.keys(result)).toContain("italian_greeting"); + expect(Object.keys(result)).toContain("italian_phrase"); + }); +}); + +describe("loadTranslations", () => { + it("returns bundled English translations for locale 'en'", async () => { + const result = await loadTranslations("en", "common"); + + expect(result).toHaveProperty("welcome", "Welcome"); + expect(result).toHaveProperty("cancel", "Cancel"); + expect(Object.keys(result).length).toBeGreaterThan(100); + }); + + it("returns French translations merged with English fallback", async () => { + const result = await loadTranslations("fr", "common"); + + expect(result).toHaveProperty("welcome", "Bienvenue"); + expect(result).toHaveProperty("cancel", "Annuler"); + expect(Object.keys(result).length).toBeGreaterThan(100); + }); + + it("aliases 'zh' to 'zh-CN'", async () => { + const zhResult = await loadTranslations("zh", "common"); + const zhCNResult = await loadTranslations("zh-CN", "common"); + + expect(zhResult).toEqual(zhCNResult); + }); + + it("falls back to English for unsupported locales", async () => { + const result = await loadTranslations("xx-INVALID", "common"); + + expect(result).toHaveProperty("welcome", "Welcome"); + expect(result).toHaveProperty("cancel", "Cancel"); + }); + + it("falls back to 'common' namespace for unsupported namespaces", async () => { + const result = await loadTranslations("en", "nonexistent-namespace"); + + expect(result).toHaveProperty("welcome", "Welcome"); + expect(Object.keys(result).length).toBeGreaterThan(100); + }); + + it("returns cached result on subsequent calls for the same locale", async () => { + const first = await loadTranslations("de", "common"); + const second = await loadTranslations("de", "common"); + + expect(first).toBe(second); + }); + + it("includes English fallback keys missing from the locale file", async () => { + const enResult = await loadTranslations("en", "common"); + const frResult = await loadTranslations("fr", "common"); + + for (const key of Object.keys(enResult)) { + expect(frResult).toHaveProperty(key); + } + }); +}); + +describe("getTranslation", () => { + it("returns a function that translates English keys", async () => { + const t = await getTranslation("en", "common"); + + expect(typeof t).toBe("function"); + expect(t("welcome")).toBe("Welcome"); + expect(t("cancel")).toBe("Cancel"); + }); + + it("returns a function that translates French keys", async () => { + const t = await getTranslation("fr", "common"); + + expect(t("welcome")).toBe("Bienvenue"); + expect(t("cancel")).toBe("Annuler"); + }); + + it("returns the key itself for missing translation keys", async () => { + const t = await getTranslation("en", "common"); + + expect(t("this_key_does_not_exist")).toBe("this_key_does_not_exist"); + }); + + it("returns consistent results from cached i18n instance on subsequent calls", async () => { + const first = await getTranslation("es", "common"); + const second = await getTranslation("es", "common"); + + expect(first("welcome")).toBe(second("welcome")); + expect(first("cancel")).toBe(second("cancel")); + }); + + it("returns different translation functions for different locales", async () => { + const enT = await getTranslation("en", "common"); + const frT = await getTranslation("fr", "common"); + + expect(enT("welcome")).not.toBe(frT("welcome")); + }); +}); diff --git a/packages/platform/libraries/i18n.ts b/packages/i18n/server.ts similarity index 57% rename from packages/platform/libraries/i18n.ts rename to packages/i18n/server.ts index 09de7e84f1..cdcd52ff90 100644 --- a/packages/platform/libraries/i18n.ts +++ b/packages/i18n/server.ts @@ -1,23 +1,27 @@ import { createInstance } from "i18next"; import type { i18n as I18nInstance } from "i18next"; -import { WEBAPP_URL } from "@calcom/lib/constants"; -import { fetchWithTimeout } from "@calcom/lib/fetchWithTimeout"; -import logger from "@calcom/lib/logger"; +const { i18n } = require("@calcom/i18n/next-i18next.config"); -/* eslint-disable @typescript-eslint/no-require-imports */ -const { i18n } = require("@calcom/config/next-i18next.config"); -const path = require("node:path"); -const translationsPath = path.resolve(__dirname, "../../../../apps/web/public/static/locales/en/common.json"); -const englishTranslations: Record = require(translationsPath); -/* eslint-enable @typescript-eslint/no-require-imports */ +const englishTranslations: Record = require("@calcom/i18n/locales/en/common.json"); -const translationCache = new Map>([["en-common", englishTranslations]]); +const translationCache = new Map>(); const i18nInstanceCache = new Map(); const SUPPORTED_NAMESPACES = ["common"]; +export function mergeWithEnglishFallback(localeTranslations: Record): Record { + return { + // IMPORTANT: Spread English translations first to provide fallback for missing keys + ...englishTranslations, + // Then spread locale translations to override English when keys exist in both + ...localeTranslations, + }; +} + /** * Loads translations for a specific locale and namespace with optimized caching + * Server-side only function that loads translations directly from file system for best performance + * Uses @calcom/config package alias for reliable access across all packages in the monorepo * @param {string} _locale - The locale code (e.g., 'en', 'fr', 'zh') * @param {string} ns - The namespace for the translations * @returns {Promise>} Translations object or fallback translations on failure @@ -28,32 +32,21 @@ export async function loadTranslations(_locale: string, _ns: string) { const ns = SUPPORTED_NAMESPACES.includes(_ns) ? _ns : "common"; const cacheKey = `${locale}-${ns}`; - if (translationCache.has(cacheKey)) { - return translationCache.get(cacheKey); + const cached = translationCache.get(cacheKey); + if (cached) { + return cached; } - const url = `${WEBAPP_URL}/static/locales/${locale}/${ns}.json`; - try { - const response = await fetchWithTimeout( - url, - { - cache: "no-store", - }, - process.env.NODE_ENV === "development" ? 30000 : 3000 - ); - - if (!response.ok) { - logger.warn(`Failed to fetch translations for ${locale}: ${response.status}, falling back to English`); - return englishTranslations; - } - - const translations = await response.json(); - translationCache.set(cacheKey, translations); - return translations; - } catch (err) { - logger.warn(`Failed to load translations for ${locale}, falling back to English:`, err); + if (locale === "en") { + translationCache.set(cacheKey, englishTranslations); return englishTranslations; } + + const { default: localeTranslations } = await import(`./locales/${locale}/${ns}.json`); + + const mergedTranslations = mergeWithEnglishFallback(localeTranslations); + translationCache.set(cacheKey, mergedTranslations); + return mergedTranslations; } /** diff --git a/packages/lib/__tests__/buildCalEventFromBooking.test.ts b/packages/lib/__tests__/buildCalEventFromBooking.test.ts index a38bc67c55..1c61b6ca3c 100644 --- a/packages/lib/__tests__/buildCalEventFromBooking.test.ts +++ b/packages/lib/__tests__/buildCalEventFromBooking.test.ts @@ -4,14 +4,14 @@ import dayjs from "@calcom/dayjs"; import { buildCalEventFromBooking } from "../buildCalEventFromBooking"; import { parseRecurringEvent } from "../isRecurringEvent"; -import { getTranslation } from "../server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; // Mock dependencies vi.mock("../isRecurringEvent", () => ({ parseRecurringEvent: vi.fn(), })); -vi.mock("../server/i18n", () => ({ +vi.mock("@calcom/i18n/server", () => ({ getTranslation: vi.fn(), })); diff --git a/packages/lib/buildCalEventFromBooking.ts b/packages/lib/buildCalEventFromBooking.ts index eaad3386b0..f34de3458d 100644 --- a/packages/lib/buildCalEventFromBooking.ts +++ b/packages/lib/buildCalEventFromBooking.ts @@ -2,7 +2,7 @@ import dayjs from "@calcom/dayjs"; import type { Prisma } from "@calcom/prisma/client"; import { parseRecurringEvent } from "./isRecurringEvent"; -import { getTranslation } from "./server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; type DestinationCalendar = { id: number; diff --git a/packages/lib/builders/CalendarEvent/builder.ts b/packages/lib/builders/CalendarEvent/builder.ts index 2d07acf8fd..1ba7e73e29 100644 --- a/packages/lib/builders/CalendarEvent/builder.ts +++ b/packages/lib/builders/CalendarEvent/builder.ts @@ -3,7 +3,7 @@ import { v5 as uuidv5 } from "uuid"; import dayjs from "@calcom/dayjs"; import { getRescheduleLink } from "@calcom/lib/CalEventParser"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import prisma from "@calcom/prisma"; import type { Prisma } from "@calcom/prisma/client"; import type { CalendarEvent } from "@calcom/types/Calendar"; diff --git a/packages/lib/i18n.ts b/packages/lib/i18n.ts index 5de87507b0..330c33365b 100644 --- a/packages/lib/i18n.ts +++ b/packages/lib/i18n.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-var-requires */ -const { i18n } = require("@calcom/config/next-i18next.config"); +const { i18n } = require("@calcom/i18n/next-i18next.config"); // Workaround for using router.locales from old router export const locales = i18n.locales as string[]; diff --git a/packages/lib/package.json b/packages/lib/package.json index 263a97e21c..9fd65f5dd4 100644 --- a/packages/lib/package.json +++ b/packages/lib/package.json @@ -12,6 +12,7 @@ "dependencies": { "@calcom/config": "workspace:*", "@calcom/dayjs": "workspace:*", + "@calcom/i18n": "workspace:*", "@formbricks/api": "3.0.0", "@formbricks/js": "4.3.0", "@sendgrid/client": "7.7.0", diff --git a/packages/lib/server/i18n.test.ts b/packages/lib/server/i18n.test.ts deleted file mode 100644 index 6ef0cee646..0000000000 --- a/packages/lib/server/i18n.test.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { describe, expect, it } from "vitest"; - -import { mergeWithEnglishFallback } from "./i18n"; - -describe("mergeWithEnglishFallback", () => { - it("should merge locale translations with English fallback", () => { - const localeTranslations = { - // Override some existing English keys - hello: "Bonjour", - goodbye: "Au revoir", - // Add new locale-specific keys - locale_only: "French only text", - }; - - const result = mergeWithEnglishFallback(localeTranslations); - - // Check that locale translations override English - expect(result.hello).toBe("Bonjour"); - expect(result.goodbye).toBe("Au revoir"); - - // Check that locale-specific keys are preserved - expect(result.locale_only).toBe("French only text"); - - // Check that English fallback keys are present (using actual keys from the real file) - expect(result).toHaveProperty("welcome"); - expect(result).toHaveProperty("cancel"); - - // Verify the structure - should have both English and locale keys - expect(Object.keys(result)).toContain("hello"); // overridden - expect(Object.keys(result)).toContain("locale_only"); // locale-specific - expect(Object.keys(result).length).toBeGreaterThan(3); // Should have many keys from English - }); - - it("should use English translations as fallback when locale translations are empty", () => { - const localeTranslations = {}; - - const result = mergeWithEnglishFallback(localeTranslations); - - // Should return all English translations - expect(result).toHaveProperty("welcome"); - expect(result).toHaveProperty("cancel"); - expect(Object.keys(result).length).toBeGreaterThan(100); // English file has many keys - }); - - it("should prioritize locale translations over English when keys overlap", () => { - const localeTranslations = { - welcome: "Bienvenido", - cancel: "Cancelar", - }; - - const result = mergeWithEnglishFallback(localeTranslations); - - // Spanish should override English - expect(result.welcome).toBe("Bienvenido"); - expect(result.cancel).toBe("Cancelar"); - - // Should still have other English keys - expect(Object.keys(result).length).toBeGreaterThan(100); - }); - - it("should handle locale translations with additional keys not in English", () => { - const localeTranslations = { - // Override existing English key - welcome: "Ciao", - // Add new keys not in English - italian_greeting: "Buongiorno", - italian_phrase: "Come stai?", - }; - - const result = mergeWithEnglishFallback(localeTranslations); - - // Check overridden key - expect(result.welcome).toBe("Ciao"); - - // Check Italian-specific keys - expect(result.italian_greeting).toBe("Buongiorno"); - expect(result.italian_phrase).toBe("Come stai?"); - - // Should have English keys plus the new Italian ones - expect(Object.keys(result).length).toBeGreaterThan(100); - expect(Object.keys(result)).toContain("italian_greeting"); - expect(Object.keys(result)).toContain("italian_phrase"); - }); -}); diff --git a/packages/lib/server/i18n.ts b/packages/lib/server/i18n.ts deleted file mode 100644 index c0a6655d42..0000000000 --- a/packages/lib/server/i18n.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { createInstance } from "i18next"; - -import { WEBAPP_URL } from "@calcom/lib/constants"; - -import { fetchWithTimeout } from "../fetchWithTimeout"; -import logger from "../logger"; - -const { i18n } = require("@calcom/config/next-i18next.config"); -const log = logger.getSubLogger({ prefix: ["[i18n]"] }); - -// Import only English translations directly to avoid HTTP requests -// Other languages will be loaded dynamically to minimize bundle size -const englishTranslations: Record< - string, - string -> = require("../../../apps/web/public/static/locales/en/common.json"); - -const translationCache = new Map>(); -const i18nInstanceCache = new Map(); -const SUPPORTED_NAMESPACES = ["common"]; - -export function mergeWithEnglishFallback(localeTranslations: Record): Record { - return { - // IMPORTANT: Spread English translations first to provide fallback for missing keys - ...englishTranslations, - // Then spread locale translations to override English when keys exist in both - ...localeTranslations, - }; -} - -/** - * Loads translations for a specific locale and namespace with optimized caching - * English translations are bundled as englishTranslations for reliability, - * other languages use dynamic imports with HTTP fallback to minimize bundle size - * @param {string} _locale - The locale code (e.g., 'en', 'fr', 'zh') - * @param {string} ns - The namespace for the translations - * @returns {Promise>} Translations object or fallback translations on failure - */ -export async function loadTranslations(_locale: string, _ns: string) { - let locale = _locale === "zh" ? "zh-CN" : _locale; - locale = i18n.locales.includes(locale) ? locale : "en"; - const ns = SUPPORTED_NAMESPACES.includes(_ns) ? _ns : "common"; - const cacheKey = `${locale}-${ns}`; - - const cached = translationCache.get(cacheKey); - if (cached) { - return cached; - } - - if (locale === "en") { - translationCache.set(cacheKey, englishTranslations); - return englishTranslations; - } - - try { - const { default: localeTranslations } = await import( - `../../../apps/web/public/static/locales/${locale}/${ns}.json` - ); - - const mergedTranslations = mergeWithEnglishFallback(localeTranslations); - translationCache.set(cacheKey, mergedTranslations); - return mergedTranslations; - } catch (dynamicImportErr) { - log.warn(`Dynamic import failed for locale ${locale}:`, dynamicImportErr); - - // Try HTTP fallback as second option - try { - const response = await fetchWithTimeout( - `${WEBAPP_URL}/static/locales/${locale}/${ns}.json`, - { - cache: "no-store", - }, - 3000 - ); - if (response.ok) { - const httpTranslations = await response.json(); - const mergedTranslations = mergeWithEnglishFallback(httpTranslations); - translationCache.set(cacheKey, mergedTranslations); - return mergedTranslations; - } - } catch (httpErr) { - log.error(`HTTP fallback also failed for locale ${locale}:`, httpErr); - } - - log.info(`Falling back to English for locale: ${locale}`); - return englishTranslations; - } -} - -/** - * Creates or retrieves a cached i18next translation function for the specified locale and namespace - * @param {string} locale - The locale code (e.g., 'en', 'fr') - * @param {string} ns - The namespace for the translations - * @returns {Promise} A translation function bound to the specified locale and namespace - */ -export const getTranslation = async (locale: string, ns: string) => { - const cacheKey = `${locale}-${ns}`; - if (i18nInstanceCache.has(cacheKey)) { - return i18nInstanceCache.get(cacheKey).getFixedT(locale, ns); - } - - const resources = await loadTranslations(locale, ns); - - const _i18n = createInstance(); - _i18n.init({ - lng: locale, - resources: { - [locale]: { - [ns]: resources, - }, - }, - fallbackLng: "en", - }); - - // Cache the i18n instance - i18nInstanceCache.set(cacheKey, _i18n); - return _i18n.getFixedT(locale, ns); -}; diff --git a/packages/platform/atoms/cal-provider/BaseCalProvider.tsx b/packages/platform/atoms/cal-provider/BaseCalProvider.tsx index 6c1c00fbd5..9f5c8136d6 100644 --- a/packages/platform/atoms/cal-provider/BaseCalProvider.tsx +++ b/packages/platform/atoms/cal-provider/BaseCalProvider.tsx @@ -5,13 +5,13 @@ import { useCallback } from "react"; import type { API_VERSIONS_ENUM } from "@calcom/platform-constants"; import { IconSprites } from "@calcom/ui/components/icon"; -import deTranslations from "@calcom/web/public/static/locales/de/common.json"; -import enTranslations from "@calcom/web/public/static/locales/en/common.json"; -import esTranslations from "@calcom/web/public/static/locales/es/common.json"; -import frTranslations from "@calcom/web/public/static/locales/fr/common.json"; -import itTranslations from "@calcom/web/public/static/locales/it/common.json"; -import nlTranslations from "@calcom/web/public/static/locales/nl/common.json"; -import ptBrTranslations from "@calcom/web/public/static/locales/pt-BR/common.json"; +import deTranslations from "@calcom/i18n/locales/de/common.json"; +import enTranslations from "@calcom/i18n/locales/en/common.json"; +import esTranslations from "@calcom/i18n/locales/es/common.json"; +import frTranslations from "@calcom/i18n/locales/fr/common.json"; +import itTranslations from "@calcom/i18n/locales/it/common.json"; +import nlTranslations from "@calcom/i18n/locales/nl/common.json"; +import ptBrTranslations from "@calcom/i18n/locales/pt-BR/common.json"; import { AtomsContext } from "../hooks/useAtomsContext"; import { useMe } from "../hooks/useMe"; diff --git a/packages/platform/atoms/cal-provider/languages.ts b/packages/platform/atoms/cal-provider/languages.ts index 5508ba90d2..fd17082fbc 100644 --- a/packages/platform/atoms/cal-provider/languages.ts +++ b/packages/platform/atoms/cal-provider/languages.ts @@ -1,10 +1,10 @@ -import type deTranslations from "@calcom/web/public/static/locales/de/common.json"; -import type enTranslations from "@calcom/web/public/static/locales/en/common.json"; -import type esTranslations from "@calcom/web/public/static/locales/es/common.json"; -import type frTranslations from "@calcom/web/public/static/locales/fr/common.json"; -import type itTranslations from "@calcom/web/public/static/locales/it/common.json"; -import type nlTranslations from "@calcom/web/public/static/locales/nl/common.json"; -import type ptBrTranslations from "@calcom/web/public/static/locales/pt-BR/common.json"; +import type deTranslations from "@calcom/i18n/locales/de/common.json"; +import type enTranslations from "@calcom/i18n/locales/en/common.json"; +import type esTranslations from "@calcom/i18n/locales/es/common.json"; +import type frTranslations from "@calcom/i18n/locales/fr/common.json"; +import type itTranslations from "@calcom/i18n/locales/it/common.json"; +import type nlTranslations from "@calcom/i18n/locales/nl/common.json"; +import type ptBrTranslations from "@calcom/i18n/locales/pt-BR/common.json"; export type enTranslationKeys = keyof typeof enTranslations; export type frTranslationKeys = keyof typeof frTranslations; diff --git a/packages/platform/atoms/package.json b/packages/platform/atoms/package.json index 8055cfa4ff..98b395405f 100644 --- a/packages/platform/atoms/package.json +++ b/packages/platform/atoms/package.json @@ -78,6 +78,7 @@ }, "types": "./dist/index.d.ts", "dependencies": { + "@calcom/i18n": "workspace:*", "@radix-ui/react-dialog-atoms": "npm:@radix-ui/react-dialog@1.0.4", "@radix-ui/react-popover-atoms": "npm:@radix-ui/react-popover@1.0.6", "@radix-ui/react-slot": "1.1.2", diff --git a/packages/platform/atoms/vite.config.ts b/packages/platform/atoms/vite.config.ts index 49e131ea81..fbe448b843 100644 --- a/packages/platform/atoms/vite.config.ts +++ b/packages/platform/atoms/vite.config.ts @@ -96,10 +96,6 @@ export default defineConfig(({ mode }) => { "@calcom/platform-constants": path.resolve(__dirname, "../constants/index.ts"), "@calcom/platform-types": path.resolve(__dirname, "../types/index.ts"), "@calcom/platform-utils": path.resolve(__dirname, "../constants/index.ts"), - "@calcom/web/public/static/locales/en/common.json": path.resolve( - __dirname, - "../../../apps/web/public/static/locales/en/common.json" - ), }, }, }; diff --git a/packages/platform/libraries/index.ts b/packages/platform/libraries/index.ts index c48b20e8d1..96e9dd0c3a 100644 --- a/packages/platform/libraries/index.ts +++ b/packages/platform/libraries/index.ts @@ -1,3 +1,4 @@ +import { getTranslation } from "@calcom/i18n/server"; import { getBookingForReschedule } from "@calcom/features/bookings/lib/get-booking"; import getAllUserBookings from "@calcom/features/bookings/lib/getAllUserBookings"; import { getBookingFieldsWithSystemFields } from "@calcom/features/bookings/lib/getBookingFields"; @@ -13,7 +14,6 @@ import { handleCreatePhoneCall } from "@calcom/features/handleCreatePhoneCall"; import handleMarkNoShow from "@calcom/features/handleMarkNoShow"; import { getRoutedUrl } from "@calcom/features/routing-forms/lib/getRoutedUrl"; import { symmetricDecrypt, symmetricEncrypt } from "@calcom/lib/crypto"; -import { getTranslation } from "@calcom/lib/server/i18n"; import type { Prisma } from "@calcom/prisma/client"; import { credentialForCalendarServiceSelect } from "@calcom/prisma/selects/credential"; import { paymentDataSelect } from "@calcom/prisma/selects/payment"; @@ -120,6 +120,7 @@ export { verifyPhoneNumber, sendVerificationCode }; export { verifyCodeUnAuthenticated } from "@calcom/features/auth/lib/verifyCodeUnAuthenticated"; export { sendEmailVerificationByCode } from "@calcom/features/auth/lib/verifyEmail"; export { BookingAccessService } from "@calcom/features/bookings/services/BookingAccessService"; +export type { OrgMembershipLookup } from "@calcom/features/di/modules/OrgMembershipLookup"; export { StripeBillingService } from "@calcom/features/ee/billing/service/billingProvider/StripeBillingService"; export { TeamService } from "@calcom/features/ee/teams/services/teamService"; export type { OAuth2Tokens } from "@calcom/features/oauth/services/OAuthService"; @@ -132,4 +133,3 @@ export { verifyCodeChallenge } from "@calcom/lib/pkce"; export { validateUrlForSSRFSync } from "@calcom/lib/ssrfProtection"; export { checkEmailVerificationRequired } from "@calcom/trpc/server/routers/publicViewer/checkIfUserEmailVerificationRequired.handler"; export { verifyCode as verifyCodeAuthenticated } from "@calcom/trpc/server/routers/viewer/organizations/verifyCode.handler"; -export type { OrgMembershipLookup } from "@calcom/features/di/modules/OrgMembershipLookup"; diff --git a/packages/platform/libraries/package.json b/packages/platform/libraries/package.json index 01a374ffe1..7fc0f98fec 100644 --- a/packages/platform/libraries/package.json +++ b/packages/platform/libraries/package.json @@ -18,6 +18,7 @@ }, "dependencies": { "@calcom/features": "workspace:*", + "@calcom/i18n": "workspace:*", "@calcom/lib": "workspace:*" }, "peerDependencies": { diff --git a/packages/platform/libraries/vite.config.js b/packages/platform/libraries/vite.config.js index 48619f12fc..68e436b32c 100644 --- a/packages/platform/libraries/vite.config.js +++ b/packages/platform/libraries/vite.config.js @@ -57,6 +57,7 @@ export default defineConfig({ }, rollupOptions: { external: [ + "@calcom/i18n", "react", "fs", "path", @@ -210,9 +211,6 @@ export default defineConfig({ resolve: { conditions: ["node", "import", "require", "default"], alias: { - "@calcom/lib/server/i18n": path.resolve(__dirname, "./i18n.ts"), - "./server/i18n": path.resolve(__dirname, "./i18n.ts"), - "../server/i18n": path.resolve(__dirname, "./i18n.ts"), "@": path.resolve(__dirname, "./src"), "@calcom/lib": path.resolve(__dirname, "../../lib"), "@calcom/trpc": resolve("../../trpc"), diff --git a/packages/testing/package.json b/packages/testing/package.json index de9ad069e7..dbce9865b5 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -15,6 +15,7 @@ "lint:report": "biome lint --reporter json . > ../../lint-results/testing.json" }, "dependencies": { + "@calcom/i18n": "workspace:*", "@calcom/lib": "workspace:*", "@calcom/prisma": "workspace:*" }, diff --git a/packages/testing/src/lib/__mocks__/libServerI18n.ts b/packages/testing/src/lib/__mocks__/libServerI18n.ts index b3e7b9771b..79b9e3d5f6 100644 --- a/packages/testing/src/lib/__mocks__/libServerI18n.ts +++ b/packages/testing/src/lib/__mocks__/libServerI18n.ts @@ -1,8 +1,8 @@ -import type * as i18n from "@calcom/lib/server/i18n"; +import type * as i18n from "@calcom/i18n/server"; import { beforeEach, vi } from "vitest"; import { mockDeep, mockReset } from "vitest-mock-extended"; -vi.mock("@calcom/lib/server/i18n", () => i18nMock); +vi.mock("@calcom/i18n/server", () => i18nMock); beforeEach(() => { mockReset(i18nMock); diff --git a/packages/testing/src/lib/bookingScenario/bookingScenario.ts b/packages/testing/src/lib/bookingScenario/bookingScenario.ts index ee774005e2..08c105fc73 100644 --- a/packages/testing/src/lib/bookingScenario/bookingScenario.ts +++ b/packages/testing/src/lib/bookingScenario/bookingScenario.ts @@ -1,4 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ +import type { TFunction } from "i18next"; + import i18nMock from "../__mocks__/libServerI18n"; import prismock from "../__mocks__/prisma"; import { v4 as uuidv4 } from "uuid"; @@ -1718,7 +1720,7 @@ export function mockNoTranslations() { log.silly("Mocking i18n.getTranslation to return identity function"); i18nMock.getTranslation.mockImplementation(() => { return new Promise((resolve) => { - const identityFn = (key: string) => key; + const identityFn = ((key: string) => key) as TFunction; resolve(identityFn); }); }); diff --git a/packages/trpc/package.json b/packages/trpc/package.json index 55454b3cee..65acf02a12 100644 --- a/packages/trpc/package.json +++ b/packages/trpc/package.json @@ -14,6 +14,7 @@ "build:react": "yarn tsc --project tsconfig.react.json" }, "dependencies": { + "@calcom/i18n": "workspace:*", "@formbricks/api": "3.0.0", "@trpc/client": "11.0.0-next-beta.222", "@trpc/next": "11.0.0-next-beta.222", diff --git a/packages/trpc/server/routers/apps/routing-forms/getFormResponseDisplay.handler.ts b/packages/trpc/server/routers/apps/routing-forms/getFormResponseDisplay.handler.ts index 446eda344f..a47a2c04d4 100644 --- a/packages/trpc/server/routers/apps/routing-forms/getFormResponseDisplay.handler.ts +++ b/packages/trpc/server/routers/apps/routing-forms/getFormResponseDisplay.handler.ts @@ -6,7 +6,7 @@ import type { FormResponse } from "@calcom/app-store/routing-forms/types/types"; import { zodFields } from "@calcom/app-store/routing-forms/zod"; import { canAccessEntity } from "@calcom/features/pbac/lib/entityPermissionUtils.server"; import { PrismaRoutingFormResponseRepository } from "@calcom/features/routing-forms/repositories/PrismaRoutingFormResponseRepository"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import type { TrpcSessionUser } from "@calcom/trpc/server/types"; import { TRPCError } from "@trpc/server"; diff --git a/packages/trpc/server/routers/apps/routing-forms/getResponseWithFormFields.handler.ts b/packages/trpc/server/routers/apps/routing-forms/getResponseWithFormFields.handler.ts index d5e9e6ebfd..739603e349 100644 --- a/packages/trpc/server/routers/apps/routing-forms/getResponseWithFormFields.handler.ts +++ b/packages/trpc/server/routers/apps/routing-forms/getResponseWithFormFields.handler.ts @@ -4,7 +4,7 @@ import { enrichFormWithMigrationData } from "@calcom/app-store/routing-forms/enr import { getSerializableForm } from "@calcom/app-store/routing-forms/lib/getSerializableForm"; import type { FormResponse } from "@calcom/app-store/routing-forms/types/types"; import { canAccessEntity } from "@calcom/features/pbac/lib/entityPermissionUtils.server"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { prisma } from "@calcom/prisma"; import type { TrpcSessionUser } from "@calcom/trpc/server/types"; diff --git a/packages/trpc/server/routers/loggedInViewer/connectAndJoin.handler.ts b/packages/trpc/server/routers/loggedInViewer/connectAndJoin.handler.ts index 6b0364bcfd..7874c5f47b 100644 --- a/packages/trpc/server/routers/loggedInViewer/connectAndJoin.handler.ts +++ b/packages/trpc/server/routers/loggedInViewer/connectAndJoin.handler.ts @@ -2,7 +2,7 @@ import { sendScheduledEmailsAndSMS } from "@calcom/emails/email-manager"; import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses"; import { scheduleNoShowTriggers } from "@calcom/features/bookings/lib/handleNewBooking/scheduleNoShowTriggers"; import { isPrismaObjOrUndefined } from "@calcom/lib/isPrismaObj"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat"; import { prisma } from "@calcom/prisma"; import { BookingStatus } from "@calcom/prisma/enums"; diff --git a/packages/trpc/server/routers/viewer/admin/sendPasswordReset.handler.ts b/packages/trpc/server/routers/viewer/admin/sendPasswordReset.handler.ts index 705a344d50..53a36e7678 100644 --- a/packages/trpc/server/routers/viewer/admin/sendPasswordReset.handler.ts +++ b/packages/trpc/server/routers/viewer/admin/sendPasswordReset.handler.ts @@ -1,7 +1,7 @@ import dayjs from "@calcom/dayjs"; import { sendPasswordResetEmail } from "@calcom/emails/auth-email-service"; import { PASSWORD_RESET_EXPIRY_HOURS } from "@calcom/features/auth/lib/passwordResetRequest"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { prisma } from "@calcom/prisma"; import type { TrpcSessionUser } from "../../../types"; diff --git a/packages/trpc/server/routers/viewer/apps/locationOptions.handler.ts b/packages/trpc/server/routers/viewer/apps/locationOptions.handler.ts index f82025edfc..b37184c9ad 100644 --- a/packages/trpc/server/routers/viewer/apps/locationOptions.handler.ts +++ b/packages/trpc/server/routers/viewer/apps/locationOptions.handler.ts @@ -1,5 +1,5 @@ import { getLocationGroupedOptions } from "@calcom/app-store/server"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import type { TrpcSessionUser } from "@calcom/trpc/server/types"; import type { TLocationOptionsInputSchema } from "./locationOptions.schema"; diff --git a/packages/trpc/server/routers/viewer/apps/toggle.handler.ts b/packages/trpc/server/routers/viewer/apps/toggle.handler.ts index 448c654385..33f2cd4ac8 100644 --- a/packages/trpc/server/routers/viewer/apps/toggle.handler.ts +++ b/packages/trpc/server/routers/viewer/apps/toggle.handler.ts @@ -1,6 +1,6 @@ import { getLocalAppMetadata } from "@calcom/app-store/utils"; import { sendDisabledAppEmail } from "@calcom/emails/integration-email-service"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import type { PrismaClient } from "@calcom/prisma"; import { AppCategories } from "@calcom/prisma/enums"; diff --git a/packages/trpc/server/routers/viewer/bookings/addGuests.handler.ts b/packages/trpc/server/routers/viewer/bookings/addGuests.handler.ts index 90d6c82889..85ae52d13f 100644 --- a/packages/trpc/server/routers/viewer/bookings/addGuests.handler.ts +++ b/packages/trpc/server/routers/viewer/bookings/addGuests.handler.ts @@ -13,7 +13,7 @@ import { UserRepository } from "@calcom/features/users/repositories/UserReposito import { extractBaseEmail } from "@calcom/lib/extract-base-email"; import { parseRecurringEvent } from "@calcom/lib/isRecurringEvent"; import logger from "@calcom/lib/logger"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { prisma } from "@calcom/prisma"; import { MembershipRole } from "@calcom/prisma/enums"; import type { BookingResponses } from "@calcom/prisma/zod-utils"; diff --git a/packages/trpc/server/routers/viewer/bookings/confirm.handler.ts b/packages/trpc/server/routers/viewer/bookings/confirm.handler.ts index c97c4526ff..852bb13058 100644 --- a/packages/trpc/server/routers/viewer/bookings/confirm.handler.ts +++ b/packages/trpc/server/routers/viewer/bookings/confirm.handler.ts @@ -25,9 +25,9 @@ import getOrgIdFromMemberOrTeamId from "@calcom/lib/getOrgIdFromMemberOrTeamId"; import { getTeamIdFromEventType } from "@calcom/lib/getTeamIdFromEventType"; import { isPrismaObjOrUndefined } from "@calcom/lib/isPrismaObj"; import { parseRecurringEvent } from "@calcom/lib/isRecurringEvent"; +import { getTranslation } from "@calcom/i18n/server"; import logger from "@calcom/lib/logger"; import { safeStringify } from "@calcom/lib/safeStringify"; -import { getTranslation } from "@calcom/lib/server/i18n"; import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat"; import type { TraceContext } from "@calcom/lib/tracing"; import { prisma } from "@calcom/prisma"; diff --git a/packages/trpc/server/routers/viewer/bookings/editLocation.handler.ts b/packages/trpc/server/routers/viewer/bookings/editLocation.handler.ts index fdb0aff36a..54cc38eb7a 100644 --- a/packages/trpc/server/routers/viewer/bookings/editLocation.handler.ts +++ b/packages/trpc/server/routers/viewer/bookings/editLocation.handler.ts @@ -15,7 +15,7 @@ import { buildCalEventFromBooking } from "@calcom/lib/buildCalEventFromBooking"; import { getVideoCallUrlFromCalEvent } from "@calcom/lib/CalEventParser"; import logger from "@calcom/lib/logger"; import { safeStringify } from "@calcom/lib/safeStringify"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { prisma } from "@calcom/prisma"; import type { Booking, BookingReference } from "@calcom/prisma/client"; import type { EventTypeMetadata, userMetadata } from "@calcom/prisma/zod-utils"; diff --git a/packages/trpc/server/routers/viewer/bookings/getBookingHistory.handler.ts b/packages/trpc/server/routers/viewer/bookings/getBookingHistory.handler.ts index 0e05722f47..86901a933b 100644 --- a/packages/trpc/server/routers/viewer/bookings/getBookingHistory.handler.ts +++ b/packages/trpc/server/routers/viewer/bookings/getBookingHistory.handler.ts @@ -9,7 +9,7 @@ import { BookingAuditErrorCode, BookingAuditPermissionError, } from "@calcom/features/booking-audit/lib/service/BookingAuditAccessService"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import type { TrpcSessionUser } from "../../../types"; import type { TGetBookingHistoryInputSchema } from "./getBookingHistory.schema"; diff --git a/packages/trpc/server/routers/viewer/bookings/reportWrongAssignment.handler.test.ts b/packages/trpc/server/routers/viewer/bookings/reportWrongAssignment.handler.test.ts index db4f44ba80..1df427eac4 100644 --- a/packages/trpc/server/routers/viewer/bookings/reportWrongAssignment.handler.test.ts +++ b/packages/trpc/server/routers/viewer/bookings/reportWrongAssignment.handler.test.ts @@ -44,7 +44,7 @@ vi.mock("@calcom/features/webhooks/lib/sendPayload"); vi.mock("@calcom/prisma", () => ({ default: {}, })); -vi.mock("@calcom/lib/server/i18n", () => ({ +vi.mock("@calcom/i18n/server", () => ({ getTranslation: vi.fn().mockResolvedValue((key: string) => { const translations: Record = { wrong_assignment_already_reported: diff --git a/packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts b/packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts index ef77ee55e6..9c5ca97107 100644 --- a/packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts +++ b/packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts @@ -27,7 +27,7 @@ import getOrgIdFromMemberOrTeamId from "@calcom/lib/getOrgIdFromMemberOrTeamId"; import { getTeamIdFromEventType } from "@calcom/lib/getTeamIdFromEventType"; import logger from "@calcom/lib/logger"; import { safeStringify } from "@calcom/lib/safeStringify"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { BookingWebhookFactory } from "@calcom/lib/server/service/BookingWebhookFactory"; import { prisma } from "@calcom/prisma"; import type { BookingReference, EventType } from "@calcom/prisma/client"; diff --git a/packages/trpc/server/routers/viewer/delegationCredential/_router.ts b/packages/trpc/server/routers/viewer/delegationCredential/_router.ts index ffd602c00d..cdd92c462f 100644 --- a/packages/trpc/server/routers/viewer/delegationCredential/_router.ts +++ b/packages/trpc/server/routers/viewer/delegationCredential/_router.ts @@ -1,5 +1,5 @@ import { FeaturesRepository } from "@calcom/features/flags/features.repository"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import prisma from "@calcom/prisma"; import { TRPCError } from "@trpc/server"; diff --git a/packages/trpc/server/routers/viewer/delegationCredential/toggleEnabled.handler.ts b/packages/trpc/server/routers/viewer/delegationCredential/toggleEnabled.handler.ts index 59a5a17793..22dfe5acfb 100644 --- a/packages/trpc/server/routers/viewer/delegationCredential/toggleEnabled.handler.ts +++ b/packages/trpc/server/routers/viewer/delegationCredential/toggleEnabled.handler.ts @@ -3,7 +3,7 @@ import { sendDelegationCredentialDisabledEmail } from "@calcom/emails/integratio import type { ServiceAccountKey } from "@calcom/features/delegation-credentials/repositories/DelegationCredentialRepository"; import { DelegationCredentialRepository } from "@calcom/features/delegation-credentials/repositories/DelegationCredentialRepository"; import logger from "@calcom/lib/logger"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import type { z } from "zod"; import { getAffectedMembersForDisable } from "./getAffectedMembersForDisable.handler"; diff --git a/packages/trpc/server/routers/viewer/eventTypes/heavy/update.handler.ts b/packages/trpc/server/routers/viewer/eventTypes/heavy/update.handler.ts index 39217ad622..0d05f9edbb 100644 --- a/packages/trpc/server/routers/viewer/eventTypes/heavy/update.handler.ts +++ b/packages/trpc/server/routers/viewer/eventTypes/heavy/update.handler.ts @@ -18,7 +18,7 @@ import tasker from "@calcom/features/tasker"; import { submitUrlForUrlScanning } from "@calcom/features/tasker/tasks/scanWorkflowUrls"; import { validateIntervalLimitOrder } from "@calcom/lib/intervalLimits/validateIntervalLimitOrder"; import logger from "@calcom/lib/logger"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { validateBookerLayouts } from "@calcom/lib/validateBookerLayouts"; import type { PrismaClient } from "@calcom/prisma"; import { Prisma } from "@calcom/prisma/client"; diff --git a/packages/trpc/server/routers/viewer/i18n/i18n.handler.test.ts b/packages/trpc/server/routers/viewer/i18n/i18n.handler.test.ts new file mode 100644 index 0000000000..5858fff8ba --- /dev/null +++ b/packages/trpc/server/routers/viewer/i18n/i18n.handler.test.ts @@ -0,0 +1,54 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; + +vi.mock("next-i18next/serverSideTranslations", () => ({ + serverSideTranslations: vi.fn(), +})); + +import { i18nHandler } from "./i18n.handler"; + +describe("i18n handler", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + it("passes i18n config to serverSideTranslations", async () => { + const { serverSideTranslations } = await import("next-i18next/serverSideTranslations"); + const mockedSST = vi.mocked(serverSideTranslations); + + const fakeResult = { + _nextI18Next: { + initialLocale: "en", + ns: ["common", "vital"], + }, + }; + mockedSST.mockResolvedValueOnce(fakeResult); + + const result = await i18nHandler({ input: { locale: "en", CalComVersion: "1.0" } }); + + expect(mockedSST).toHaveBeenCalledOnce(); + const [locale, namespaces, config] = mockedSST.mock.calls[0]; + expect(locale).toBe("en"); + expect(namespaces).toEqual(["common", "vital"]); + expect(config).toBeDefined(); + expect(config).toHaveProperty("i18n"); + expect(config).toHaveProperty("localePath"); + expect(result.i18n).toBe(fakeResult); + expect(result.locale).toBe("en"); + }); + + it("passes the locale from input to serverSideTranslations", async () => { + const { serverSideTranslations } = await import("next-i18next/serverSideTranslations"); + const mockedSST = vi.mocked(serverSideTranslations); + + mockedSST.mockResolvedValueOnce({ + _nextI18Next: { + initialLocale: "fr", + ns: ["common", "vital"], + }, + }); + + const result = await i18nHandler({ input: { locale: "fr", CalComVersion: "1.0" } }); + + expect(mockedSST.mock.calls[0][0]).toBe("fr"); + expect(result.locale).toBe("fr"); + }); +}); diff --git a/packages/trpc/server/routers/viewer/i18n/i18n.handler.ts b/packages/trpc/server/routers/viewer/i18n/i18n.handler.ts index e21acb5f22..649c649809 100644 --- a/packages/trpc/server/routers/viewer/i18n/i18n.handler.ts +++ b/packages/trpc/server/routers/viewer/i18n/i18n.handler.ts @@ -1,3 +1,4 @@ +import i18nConfig from "@calcom/i18n/next-i18next.config"; import type { I18nInputSchema } from "./i18n.schema"; type I18nOptions = { @@ -7,7 +8,7 @@ type I18nOptions = { export const i18nHandler = async ({ input }: I18nOptions) => { const { locale } = input; const { serverSideTranslations } = await import("next-i18next/serverSideTranslations"); - const i18n = await serverSideTranslations(locale, ["common", "vital"]); + const i18n = await serverSideTranslations(locale, ["common", "vital"], i18nConfig); return { i18n, diff --git a/packages/trpc/server/routers/viewer/i18n/i18n.schema.ts b/packages/trpc/server/routers/viewer/i18n/i18n.schema.ts index f17f615871..eb91704b6d 100644 --- a/packages/trpc/server/routers/viewer/i18n/i18n.schema.ts +++ b/packages/trpc/server/routers/viewer/i18n/i18n.schema.ts @@ -2,7 +2,7 @@ import { lookup } from "bcp-47-match"; import { z } from "zod"; // eslint-disable-next-line @typescript-eslint/no-var-requires -const { i18n } = require("@calcom/config/next-i18next.config"); +const { i18n } = require("@calcom/i18n/next-i18next.config"); export const i18nInputSchema = z.object({ locale: z diff --git a/packages/trpc/server/routers/viewer/me/updateProfile.handler.ts b/packages/trpc/server/routers/viewer/me/updateProfile.handler.ts index e587f27eb4..3a0e830cc2 100644 --- a/packages/trpc/server/routers/viewer/me/updateProfile.handler.ts +++ b/packages/trpc/server/routers/viewer/me/updateProfile.handler.ts @@ -12,7 +12,7 @@ import hasKeyInMetadata from "@calcom/lib/hasKeyInMetadata"; import { HttpError } from "@calcom/lib/http-error"; import logger from "@calcom/lib/logger"; import { uploadAvatar } from "@calcom/lib/server/avatar"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { resizeBase64Image } from "@calcom/lib/server/resizeBase64Image"; import slugify from "@calcom/lib/slugify"; import { validateBookerLayouts } from "@calcom/lib/validateBookerLayouts"; diff --git a/packages/trpc/server/routers/viewer/oAuth/submitClientForReview.handler.test.ts b/packages/trpc/server/routers/viewer/oAuth/submitClientForReview.handler.test.ts index 085db2040a..1a9ec18109 100644 --- a/packages/trpc/server/routers/viewer/oAuth/submitClientForReview.handler.test.ts +++ b/packages/trpc/server/routers/viewer/oAuth/submitClientForReview.handler.test.ts @@ -26,7 +26,7 @@ vi.mock("@calcom/emails/oauth-email-service", () => ({ sendAdminOAuthClientNotification: mocks.sendAdminOAuthClientNotification, })); -vi.mock("@calcom/lib/server/i18n", () => ({ +vi.mock("@calcom/i18n/server", () => ({ getTranslation: mocks.getTranslation, })); diff --git a/packages/trpc/server/routers/viewer/oAuth/submitClientForReview.handler.ts b/packages/trpc/server/routers/viewer/oAuth/submitClientForReview.handler.ts index e370f52701..f0c41d8657 100644 --- a/packages/trpc/server/routers/viewer/oAuth/submitClientForReview.handler.ts +++ b/packages/trpc/server/routers/viewer/oAuth/submitClientForReview.handler.ts @@ -1,5 +1,5 @@ import { sendAdminOAuthClientNotification } from "@calcom/emails/oauth-email-service"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { OAuthClientRepository } from "@calcom/features/oauth/repositories/OAuthClientRepository"; import { generateSecret } from "@calcom/features/oauth/utils/generateSecret"; import type { PrismaClient } from "@calcom/prisma"; diff --git a/packages/trpc/server/routers/viewer/oAuth/updateClient.handler.test.ts b/packages/trpc/server/routers/viewer/oAuth/updateClient.handler.test.ts index 8b34f12eba..ec6281367d 100644 --- a/packages/trpc/server/routers/viewer/oAuth/updateClient.handler.test.ts +++ b/packages/trpc/server/routers/viewer/oAuth/updateClient.handler.test.ts @@ -43,7 +43,7 @@ vi.mock("@calcom/emails/oauth-email-service", () => ({ sendOAuthClientRejectedNotification: mocks.sendOAuthClientRejectedNotification, })); -vi.mock("@calcom/lib/server/i18n", () => ({ +vi.mock("@calcom/i18n/server", () => ({ getTranslation: mocks.getTranslation, })); diff --git a/packages/trpc/server/routers/viewer/oAuth/updateClient.handler.ts b/packages/trpc/server/routers/viewer/oAuth/updateClient.handler.ts index a49197d13c..72b7b2b7f4 100644 --- a/packages/trpc/server/routers/viewer/oAuth/updateClient.handler.ts +++ b/packages/trpc/server/routers/viewer/oAuth/updateClient.handler.ts @@ -1,10 +1,7 @@ import { TRPCError } from "@trpc/server"; -import { - sendOAuthClientApprovedNotification, - sendOAuthClientRejectedNotification, -} from "@calcom/emails/oauth-email-service"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { sendOAuthClientApprovedNotification, sendOAuthClientRejectedNotification } from "@calcom/emails/oauth-email-service"; +import { getTranslation } from "@calcom/i18n/server"; import { OAuthClientRepository } from "@calcom/features/oauth/repositories/OAuthClientRepository"; import type { PrismaClient } from "@calcom/prisma"; import { UserPermissionRole } from "@calcom/prisma/enums"; diff --git a/packages/trpc/server/routers/viewer/ooo/outOfOfficeCreateOrUpdate.handler.ts b/packages/trpc/server/routers/viewer/ooo/outOfOfficeCreateOrUpdate.handler.ts index b33795e6e4..0b4b2c5695 100644 --- a/packages/trpc/server/routers/viewer/ooo/outOfOfficeCreateOrUpdate.handler.ts +++ b/packages/trpc/server/routers/viewer/ooo/outOfOfficeCreateOrUpdate.handler.ts @@ -7,7 +7,7 @@ import type { GetSubscriberOptions } from "@calcom/features/webhooks/lib/getWebh import getWebhooks from "@calcom/features/webhooks/lib/getWebhooks"; import type { OOOEntryPayloadType } from "@calcom/features/webhooks/lib/sendPayload"; import sendPayload from "@calcom/features/webhooks/lib/sendPayload"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import prisma from "@calcom/prisma"; import { WebhookTriggerEvents } from "@calcom/prisma/enums"; import type { TrpcSessionUser } from "@calcom/trpc/server/types"; diff --git a/packages/trpc/server/routers/viewer/ooo/outOfOfficeEntriesList.handler.ts b/packages/trpc/server/routers/viewer/ooo/outOfOfficeEntriesList.handler.ts index 0d2715171e..54bb84feec 100644 --- a/packages/trpc/server/routers/viewer/ooo/outOfOfficeEntriesList.handler.ts +++ b/packages/trpc/server/routers/viewer/ooo/outOfOfficeEntriesList.handler.ts @@ -1,5 +1,5 @@ import { checkAdminOrOwner } from "@calcom/features/auth/lib/checkAdminOrOwner"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import prisma from "@calcom/prisma"; import type { TrpcSessionUser } from "@calcom/trpc/server/types"; diff --git a/packages/trpc/server/routers/viewer/ooo/outOfOfficeEntryDelete.handler.ts b/packages/trpc/server/routers/viewer/ooo/outOfOfficeEntryDelete.handler.ts index 22ad598ad8..587d6030b2 100644 --- a/packages/trpc/server/routers/viewer/ooo/outOfOfficeEntryDelete.handler.ts +++ b/packages/trpc/server/routers/viewer/ooo/outOfOfficeEntryDelete.handler.ts @@ -1,5 +1,5 @@ import { sendBookingRedirectNotification } from "@calcom/emails/workflow-email-service"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import prisma from "@calcom/prisma"; import type { TrpcSessionUser } from "@calcom/trpc/server/types"; diff --git a/packages/trpc/server/routers/viewer/organizations/create.handler.test.ts b/packages/trpc/server/routers/viewer/organizations/create.handler.test.ts index 7373ade39d..bbcd7d871c 100644 --- a/packages/trpc/server/routers/viewer/organizations/create.handler.test.ts +++ b/packages/trpc/server/routers/viewer/organizations/create.handler.test.ts @@ -18,7 +18,7 @@ vi.mock("@calcom/lib/domainManager/organization", () => ({ createDomain: vi.fn().mockResolvedValue(true), })); -vi.mock("@calcom/lib/server/i18n", () => ({ +vi.mock("@calcom/i18n/server", () => ({ getTranslation: vi.fn().mockResolvedValue((key: string) => key), })); diff --git a/packages/trpc/server/routers/viewer/organizations/create.handler.ts b/packages/trpc/server/routers/viewer/organizations/create.handler.ts index 34d89f1ea5..1501a76219 100644 --- a/packages/trpc/server/routers/viewer/organizations/create.handler.ts +++ b/packages/trpc/server/routers/viewer/organizations/create.handler.ts @@ -17,7 +17,7 @@ import { WEBAPP_URL, } from "@calcom/lib/constants"; import { createDomain } from "@calcom/lib/domainManager/organization"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { prisma } from "@calcom/prisma"; import { UserPermissionRole } from "@calcom/prisma/enums"; diff --git a/packages/trpc/server/routers/viewer/organizations/intentToCreateOrg.handler.test.ts b/packages/trpc/server/routers/viewer/organizations/intentToCreateOrg.handler.test.ts index 7a994ab20e..2b63754e41 100644 --- a/packages/trpc/server/routers/viewer/organizations/intentToCreateOrg.handler.test.ts +++ b/packages/trpc/server/routers/viewer/organizations/intentToCreateOrg.handler.test.ts @@ -44,13 +44,15 @@ vi.mock("@calcom/trpc/server/routers/viewer/teams/inviteMember/inviteMember.hand inviteMembersWithNoInviterPermissionCheck: vi.fn().mockResolvedValue({}), })); -vi.mock("@calcom/lib/server/i18n", () => ({ - getTranslation: vi.fn().mockImplementation(async (locale: string, namespace: string) => { - const t = (key: string) => key; - t.locale = locale; - t.namespace = namespace; - return t; - }), +vi.mock("@calcom/i18n/server", () => ({ + getTranslation: vi + .fn() + .mockImplementation(async (locale: string, namespace: string) => { + const t = (key: string) => key; + t.locale = locale; + t.namespace = namespace; + return t; + }), })); vi.mock("@calcom/lib/domainManager/organization", () => ({ diff --git a/packages/trpc/server/routers/viewer/teams/inviteMember/__mocks__/getTranslation.ts b/packages/trpc/server/routers/viewer/teams/inviteMember/__mocks__/getTranslation.ts index cd68e7d9b8..8a73825684 100644 --- a/packages/trpc/server/routers/viewer/teams/inviteMember/__mocks__/getTranslation.ts +++ b/packages/trpc/server/routers/viewer/teams/inviteMember/__mocks__/getTranslation.ts @@ -1,9 +1,10 @@ +import type { TFunction } from "i18next"; import { beforeEach, vi } from "vitest"; import { mockReset, mockDeep } from "vitest-mock-extended"; -import type * as getTranslation from "@calcom/lib/server/i18n"; +import type * as getTranslation from "@calcom/i18n/server"; -vi.mock("@calcom/lib/server/i18n", () => getTranslationMock); +vi.mock("@calcom/i18n/server", () => getTranslationMock); beforeEach(() => { mockReset(getTranslationMock); @@ -13,7 +14,9 @@ const getTranslationMock = mockDeep(); export const mock = { fakeIdentityFn: () => - getTranslationMock.getTranslation.mockImplementation(async () => (key: string) => key), + getTranslationMock.getTranslation.mockImplementation( + async () => ((key: string) => key) as TFunction + ), }; export default getTranslationMock; diff --git a/packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.integration-test.ts b/packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.integration-test.ts index ca4ede014f..681bebdd1c 100644 --- a/packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.integration-test.ts +++ b/packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.integration-test.ts @@ -124,7 +124,7 @@ vi.mock("@calcom/emails/organization-email-service", () => ({ })); // Mock for getTranslation -vi.mock("@calcom/lib/server/i18n", () => ({ +vi.mock("@calcom/i18n/server", () => ({ getTranslation: vi.fn(() => Promise.resolve((key: string) => key)), })); diff --git a/packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.ts b/packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.ts index 1bf6316f69..1e469002bc 100644 --- a/packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.ts +++ b/packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.ts @@ -7,7 +7,7 @@ import { UserRepository } from "@calcom/features/users/repositories/UserReposito import { checkRateLimitAndThrowError } from "@calcom/lib/checkRateLimitAndThrowError"; import logger from "@calcom/lib/logger"; import { safeStringify } from "@calcom/lib/safeStringify"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { isOrganisationOwner } from "@calcom/features/pbac/utils/isOrganisationAdmin"; import prisma from "@calcom/prisma"; import { MembershipRole } from "@calcom/prisma/enums"; diff --git a/packages/trpc/server/routers/viewer/teams/inviteMember/inviteMemberUtils.test.ts b/packages/trpc/server/routers/viewer/teams/inviteMember/inviteMemberUtils.test.ts index 7067d8c03c..92baf8dce9 100644 --- a/packages/trpc/server/routers/viewer/teams/inviteMember/inviteMemberUtils.test.ts +++ b/packages/trpc/server/routers/viewer/teams/inviteMember/inviteMemberUtils.test.ts @@ -78,7 +78,7 @@ vi.mock("@calcom/features/ee/billing/service/seatTracking/SeatChangeTrackingServ }, })); -vi.mock("@calcom/lib/server/i18n", () => ({ +vi.mock("@calcom/i18n/server", () => ({ getTranslation: vi.fn().mockResolvedValue((key: string) => key), })); diff --git a/packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts b/packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts index 4016351c84..36b28a297d 100644 --- a/packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts +++ b/packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts @@ -17,7 +17,7 @@ import { DEFAULT_SCHEDULE, getAvailabilityFromSchedule } from "@calcom/lib/avail import { ENABLE_PROFILE_SWITCHER } from "@calcom/lib/constants"; import logger from "@calcom/lib/logger"; import { safeStringify } from "@calcom/lib/safeStringify"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import slugify from "@calcom/lib/slugify"; import { prisma } from "@calcom/prisma"; import type { OrganizationSettings, Team } from "@calcom/prisma/client"; diff --git a/packages/trpc/server/routers/viewer/teams/resendInvitation.handler.ts b/packages/trpc/server/routers/viewer/teams/resendInvitation.handler.ts index 562c78f5e7..49b401e332 100644 --- a/packages/trpc/server/routers/viewer/teams/resendInvitation.handler.ts +++ b/packages/trpc/server/routers/viewer/teams/resendInvitation.handler.ts @@ -2,7 +2,7 @@ import { sendTeamInviteEmail } from "@calcom/emails/organization-email-service"; import { OnboardingPathService } from "@calcom/features/onboarding/lib/onboarding-path.service"; import { UserRepository } from "@calcom/features/users/repositories/UserRepository"; import { WEBAPP_URL } from "@calcom/lib/constants"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { VerificationTokenRepository } from "@calcom/app-store/stripepayment/lib/repositories/VerificationTokenRepository"; import { prisma } from "@calcom/prisma"; import type { TrpcSessionUser } from "@calcom/trpc/server/types"; diff --git a/packages/trpc/server/routers/viewer/webhook/testTrigger.handler.ts b/packages/trpc/server/routers/viewer/webhook/testTrigger.handler.ts index a12cb6fb97..b5a3502957 100644 --- a/packages/trpc/server/routers/viewer/webhook/testTrigger.handler.ts +++ b/packages/trpc/server/routers/viewer/webhook/testTrigger.handler.ts @@ -2,7 +2,7 @@ import { DEFAULT_WEBHOOK_VERSION } from "@calcom/features/webhooks/lib/interface import type { EventPayloadType } from "@calcom/features/webhooks/lib/sendPayload"; import sendPayload from "@calcom/features/webhooks/lib/sendPayload"; import { validateUrlForSSRFSync } from "@calcom/lib/ssrfProtection"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import type { TTestTriggerInputSchema } from "./testTrigger.schema"; diff --git a/packages/trpc/server/routers/viewer/workflows/create.handler.ts b/packages/trpc/server/routers/viewer/workflows/create.handler.ts index 0c08e667bb..4c51d809e3 100644 --- a/packages/trpc/server/routers/viewer/workflows/create.handler.ts +++ b/packages/trpc/server/routers/viewer/workflows/create.handler.ts @@ -1,7 +1,7 @@ import emailReminderTemplate from "@calcom/ee/workflows/lib/reminders/templates/emailReminderTemplate"; import { PermissionCheckService } from "@calcom/features/pbac/services/permission-check.service"; import { SENDER_NAME } from "@calcom/lib/constants"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat"; import type { PrismaClient } from "@calcom/prisma"; import { prisma } from "@calcom/prisma"; diff --git a/packages/trpc/server/routers/viewer/workflows/getWorkflowActionOptions.handler.ts b/packages/trpc/server/routers/viewer/workflows/getWorkflowActionOptions.handler.ts index 5317ad041c..78431083bb 100644 --- a/packages/trpc/server/routers/viewer/workflows/getWorkflowActionOptions.handler.ts +++ b/packages/trpc/server/routers/viewer/workflows/getWorkflowActionOptions.handler.ts @@ -1,5 +1,5 @@ import { getWorkflowActionOptions } from "@calcom/features/ee/workflows/lib/getOptions"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import type { TrpcSessionUser } from "@calcom/trpc/server/types"; type GetWorkflowActionOptionsOptions = { diff --git a/packages/trpc/server/routers/viewer/workflows/util.ts b/packages/trpc/server/routers/viewer/workflows/util.ts index f9233baeba..f9202eaeb6 100644 --- a/packages/trpc/server/routers/viewer/workflows/util.ts +++ b/packages/trpc/server/routers/viewer/workflows/util.ts @@ -12,7 +12,7 @@ import { import { removeBookingField, upsertBookingField } from "@calcom/features/eventtypes/lib/bookingFieldsManager"; import { SMS_REMINDER_NUMBER_FIELD, CAL_AI_AGENT_PHONE_NUMBER_FIELD } from "@calcom/lib/bookings/SystemField"; import { SENDER_ID, SENDER_NAME } from "@calcom/lib/constants"; -import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTranslation } from "@calcom/i18n/server"; import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat"; import prisma from "@calcom/prisma"; import type { WorkflowStep } from "@calcom/prisma/client"; diff --git a/turbo.json b/turbo.json index 7a7c2ddb56..cf7697f8e4 100644 --- a/turbo.json +++ b/turbo.json @@ -537,10 +537,7 @@ }, "post-install": { "dependsOn": [], - "outputs": [ - "../../node_modules/@prisma/client/**", - "../../node_modules/@prisma/admin-client/**" - ], + "outputs": ["../../node_modules/@prisma/client/**", "../../node_modules/@prisma/admin-client/**"], "inputs": ["./schema.prisma", "./prisma/schema.prisma"], "env": ["PRISMA_GENERATE_DATAPROXY"] }, @@ -581,10 +578,7 @@ "../../packages/app-store/**/pages/**", "../../packages/app-store-cli/src/**" ], - "outputs": [ - "../../packages/app-store/*.generated.ts", - "../../packages/app-store/*.generated.tsx" - ] + "outputs": ["../../packages/app-store/*.generated.ts", "../../packages/app-store/*.generated.tsx"] }, "@calcom/embed-react#type-check": { "dependsOn": ["@calcom/embed-core#build", "@calcom/embed-snippet#build"], diff --git a/yarn.lock b/yarn.lock index bb00aaffca..beb8889981 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2065,6 +2065,7 @@ __metadata: "@calcom/dailyvideo": "workspace:*" "@calcom/dayjs": "workspace:*" "@calcom/features": "workspace:*" + "@calcom/i18n": "workspace:*" "@calcom/lib": "workspace:*" "@calcom/office365video": "workspace:*" "@calcom/testing": "workspace:*" @@ -2096,6 +2097,7 @@ __metadata: version: 0.0.0-use.local resolution: "@calcom/atoms@workspace:packages/platform/atoms" dependencies: + "@calcom/i18n": "workspace:*" "@radix-ui/react-dialog-atoms": "npm:@radix-ui/react-dialog@1.0.4" "@radix-ui/react-popover-atoms": "npm:@radix-ui/react-popover@1.0.6" "@radix-ui/react-slot": "npm:1.1.2" @@ -2309,6 +2311,7 @@ __metadata: version: 0.0.0-use.local resolution: "@calcom/ee@workspace:packages/features/ee" dependencies: + "@calcom/i18n": "workspace:*" "@calcom/lib": "workspace:*" "@calcom/tsconfig": "workspace:*" "@calcom/ui": "workspace:*" @@ -2496,6 +2499,7 @@ __metadata: resolution: "@calcom/feature-auth@workspace:packages/features/auth" dependencies: "@calcom/dayjs": "workspace:*" + "@calcom/i18n": "workspace:*" "@calcom/lib": "workspace:*" "@calcom/prisma": "workspace:*" "@calcom/trpc": "workspace:*" @@ -2517,6 +2521,7 @@ __metadata: dependencies: "@calcom/atoms": "workspace:*" "@calcom/dayjs": "workspace:*" + "@calcom/i18n": "workspace:*" "@calcom/lib": "workspace:*" "@calcom/testing": "workspace:*" "@calcom/trpc": "workspace:*" @@ -2649,6 +2654,16 @@ __metadata: languageName: unknown linkType: soft +"@calcom/i18n@workspace:*, @calcom/i18n@workspace:packages/i18n": + version: 0.0.0-use.local + resolution: "@calcom/i18n@workspace:packages/i18n" + dependencies: + "@calcom/tsconfig": "workspace:*" + i18next: "npm:23.2.3" + typescript: "npm:5.9.3" + languageName: unknown + linkType: soft + "@calcom/ics-feed@workspace:packages/app-store/ics-feedcalendar": version: 0.0.0-use.local resolution: "@calcom/ics-feed@workspace:packages/app-store/ics-feedcalendar" @@ -2727,6 +2742,7 @@ __metadata: "@biomejs/biome": "npm:2.3.10" "@calcom/config": "workspace:*" "@calcom/dayjs": "workspace:*" + "@calcom/i18n": "workspace:*" "@calcom/tsconfig": "workspace:*" "@calcom/types": "workspace:*" "@faker-js/faker": "npm:7.6.0" @@ -2883,6 +2899,7 @@ __metadata: resolution: "@calcom/platform-libraries@workspace:packages/platform/libraries" dependencies: "@calcom/features": "workspace:*" + "@calcom/i18n": "workspace:*" "@calcom/lib": "workspace:*" "@types/node": "npm:20.17.23" "@vitejs/plugin-react": "npm:5.1.2" @@ -3130,6 +3147,7 @@ __metadata: resolution: "@calcom/testing@workspace:packages/testing" dependencies: "@biomejs/biome": "npm:2.3.10" + "@calcom/i18n": "workspace:*" "@calcom/lib": "workspace:*" "@calcom/prisma": "workspace:*" "@calcom/tsconfig": "workspace:*" @@ -3143,6 +3161,7 @@ __metadata: resolution: "@calcom/trpc@workspace:packages/trpc" dependencies: "@biomejs/biome": "npm:2.3.10" + "@calcom/i18n": "workspace:*" "@formbricks/api": "npm:3.0.0" "@tanstack/react-query": "npm:5.17.19" "@trpc/client": "npm:11.0.0-next-beta.222" @@ -3264,6 +3283,7 @@ __metadata: version: 0.0.0-use.local resolution: "@calcom/vital@workspace:packages/app-store/vital" dependencies: + "@calcom/i18n": "workspace:*" "@calcom/prisma": "workspace:*" "@calcom/types": "workspace:*" "@tryvital/vital-node": "npm:1.4.6" @@ -17127,6 +17147,7 @@ __metadata: version: 0.0.0-use.local resolution: "WipeMyCal@workspace:packages/app-store/wipemycalother" dependencies: + "@calcom/i18n": "workspace:*" "@calcom/prisma": "workspace:*" "@calcom/types": "workspace:*" queue: "npm:6.0.2"