Skip to content

Comments

revert: "refactor: replace i18n HTTP requests with build-time bundling (#22422)"#22496

Merged
emrysal merged 1 commit intomainfrom
revert-i18n-pr
Jul 14, 2025
Merged

revert: "refactor: replace i18n HTTP requests with build-time bundling (#22422)"#22496
emrysal merged 1 commit intomainfrom
revert-i18n-pr

Conversation

@hbjORbj
Copy link
Contributor

@hbjORbj hbjORbj commented Jul 14, 2025

This reverts commit 163c7ff.

Summary by CodeRabbit

  • Refactor
    • Updated all localization logic and configuration to load translation files from the web app's public static directory instead of server-side directories.
    • Removed unused scripts and code related to previous translation bundling and copying mechanisms.
    • Adjusted build and test configurations to align with new locale file locations.
  • Style
    • Minor formatting changes in locale JSON files (e.g., removal of trailing newlines, spacing adjustments).
  • Chores
    • Updated workflow and configuration files to reflect new paths for localization resources.

@hbjORbj hbjORbj requested a review from a team July 14, 2025 22:06
@hbjORbj hbjORbj requested a review from a team as a code owner July 14, 2025 22:06
@vercel
Copy link

vercel bot commented Jul 14, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

2 Skipped Deployments
Name Status Preview Comments Updated (UTC)
cal ⬜️ Ignored (Inspect) Jul 14, 2025 10:07pm
cal-eu ⬜️ Ignored (Inspect) Jul 14, 2025 10:07pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 14, 2025

Walkthrough

This change migrates all locale JSON files and related references from a server-side package directory to the web application's public static directory. It updates import paths, configuration files, and build scripts accordingly. Additionally, it removes now-obsolete scripts and files, adjusts caching and fetching logic, and applies minor formatting updates to locale files.

Changes

Files / Groups Change Summary
apps/web/public/static/locales/*/common.json Removed trailing newlines from all locale JSON files; minor formatting fix in English locale.
apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/[type]/embed/page.tsx
.../page.tsx
Removed explicit type annotation from translations variable; deferred initialization.
apps/web/next.config.js
apps/web/playwright/lib/localize.ts
apps/web/scripts/check-missing-translations.ts
Updated locale JSON file paths from server-side to public static directory.
apps/web/package.json Removed copy-locales-static.js from copy-static script.
apps/web/scripts/copy-locales-static.js Deleted the locale copying script.
.github/workflows/pr.yml Updated locale file path pattern in paths filter for CI.
apps/api/v2/next-i18next.config.js Changed localePath to point to public static directory.
i18n-unused.config.js
i18n.json
Updated locale paths to public static directory.
packages/lib/server/i18n.ts Switched from bundler-based to fetch-based translation loading; updated caching and error handling.
packages/lib/server/translationBundler.ts Deleted translation bundler module.
packages/lib/buildCalEventFromBooking.ts Updated import path for getTranslation.
packages/features/ee/workflows/lib/test/compareReminderBodyToTemplate.test.ts Changed import path for English locale JSON in tests.
packages/platform/atoms/cal-provider/BaseCalProvider.tsx
languages.ts
Updated translation JSON import paths to public static directory.
packages/platform/atoms/vite.config.ts Changed Vite alias mapping for English locale JSON file.

Poem

🐇✨
Hop, hop, the locales leap,
From server shelves to public keep!
Paths are trimmed, the scripts are neat,
Old bundlers rest, new fetchers greet.
Translations now are quick to find—
In static fields, all tongues aligned.
A carrot toast to code refined!

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

apps/api/v2/next-i18next.config.js

Oops! Something went wrong! :(

ESLint: 8.57.1

ESLint couldn't find the plugin "@typescript-eslint/eslint-plugin".

(The package "@typescript-eslint/eslint-plugin" was not found when loaded as a Node module from the directory "/apps/api/v2".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install @typescript-eslint/eslint-plugin@latest --save-dev

The plugin "@typescript-eslint/eslint-plugin" was referenced from the config file in "apps/api/v2/.eslintrc.js".

If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.

apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/[type]/embed/page.tsx

Oops! Something went wrong! :(

ESLint: 8.57.1

ESLint couldn't find the plugin "eslint-plugin-playwright".

(The package "eslint-plugin-playwright" was not found when loaded as a Node module from the directory "".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-playwright@latest --save-dev

The plugin "eslint-plugin-playwright" was referenced from the config file in ".eslintrc.js".

If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.

apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/[type]/page.tsx

Oops! Something went wrong! :(

ESLint: 8.57.1

ESLint couldn't find the plugin "eslint-plugin-playwright".

(The package "eslint-plugin-playwright" was not found when loaded as a Node module from the directory "".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-playwright@latest --save-dev

The plugin "eslint-plugin-playwright" was referenced from the config file in ".eslintrc.js".

If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.

  • 10 others
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@graphite-app graphite-app bot requested a review from a team July 14, 2025 22:06
@keithwillcode keithwillcode added core area: core, team members only foundation labels Jul 14, 2025
@dosubot dosubot bot added the i18n area: i18n, translations label Jul 14, 2025
@delve-auditor
Copy link

delve-auditor bot commented Jul 14, 2025

No security or compliance issues detected. Reviewed everything up to 1ac6b75.

Security Overview
  • 🔎 Scanned files: 62 changed file(s)
Detected Code Changes
Change Type Relevant files
Refactor ► next-i18next.config.js
    Update locales path
► i18n.ts
    Revert translation HTTP requests implementation
► translations folder structure
    Move from packages/lib/server/locales to apps/web/public/static/locales

Reply to this PR with @delve-auditor followed by a description of what change you want and we'll auto-submit a change to this PR to implement it.

@graphite-app
Copy link

graphite-app bot commented Jul 14, 2025

Graphite Automations

"Add consumer team as reviewer" took an action on this PR • (07/14/25)

1 reviewer was added to this PR based on Keith Williams's automation.

"Add ready-for-e2e label" took an action on this PR • (07/14/25)

1 label was added to this PR based on Keith Williams's automation.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🔭 Outside diff range comments (3)
apps/web/public/static/locales/vi/common.json (1)

618-619: Remove stray control character from the am_pm translation.

The value contains the Unicode “INFORMATION SEPARATOR ONE” control character (\u001d) right before am/pm.
That character is non-printable, can break ICU/Intl formatting and causes hard-to-debug rendering issues in some browsers.

-  "am_pm": "\u001dam/pm",
+  "am_pm": "am/pm",
apps/web/public/static/locales/ro/common.json (2)

3-3: Potentially invalid interpolation placeholder

$t(zi, {\"count\": {{days}} }) nests {{days}} inside a JSON object that is itself embedded in the string.
i18next will parse ${...} and {{…}} literally; the inner {{days}} is therefore evaluated before the outer $t call and produces an empty token, which breaks the plural-helper.
Safe variant:

-"trial_days_left": "Aveți $t(zi, {\"count\": {{days}} }) rămase din perioada de probă PRO",
+"trial_days_left": "Aveți $t(day, {\"count\": {{days}} }) rămase din perioada de probă PRO",

• Keep the English key (day) – only the value gets translated.
• Remove the extra curlies around days if you want $t to receive a raw number.
Otherwise the runtime will throw InterpolationError: Missing interpolation value "days".


780-786: Duplicate top-level keys break the JSON object

Keys description/title/status/… appear multiple times in the root.
In plain JSON the last occurrence silently overwrites the previous ones, so earlier translations are discarded and the file becomes misleading.

Example collision:

783   "title": "Titlu",
784   "description": "Descriere",
...
1016  "title": "Titlu",
1017  "description": "Descriere",

Move those into scoped namespaces (e.g. "generic.description", "page.profile.title") before shipping; otherwise only the last block will be loaded by the i18n runtime.

🧹 Nitpick comments (15)
apps/web/public/static/locales/nl/common.json (1)

3360-3363: Only cosmetic change – consider skipping in future commits

The only difference in this file appears to be the removal of the trailing newline (line 3363).
While harmless, these “whitespace-only” edits make PRs harder to review and generate noisy diffs.

If no functional change is intended, consider omitting such edits or running a formatter (e.g. Prettier) in a dedicated “format” commit.

apps/web/public/static/locales/no/common.json (1)

3361-3363: No functional impact detected, but keep trailing newline for POSIX-compliant tooling
The only change here is removal of the final newline (EOF). While JSON parsers are unaffected, some Unix-style tools (cat, wc, GNU diff, etc.) and CI linters expect text files to end with \n. Consider reinstating it to avoid spurious diffs in future commits.

@@
-3363 }
\ No newline at end of file
+3363 }
+
apps/web/public/static/locales/ko/common.json (1)

3360-3363: Consider preserving the trailing newline for POSIX compliance

The only effective change is the removal of the final newline after the closing brace.
While this has no functional impact on JSON parsing, a newline-at-EOF is standard in many tooling chains and avoids noisy diffs in subsequent edits.

 }⏎
+

Keeping it helps avoid blame-only churn.
Feel free to ignore if your formatter strips it automatically.

apps/web/public/static/locales/id/common.json (1)

169-169: Add trailing newline to comply with common tooling expectations

Several linters, POSIX text utilities, and some editors expect a final newline at end-of-file. Keeping it prevents needless diffs and avoids warnings.

-}
+}
+
apps/web/public/static/locales/ta/common.json (1)

214-214: Restore trailing newline for cleaner diffs & POSIX friendliness

The only change in this file is the removal of the final newline. While harmless at runtime, keeping a newline at EOF avoids “no-newline-at-end-of-file” warnings and prevents superfluous diffs in future edits.

   "email_survey_triggered_by_workflow": "இந்த ஆய்வு Cal-ல் உள்ள பணிப்பாய்வு மூலம் தூண்டப்பட்டது."
-}
+}
+
apps/web/public/static/locales/zh-CN/common.json (1)

3360-3363: Trailing-newline removal is harmless but adds noise to git history

Nothing functionally changes; if the newline was removed unintentionally you may want to restore it, otherwise consider batching such cosmetic tweaks to avoid churn in large locale files.

apps/web/public/static/locales/zh-TW/common.json (1)

3360-3363: File is valid JSON – no issues introduced, but consider long-term maintainability

The closing brace is intact and the last entry no longer ends with a trailing comma, so the JSON remains valid.
Given this file is now ~3 300 lines long, localisation diffs become noisy and hard to review.
Consider splitting the locale into multiple domain-specific files (e.g. booking.json, team.json, admin.json) and loading them dynamically; this speeds up reviews and avoids merge-conflicts on large monolith files.

apps/web/public/static/locales/sv/common.json (1)

3363-3363: Restore trailing newline at EOF

The file now ends directly with } without a terminating newline. While harmless at runtime, many POSIX‐compliant tools (diff, git, some editors) expect a final newline and will flag the file as modified on every save. Adding it back keeps future diffs cleaner.

-}
+}
+
apps/web/public/static/locales/hr/common.json (1)

456-456: Restore POSIX-style trailing newline

The closing brace now sits at EOF with no trailing newline. While JSON tooling is usually indifferent, omitting the final LF breaks POSIX convention and can cause annoyances in diffs and some editors. Recommend reinstating a single trailing newline for consistency across locale files.

apps/web/public/static/locales/ro/common.json (1)

1-3363: File is edging toward 4000 lines – consider modularising

A monolithic locale file:

  • is hard to diff & review (as witnessed here),
  • increases bundle size (loaded for every request),
  • amplifies merge-conflict probability.

Recommend splitting by logical domain, e.g.:

locales/
  ro/
    common.json           # handful of truly shared strings
    onboarding.json
    bookings.json
    emailTemplates.json

next-i18next supports per-namespace loading and will fetch on demand.

apps/web/public/static/locales/pt-BR/common.json (1)

3360-3363: Consider restoring the final newline for cross-tool compatibility
The only change in this file is the removal of the trailing newline (the closing brace is now the very last byte).
JSON itself doesn’t care, but a few linters / POSIX-style toolchains (e.g. git diff, some editors, cat pipelines) assume every text file ends with “\n”. Keeping the newline avoids spurious diffs like this one.

If there is no strong reason to drop it, re-add the newline to minimise noise in future diffs.

packages/lib/buildCalEventFromBooking.ts (1)

71-83: Redundant translation fetches per attendee – cache or batch

Promise.all runs getTranslation for every attendee even when several share the same locale.
For a 10-attendee meeting with two locales you’ll issue 10 network/IO calls instead of 2.

-const attendeesList = await Promise.all(
-  booking.attendees.map(async (attendee) => {
-    return {
-      ...,
-      language: {
-        translate: await getTranslation(attendee.locale ?? "en", "common"),
-        locale: attendee.locale ?? "en",
-      },
-    };
-  })
-);
+const translationCache = new Map<string, Awaited<ReturnType<typeof getTranslation>>>();
+const attendeesList = await Promise.all(
+  booking.attendees.map(async (att) => {
+    const locale = att.locale ?? "en";
+    if (!translationCache.has(locale)) {
+      translationCache.set(locale, await getTranslation(locale, "common"));
+    }
+    return {
+      ...att,
+      language: { translate: translationCache.get(locale)!, locale },
+    };
+  }),
+);

Cuts duplicate I/O and speeds up large bookings.

packages/platform/atoms/cal-provider/languages.ts (1)

28-28: Typo: CAL_PROVIDER_LANGUAUES

Minor but leaks into the public type:

-export const CAL_PROVIDER_LANGUAUES = [FR, EN, PT_BR, DE, ES, NL] as const;
+export const CAL_PROVIDER_LANGUAGES = [FR, EN, PT_BR, DE, ES, NL] as const;

Rename the accompanying CalProviderLanguagesType generic accordingly.

apps/web/public/static/locales/en/common.json (1)

285-288: Keep JSON formatting consistent

The only modification here is removal of the single space after the colon. While functionally harmless, it introduces an inconsistent formatting style compared to the rest of the file and creates noisy diffs. Consider keeping the space (or running the existing project formatter/prettier) so the file remains uniformly formatted:

-  "confirmation":"Confirmation",
+  "confirmation": "Confirmation",
packages/lib/server/i18n.ts (1)

44-70: Verify network-based translation loading strategy.

The implementation correctly handles network failures with fallback to English translations. However, this introduces performance and reliability considerations:

  1. Performance impact: Network requests will be slower than bundled translations
  2. Cache strategy: Using browser cache in production, but cache invalidation may be problematic
  3. Availability dependency: System functionality now depends on web server availability

Consider implementing additional resilience measures:

 export async function loadTranslations(_locale: string, ns: string) {
   const locale = _locale === "zh" ? "zh-CN" : _locale;
   const cacheKey = `${locale}-${ns}`;

   if (translationCache.has(cacheKey)) {
     return translationCache.get(cacheKey);
   }

   try {
     const url = `${WEBAPP_URL}/static/locales/${locale}/${ns}.json`;
+    // Add timeout to prevent hanging requests
     const response = await fetch(url, {
       cache: process.env.NODE_ENV === "production" ? "force-cache" : "no-store",
+      signal: AbortSignal.timeout(5000), // 5 second timeout
     });
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fe4946a and 1ac6b75.

📒 Files selected for processing (57)
  • .github/workflows/pr.yml (1 hunks)
  • apps/api/v2/next-i18next.config.js (1 hunks)
  • apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/[type]/embed/page.tsx (1 hunks)
  • apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/[type]/page.tsx (1 hunks)
  • apps/web/next.config.js (1 hunks)
  • apps/web/package.json (1 hunks)
  • apps/web/playwright/lib/localize.ts (1 hunks)
  • apps/web/public/static/locales/ar/common.json (1 hunks)
  • apps/web/public/static/locales/az/common.json (1 hunks)
  • apps/web/public/static/locales/bg/common.json (1 hunks)
  • apps/web/public/static/locales/bn/common.json (1 hunks)
  • apps/web/public/static/locales/ca/common.json (1 hunks)
  • apps/web/public/static/locales/cs/common.json (1 hunks)
  • apps/web/public/static/locales/da/common.json (1 hunks)
  • apps/web/public/static/locales/el/common.json (1 hunks)
  • apps/web/public/static/locales/en/common.json (1 hunks)
  • apps/web/public/static/locales/es-419/common.json (1 hunks)
  • apps/web/public/static/locales/es/common.json (1 hunks)
  • apps/web/public/static/locales/et/common.json (1 hunks)
  • apps/web/public/static/locales/eu/common.json (1 hunks)
  • apps/web/public/static/locales/fi/common.json (1 hunks)
  • apps/web/public/static/locales/he/common.json (1 hunks)
  • apps/web/public/static/locales/hr/common.json (1 hunks)
  • apps/web/public/static/locales/hu/common.json (1 hunks)
  • apps/web/public/static/locales/id/common.json (1 hunks)
  • apps/web/public/static/locales/it/common.json (1 hunks)
  • apps/web/public/static/locales/ja/common.json (1 hunks)
  • apps/web/public/static/locales/km/common.json (1 hunks)
  • apps/web/public/static/locales/ko/common.json (1 hunks)
  • apps/web/public/static/locales/lv/common.json (1 hunks)
  • apps/web/public/static/locales/nl/common.json (1 hunks)
  • apps/web/public/static/locales/no/common.json (1 hunks)
  • apps/web/public/static/locales/pt-BR/common.json (1 hunks)
  • apps/web/public/static/locales/pt/common.json (1 hunks)
  • apps/web/public/static/locales/ro/common.json (1 hunks)
  • apps/web/public/static/locales/ru/common.json (1 hunks)
  • apps/web/public/static/locales/sk-SK/common.json (1 hunks)
  • apps/web/public/static/locales/sk/common.json (1 hunks)
  • apps/web/public/static/locales/sr/common.json (1 hunks)
  • apps/web/public/static/locales/sv/common.json (1 hunks)
  • apps/web/public/static/locales/ta/common.json (1 hunks)
  • apps/web/public/static/locales/tr/common.json (1 hunks)
  • apps/web/public/static/locales/uk/common.json (1 hunks)
  • apps/web/public/static/locales/vi/common.json (1 hunks)
  • apps/web/public/static/locales/zh-CN/common.json (1 hunks)
  • apps/web/public/static/locales/zh-TW/common.json (1 hunks)
  • apps/web/scripts/check-missing-translations.ts (1 hunks)
  • apps/web/scripts/copy-locales-static.js (0 hunks)
  • i18n-unused.config.js (1 hunks)
  • i18n.json (1 hunks)
  • packages/features/ee/workflows/lib/test/compareReminderBodyToTemplate.test.ts (1 hunks)
  • packages/lib/buildCalEventFromBooking.ts (1 hunks)
  • packages/lib/server/i18n.ts (4 hunks)
  • packages/lib/server/translationBundler.ts (0 hunks)
  • packages/platform/atoms/cal-provider/BaseCalProvider.tsx (1 hunks)
  • packages/platform/atoms/cal-provider/languages.ts (1 hunks)
  • packages/platform/atoms/vite.config.ts (1 hunks)
💤 Files with no reviewable changes (2)
  • apps/web/scripts/copy-locales-static.js
  • packages/lib/server/translationBundler.ts
🧰 Additional context used
🧠 Learnings (5)
apps/web/public/static/locales/ja/common.json (1)

undefined

<retrieved_learning>
Learnt from: bandhan-majumder
PR: #22359
File: packages/lib/server/locales/en/common.json:1336-1339
Timestamp: 2025-07-14T16:31:45.201Z
Learning: When making localization changes for new features, it's often safer to add new strings rather than modify existing ones to avoid breaking existing functionality that depends on the original strings. This approach allows for feature-specific customization while maintaining backward compatibility.
</retrieved_learning>

apps/web/public/static/locales/en/common.json (1)

undefined

<retrieved_learning>
Learnt from: bandhan-majumder
PR: #22359
File: packages/lib/server/locales/en/common.json:1336-1339
Timestamp: 2025-07-14T16:31:45.201Z
Learning: When making localization changes for new features, it's often safer to add new strings rather than modify existing ones to avoid breaking existing functionality that depends on the original strings. This approach allows for feature-specific customization while maintaining backward compatibility.
</retrieved_learning>

i18n.json (1)
Learnt from: bandhan-majumder
PR: calcom/cal.com#22359
File: packages/lib/server/locales/en/common.json:1336-1339
Timestamp: 2025-07-14T16:31:45.201Z
Learning: When making localization changes for new features, it's often safer to add new strings rather than modify existing ones to avoid breaking existing functionality that depends on the original strings. This approach allows for feature-specific customization while maintaining backward compatibility.
apps/web/playwright/lib/localize.ts (1)
Learnt from: bandhan-majumder
PR: calcom/cal.com#22359
File: packages/lib/server/locales/en/common.json:1336-1339
Timestamp: 2025-07-14T16:31:45.201Z
Learning: When making localization changes for new features, it's often safer to add new strings rather than modify existing ones to avoid breaking existing functionality that depends on the original strings. This approach allows for feature-specific customization while maintaining backward compatibility.
packages/lib/server/i18n.ts (1)
Learnt from: bandhan-majumder
PR: calcom/cal.com#22359
File: packages/lib/server/locales/en/common.json:1336-1339
Timestamp: 2025-07-14T16:31:45.201Z
Learning: When making localization changes for new features, it's often safer to add new strings rather than modify existing ones to avoid breaking existing functionality that depends on the original strings. This approach allows for feature-specific customization while maintaining backward compatibility.
🧬 Code Graph Analysis (2)
apps/api/v2/next-i18next.config.js (1)
i18n-unused.config.js (1)
  • path (1-1)
packages/lib/server/i18n.ts (1)
packages/lib/constants.ts (1)
  • WEBAPP_URL (12-18)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Security Check
🔇 Additional comments (40)
apps/web/public/static/locales/ru/common.json (1)

3361-3363: No-op change – nothing to review

The sole edit is the deletion of a trailing newline. JSON validity and runtime behaviour remain untouched.

apps/web/public/static/locales/pt/common.json (1)

3363-3363: No functional impact – closing brace only

Only the final newline/brace was touched. JSON remains well-formed; no further action needed.

apps/web/public/static/locales/da/common.json (1)

3363-3363: Trailing-newline trim is harmless
The only change is deletion of the final blank line. JSON remains valid; no action required.

apps/web/public/static/locales/eu/common.json (1)

3360-3363: Trailing newline deleted – JSON still valid but watch for merge-conflicts

The only effective diff here is the removal of the final newline after the sentinel key
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS".
That doesn’t break JSON validity, yet many editors/tools add the newline back automatically, which can create noisy diffs later. If the deletion wasn’t intentional, consider reinstating it to keep the file checksum stable.

No other content changes detected – keys, ordering and structure remain intact.

apps/web/public/static/locales/tr/common.json (1)

3363-3363: No-op change – looks good

Only the trailing newline was removed. JSON remains valid and tooling will not be impacted.

apps/web/public/static/locales/es/common.json (1)

3361-3363: No issues – removal of trailing newline is harmless

The only change is the deletion of a superfluous trailing newline.
JSON structure and content remain intact, so nothing to fix here.

apps/web/public/static/locales/uk/common.json (1)

3363-3363: No-op change – file remains valid JSON

Only the trailing newline was removed. This has no functional impact and the file still parses correctly. LGTM.

apps/web/public/static/locales/el/common.json (1)

3361-3363: No functional impact from newline removal

The only change here is the removal of a trailing newline at EOF, which has no effect on runtime behaviour or localisation loading.
Safe to merge.

apps/web/public/static/locales/he/common.json (1)

3360-3363: No functional impact – newline trim looks fine

Only a trailing‐newline change (line 3363). JSON content remains valid; no further action required.

apps/web/public/static/locales/bg/common.json (1)

3363-3363: No issues – content unchanged, newline removal is innocuous

Only the trailing newline was removed; the JSON remains valid and untouched.
No action required.

apps/web/public/static/locales/ca/common.json (1)

3363-3363: No functional impact – change limited to trailing newline 🔍

The only difference is the modified closing brace, effectively just whitespace. Nothing to action here.

apps/web/public/static/locales/km/common.json (1)

3363-3363: No content change—looks safe to merge

Only the trailing newline was removed. No functional impact detected.

apps/web/public/static/locales/sr/common.json (1)

3363-3363: Change is safe – nothing functional impacted
Only a trailing-whitespace / newline tweak around the sentinel string was made. This doesn’t alter any keys/values, so runtime behaviour is untouched.

apps/web/public/static/locales/es-419/common.json (1)

3360-3363: No functional impact – okay to merge

The only modification is the removal of a trailing newline after the closing brace of the JSON object. The JSON content remains valid and unchanged, and most parsers ignore trailing whitespace. Nothing else to flag.

apps/web/public/static/locales/it/common.json (1)

3363-3363: No-op change looks good
Only a trailing-newline tweak; JSON remains syntactically correct.

apps/web/public/static/locales/sk/common.json (1)

70-70: No functional impact – safe to ignore
The change only removes a trailing newline; nothing else is modified.

apps/web/public/static/locales/cs/common.json (1)

3360-3363: No-op change – looks good

Only the trailing-newline flag on the sentinel key was touched; functional behaviour is unaffected.

apps/web/public/static/locales/ar/common.json (1)

3360-3363: No-op change – only trailing-newline removed
The only diff is the removal of the final newline after the closing brace. This has no effect on JSON parsing and can be left as-is.

apps/web/public/static/locales/fi/common.json (1)

3363-3363: No action needed – newline removal is harmless

The only modification is the removal of the trailing newline after the closing brace. JSON parsers do not require a newline at EOF, so this is functionally neutral.

apps/web/public/static/locales/lv/common.json (1)

165-165: LGTM – content unchanged, newline removal only

JSON remains valid; no functional impact. 👍

apps/web/public/static/locales/sk-SK/common.json (1)

3363-3363: No functional impact – looks good

Only the trailing newline was removed. JSON structure remains valid and unchanged. Nothing else to address.

apps/web/public/static/locales/ja/common.json (1)

3360-3363: No functional impact from trailing‐newline removal
Only the final newline was trimmed; the JSON payload remains valid and unchanged. Nothing else to flag.

apps/web/public/static/locales/et/common.json (1)

3360-3363: Whitespace-only update – nothing to do
The change simply removes/adjusts trailing whitespace; the JSON data itself is untouched.

apps/web/public/static/locales/hu/common.json (1)

3363-3363: Only trailing-newline change – safe to merge

The diff solely removes the file’s final newline. JSON validity and runtime behaviour remain unchanged, so this is fine.

apps/web/public/static/locales/az/common.json (1)

3363-3363: No functional impact – newline removal is fine

Only the final newline was removed; JSON validity remains intact.
No further action required.

apps/web/scripts/check-missing-translations.ts (1)

6-6: Path update looks correct for the locale migration.

The LOCALES_PATH correctly points to the new public static location where locale files will be accessible via HTTP requests instead of being bundled at build time.

apps/api/v2/next-i18next.config.js (1)

8-8: Configuration correctly updated for locale migration.

The localePath now points to the web public static directory, enabling HTTP-based translation fetching for the API v2 application.

packages/platform/atoms/cal-provider/BaseCalProvider.tsx (1)

8-13: Import paths correctly updated for all supported locales.

All locale JSON import paths have been consistently updated to point to the web public static directory. This enables HTTP-based fetching of translations instead of build-time bundling.

i18n.json (1)

46-46: Buckets configuration correctly updated for new locale path.

The include path now points to the web public static locales directory, ensuring i18n tooling scans the correct location for translation files.

packages/features/ee/workflows/lib/test/compareReminderBodyToTemplate.test.ts (1)

7-7: Test import path correctly updated for locale migration.

The English locale import now points to the web public static directory, consistent with the overall migration from build-time bundling to HTTP-based translation fetching.

apps/web/next.config.js (1)

2-2: LGTM! Path update aligns with locale migration.

The import path correctly updates to the new location in the web app's public static directory, which is consistent with the broader migration from server-side bundling to static asset serving.

apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/[type]/embed/page.tsx (1)

35-35: LGTM! Type annotation removal is safe.

The removal of explicit typing is appropriate here since translations is only used within the conditional block where it's assigned, and TypeScript can infer the correct type from loadTranslations().

apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/[type]/page.tsx (1)

71-71: LGTM! Consistent type annotation removal.

Similar to the embed page, this change is safe as translations follows the same conditional assignment and usage pattern.

apps/web/playwright/lib/localize.ts (1)

5-5: LGTM! Path update is consistent with locale migration.

The relative path correctly navigates from playwright/lib/ to the new locale directory in public/static/locales/, maintaining the same functionality with the updated file structure.

packages/platform/atoms/vite.config.ts (1)

65-68: LGTM: Alias configuration updated correctly for locale migration.

The alias path update correctly reflects the migration of locale files from the server package directory to the web app's public static directory.

apps/web/package.json (1)

18-18: LGTM: Script update aligns with locale migration strategy.

Removing the copy-locales-static.js execution is appropriate since locale files are now maintained directly in the web app's public static directory.

.github/workflows/pr.yml (1)

36-36: LGTM: Workflow exclusion pattern updated for new locale path.

The path filter correctly excludes locale files from the new location, maintaining the intended CI optimization.

packages/lib/server/i18n.ts (3)

3-3: LGTM: Appropriate import for webapp URL constant.

The import correctly references the WEBAPP_URL constant needed for constructing translation fetch URLs.


78-100: LGTM: Cache key simplification is appropriate.

The simplified cache key (${locale}-${ns}) is cleaner than version-based keys and aligns well with the fetch-based approach.


13-36: Ensure reliable fallback implementation for translations

We’ve confirmed that all common.json files under apps/web/public/static/locales/*/common.json are present and non-empty, so the fetch URL is valid. However, the runtime fetch still depends on your web server’s availability and currently returns {} on any failure, which may lead to missing UI text. To harden this:

  • Verify that WEBAPP_URL in production correctly points to your server’s static assets endpoint and that it consistently serves /static/locales/en/common.json (e.g., via a staging health check).
  • Add monitoring or retries around the fetch to surface failures early.
  • For critical translations, consider bundling the fallback JSON directly into the server (e.g., import common from '.../locales/en/common.json') or implementing a filesystem-based fallback before returning an empty object.

Comment on lines 3360 to +3363
"license_key_saved": "লাইসেন্স কী সফলভাবে সংরক্ষিত হয়েছে",
"timezone_mismatch_tooltip": "আপনি আপনার প্রোফাইল টাইমজোন ({{userTimezone}}) অনুসারে রিপোর্ট দেখছেন, যখন আপনার ব্রাউজার টাইমজোন ({{browserTimezone}}) এ সেট করা আছে",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑ুষান্ত"
}
} No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Sentinel key must remain untranslated – revert accidental Bengali characters

The "ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS" entry is a tooling sentinel and must stay identical across all locale files to avoid automated-merge failures.
Current value contains unintended text ("↑↑↑↑ুষান্ত"). Keep only the four arrows:

-  "ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑ুষান্ত"
+  "ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"license_key_saved": "লাইসেন্স কী সফলভাবে সংরক্ষিত হয়েছে",
"timezone_mismatch_tooltip": "আপনি আপনার প্রোফাইল টাইমজোন ({{userTimezone}}) অনুসারে রিপোর্ট দেখছেন, যখন আপনার ব্রাউজার টাইমজোন ({{browserTimezone}}) এ সেট করা আছে",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑ুষান্ত"
}
}
"license_key_saved": "লাইসেন্স কী সফলভাবে সংরক্ষিত হয়েছে",
"timezone_mismatch_tooltip": "আপনি আপনার প্রোফাইল টাইমজোন ({{userTimezone}}) অনুসারে রিপোর্ট দেখছেন, যখন আপনার ব্রাউজার টাইমজোন ({{browserTimezone}}) এ সেট করা আছে",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑"
}
🤖 Prompt for AI Agents
In apps/web/public/static/locales/bn/common.json at lines 3360 to 3363, the
sentinel key "ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS" has
been accidentally modified with extra Bengali characters. Revert its value to
contain only the four arrows "↑↑↑↑" exactly as in other locale files to maintain
consistency and prevent automated merge conflicts.

import { getTranslation } from "@calcom/lib/server/i18n";

import { parseRecurringEvent } from "./isRecurringEvent";
import { getTranslation } from "./server/i18n";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Relative import introduces fragile cross-package coupling

Switching from the path-alias (@calcom/lib/server/i18n) to a relative hop ("./server/i18n") ties this file’s correctness to its on-disk location.
If any part of packages/lib is moved or published independently, the import will silently break, whereas the alias survives refactors and keeps the public API stable.

-import { getTranslation } from "./server/i18n";
+// keep the stable, package-scoped alias
+import { getTranslation } from "@calcom/lib/server/i18n";

Verify that tsconfig.paths/moduleAliases still map @calcom/lib/server/*; if the revert deleted that mapping, consider restoring it rather than sprinkling relative paths.
This prevents accidental tight-coupling and makes the lib consumable outside the monorepo.


I’ll verify whether the alias mapping for @calcom/lib/server/* still exists in your build config.


🏁 Script executed:

#!/bin/bash
set -e

echo "🔍 Found tsconfig files:"
find . -maxdepth 2 -type f -name "tsconfig*.json"

echo
echo "🔍 Checking for '@calcom/lib/server' in tsconfig paths:"
grep -R '"@calcom/lib/server' -n tsconfig*.json || echo "→ No mapping found in tsconfig paths"

echo
echo "🔍 Checking for moduleAliases in package.json:"
grep -R "moduleAliases" -n package.json || echo "→ No moduleAliases found"

Length of output: 647


Add a stable path alias for @calcom/lib/server instead of a fragile relative import

I didn’t find any @calcom/lib/server/* mapping in your TypeScript or module-alias configs, so importing via the alias will currently break. To avoid brittle relative hops, please:

• In your tsconfig.json (or the package’s own tsconfig), under compilerOptions.paths, add:

{
  "compilerOptions": {
    "paths": {
      "@calcom/lib/server/*": ["packages/lib/server/*"]
    }
  }
}

• Then revert the import in packages/lib/buildCalEventFromBooking.ts:

- import { getTranslation } from "./server/i18n";
+ import { getTranslation } from "@calcom/lib/server/i18n";

This restores a stable, package-scoped alias that survives refactors and keeps your public API stable.

🤖 Prompt for AI Agents
In packages/lib/buildCalEventFromBooking.ts at line 6, replace the relative
import of getTranslation with the alias import from '@calcom/lib/server'. First,
add the path alias "@calcom/lib/server/*": ["packages/lib/server/*"] to the
compilerOptions.paths section in the package's tsconfig.json or the root
tsconfig.json. Then update the import statement to use this alias to ensure a
stable and maintainable import path.

Comment on lines +1 to +6
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 nlTranslations from "@calcom/web/public/static/locales/nl/common.json";
import type ptBrTranslations from "@calcom/web/public/static/locales/pt-BR/common.json";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Package → app import creates an undesirable reverse dependency

packages/platform/atoms now reaches into @calcom/web/public/static/....
That makes the library depend on an application layer, breaking the usual dependency graph and preventing independent publishing.

Consider introducing a thin @calcom/locales (or restoring the previous @calcom/lib/server/locales) package that owns the JSON files, then import:

import type enTranslations from "@calcom/locales/en/common.json";

Keeps atoms portable and avoids accidental circular builds.

🤖 Prompt for AI Agents
In packages/platform/atoms/cal-provider/languages.ts lines 1 to 6, the current
imports reach into @calcom/web/public/static/locales, creating a reverse
dependency from the library to the application layer. To fix this, move the JSON
locale files into a dedicated package such as @calcom/locales or restore the
previous @calcom/lib/server/locales package to own these files. Then update the
import statements to import from this new package (e.g., import type
enTranslations from "@calcom/locales/en/common.json") to maintain proper
dependency direction and keep the atoms package portable.

const config = {
// localesPath: localePath, // uncomment to run on all locales (to calculate kb savings)
localesPath: path.join("./packages/lib/server/locales", "/en"),
localesPath: path.join("./apps/website", "/public/static/locales", "/en"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix incorrect directory name in locale path.

The path uses apps/website but should be apps/web to match the actual directory structure and be consistent with other files in this PR.

-  localesPath: path.join("./apps/website", "/public/static/locales", "/en"),
+  localesPath: path.join("./apps/web", "/public/static/locales", "/en"),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
localesPath: path.join("./apps/website", "/public/static/locales", "/en"),
localesPath: path.join("./apps/web", "/public/static/locales", "/en"),
🤖 Prompt for AI Agents
In i18n-unused.config.js at line 26, the localesPath is incorrectly set to use
"apps/website" instead of "apps/web". Update the path to replace "apps/website"
with "apps/web" to match the actual directory structure and maintain consistency
with other files in the PR.

Copy link
Contributor

@emrysal emrysal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now OK 👍

@emrysal emrysal enabled auto-merge (squash) July 14, 2025 22:19
dakshgup added a commit to dakshgup/cal.com that referenced this pull request Jul 14, 2025
…s with build-time bundling (calcom#22422)"

Originally by: hbjORbj
This reverts commit 163c7ff.

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **Refactor**
  * Updated all localization logic and configuration to load translation files from the web app's public static directory instead of server-side directories.
  * Removed unused scripts and code related to previous translation bundling and copying mechanisms.
  * Adjusted build and test configurations to align with new locale file locations.
* **Style**
  * Minor formatting changes in locale JSON files (e.g., removal of trailing newlines, spacing adjustments).
* **Chores**
  * Updated workflow and configuration files to reflect new paths for localization resources.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
@github-actions
Copy link
Contributor

E2E results are ready!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core area: core, team members only foundation i18n area: i18n, translations ready-for-e2e

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants