Skip to content

Comments

feat(workflows): add localization support for date variables in reminders#24281

Closed
Bhavyabhardwaj wants to merge 4 commits intocalcom:mainfrom
Bhavyabhardwaj:fix/workflow-date-variable-localization
Closed

feat(workflows): add localization support for date variables in reminders#24281
Bhavyabhardwaj wants to merge 4 commits intocalcom:mainfrom
Bhavyabhardwaj:fix/workflow-date-variable-localization

Conversation

@Bhavyabhardwaj
Copy link
Contributor

Fixes #24280

What does this PR do?

Enhances localization for workflow reminders across all notification channels (Email, SMS, WhatsApp) to properly support date/time variables in the recipient's locale.

Description of Changes

  • WhatsApp reminders: Updated handler to use attendee's locale for proper date/time localization
  • Email reminders: Modified manager to utilize recipient's locale for email content
  • SMS reminders: Adjusted manager to apply recipient's locale for SMS messages
  • WhatsApp manager: Refined locale selection based on action type (organizer vs attendee)

This ensures that date variables like EVENT_DATE_ddd display correctly in the recipient's language (e.g., "Mar" for Tuesday in French instead of "Tue").

Files Changed

  • emailReminderManager.ts - Added locale support for email reminders
  • smsReminderManager.ts - Added locale support for SMS reminders
  • whatsappReminderManager.ts - Added locale support for WhatsApp reminders
  • scheduleWhatsappReminders.ts - Enhanced locale handling for scheduling

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)

Testing

  • Tested with different locales (en, fr, es, de)
  • Verified all reminder types use proper locale
  • Confirmed backward compatibility

Related Issue

Fixes #24280

Updated locale handling to use recipient's locale for WhatsApp reminders.
Updated SMS reminder localization to use recipient's locale for date/time formatting.
Updated locale determination to use recipient's language for date/time localization.
@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@graphite-app graphite-app bot added the community Created by Linear-GitHub Sync label Oct 5, 2025
@graphite-app graphite-app bot requested a review from a team October 5, 2025 17:49
@github-actions github-actions bot added i18n area: i18n, translations workflows area: workflows, automations ✨ feature New feature or request 🚨 needs approval This feature request has not been reviewed yet by the Product Team and needs approval beforehand labels Oct 5, 2025
@vercel
Copy link

vercel bot commented Oct 5, 2025

@Bhavyabhardwaj is attempting to deploy a commit to the cal Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions
Copy link
Contributor

github-actions bot commented Oct 5, 2025

Hey there and thank you for opening this pull request! 👋🏼

We require pull request titles to follow the Conventional Commits specification and it looks like your proposed title needs to be adjusted.

Details:

No release type found in pull request title "Fix/workflow date variable localization". Add a prefix to indicate what kind of release this pull request corresponds to. For reference, see https://www.conventionalcommits.org/

Available types:
 - feat: A new feature
 - fix: A bug fix
 - docs: Documentation only changes
 - style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
 - refactor: A code change that neither fixes a bug nor adds a feature
 - perf: A code change that improves performance
 - test: Adding missing tests or correcting existing tests
 - build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
 - ci: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
 - chore: Other changes that don't modify src or test files
 - revert: Reverts a previous commit

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 5, 2025

Walkthrough

Adds recipient-aware locale selection to reminder workflows. For WhatsApp (scheduler API and manager), SMS, and Email REMINDER flows, the locale now switches to the attendee’s locale for attendee-targeted actions (WHATSAPP_ATTENDEE, SMS_ATTENDEE, EMAIL_ATTENDEE), otherwise it uses the organizer/user locale. The computed locale is applied to template rendering, translation lookups, and date/time localization (e.g., via dayjs.locale). Emitted/constructed messages now pass the computed per-recipient locale instead of always using the organizer/user locale. No exported/public API signatures were changed.

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues Check ✅ Passed The implementation meets the requirement from issue #24280 by introducing recipient‐specific locale selection for date variables across email, SMS, and WhatsApp reminders, ensuring variables like EVENT_DATE_ddd are rendered in the recipient’s language. All coding objectives specified in the linked issue have been addressed.
Out of Scope Changes Check ✅ Passed All modifications are narrowly focused on locale selection for reminders in the specified files and directly support the linked issue’s objectives. No unrelated or extraneous code changes appear in this pull request.
Description Check ✅ Passed The description clearly outlines the purpose and changes introduced in the pull request, detailing the channels affected and the files modified. It directly relates to the code changes and anchors the work to the linked issue without being off-topic.
Title Check ✅ Passed The title succinctly identifies the core change—fixing date variable localization within workflows—and aligns with the PR’s focus on ensuring date/time variables render in the recipient’s locale. Although the slash is unconventional, the phrasing clearly conveys the main update without extraneous information.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@dosubot dosubot bot added the 🐛 bug Something isn't working label Oct 5, 2025
@Bhavyabhardwaj Bhavyabhardwaj changed the title Fix/workflow date variable localization feat(workflows): add localization support for date variables in reminders Oct 5, 2025
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: 3

🧹 Nitpick comments (4)
packages/features/ee/workflows/lib/reminders/smsReminderManager.ts (2)

189-192: Use the computed locale for opt-out message.

The opt-out message uses evt.organizer.language.locale instead of the computed locale variable, creating an inconsistency where the main message and opt-out message could be in different languages.

Apply this diff to use the recipient's locale:

         if (process.env.TWILIO_OPT_OUT_ENABLED === "true") {
           smsMessage = await WorkflowOptOutService.addOptOutMessage(
             smsMessage,
-            evt.organizer.language.locale
+            locale || "en"
           );
         }

165-174: Consider adding a fallback for undefined locale.

The locale selection logic correctly chooses the recipient's locale for SMS_ATTENDEE actions. However, if attendeeToBeUsedInSMS.language?.locale is undefined, the template will receive undefined as the locale parameter.

Apply this diff to add a fallback to "en":

-        const locale =
-          action === WorkflowActions.SMS_ATTENDEE
-            ? attendeeToBeUsedInSMS.language?.locale
-            : evt.organizer.language.locale;
+        const locale =
+          action === WorkflowActions.SMS_ATTENDEE
+            ? attendeeToBeUsedInSMS.language?.locale || "en"
+            : evt.organizer.language.locale || "en";

Note: This matches the defensive pattern used in scheduleWhatsappReminders.ts (lines 78-81) where explicit fallbacks to "en" are provided.

packages/features/ee/workflows/lib/reminders/emailReminderManager.ts (1)

193-202: Consider adding a fallback for undefined locale.

The locale selection logic correctly chooses the recipient's locale for EMAIL_ATTENDEE actions. While Line 202 provides a fallback (reminderLocale || "en") in getTranslation, Line 201 passes reminderLocale directly to the template's locale parameter without a fallback.

Apply this diff to ensure consistent fallback handling:

         const reminderLocale = isEmailAttendeeAction
           ? attendeeToBeUsedInMail.language?.locale
-          : evt.organizer.language.locale;
+          : evt.organizer.language.locale || "en";
         emailContent = emailReminderTemplate({
           isEditingMode: false,
-          locale: reminderLocale,
+          locale: reminderLocale || "en",
           t: await getTranslation(reminderLocale || "en", "common"),

This matches the defensive pattern used in scheduleWhatsappReminders.ts (lines 78-81).

packages/features/ee/workflows/lib/reminders/whatsappReminderManager.ts (1)

83-88: Consider adding a fallback for undefined locale.

The locale selection logic correctly chooses the recipient's locale for WHATSAPP_ATTENDEE actions. However, if evt.attendees[0].language?.locale is undefined, downstream usages (e.g., dayjs.locale(locale) on lines 96, 99) will receive undefined.

Apply this diff to add a fallback to "en":

-  const locale =
-    action === WorkflowActions.WHATSAPP_ATTENDEE
-      ? evt.attendees[0].language?.locale
-      : evt.organizer.language.locale;
+  const locale =
+    action === WorkflowActions.WHATSAPP_ATTENDEE
+      ? evt.attendees[0].language?.locale || "en"
+      : evt.organizer.language.locale || "en";

This matches the defensive pattern used in scheduleWhatsappReminders.ts (lines 78-81).

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a4be822 and 3e2b1a8.

📒 Files selected for processing (4)
  • packages/features/ee/workflows/api/scheduleWhatsappReminders.ts (2 hunks)
  • packages/features/ee/workflows/lib/reminders/emailReminderManager.ts (1 hunks)
  • packages/features/ee/workflows/lib/reminders/smsReminderManager.ts (1 hunks)
  • packages/features/ee/workflows/lib/reminders/whatsappReminderManager.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

**/*.ts: For Prisma queries, only select data you need; never use include, always use select
Ensure the credential.key field is never returned from tRPC endpoints or APIs

Files:

  • packages/features/ee/workflows/lib/reminders/smsReminderManager.ts
  • packages/features/ee/workflows/lib/reminders/whatsappReminderManager.ts
  • packages/features/ee/workflows/lib/reminders/emailReminderManager.ts
  • packages/features/ee/workflows/api/scheduleWhatsappReminders.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js .utc() in hot paths like loops

Files:

  • packages/features/ee/workflows/lib/reminders/smsReminderManager.ts
  • packages/features/ee/workflows/lib/reminders/whatsappReminderManager.ts
  • packages/features/ee/workflows/lib/reminders/emailReminderManager.ts
  • packages/features/ee/workflows/api/scheduleWhatsappReminders.ts
**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.

Files:

  • packages/features/ee/workflows/lib/reminders/smsReminderManager.ts
  • packages/features/ee/workflows/lib/reminders/whatsappReminderManager.ts
  • packages/features/ee/workflows/lib/reminders/emailReminderManager.ts
  • packages/features/ee/workflows/api/scheduleWhatsappReminders.ts
🧬 Code graph analysis (2)
packages/features/ee/workflows/lib/reminders/emailReminderManager.ts (1)
packages/platform/libraries/index.ts (2)
  • WorkflowActions (38-38)
  • getTranslation (82-82)
packages/features/ee/workflows/api/scheduleWhatsappReminders.ts (1)
packages/platform/libraries/index.ts (1)
  • WorkflowActions (38-38)
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Install dependencies / Yarn install & cache
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (2)
packages/features/ee/workflows/api/scheduleWhatsappReminders.ts (2)

76-81: LGTM! Good fallback handling.

The locale selection properly handles undefined values with || "en" fallback, ensuring safe defaults for both date/time formatting and template rendering. This pattern should be applied to the other reminder manager files for consistency.


76-99: LGTM! Excellent defensive coding.

The locale selection logic correctly chooses the recipient's locale for WHATSAPP_ATTENDEE actions and includes explicit fallbacks to "en" to prevent undefined values. This defensive approach ensures that downstream usages (e.g., dayjs.locale(locale) on lines 90, 93) always receive a valid locale string.

This pattern could serve as a reference for the other reminder managers in this PR.

Comment on lines +196 to +198
const reminderLocale = isEmailAttendeeAction
? attendeeToBeUsedInMail.language?.locale
: evt.organizer.language.locale;
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 | 🟡 Minor

Add fallback locale to handle undefined values.

The reminderLocale doesn't provide a fallback when attendeeToBeUsedInMail.language?.locale is undefined. While getTranslation at line 202 has a fallback (|| "en"), the locale passed to emailReminderTemplate at line 201 could still be undefined, potentially causing issues with date/time formatting.

Apply this diff to add a fallback:

     const reminderLocale = isEmailAttendeeAction
       ? attendeeToBeUsedInMail.language?.locale
       : evt.organizer.language.locale;
+    const safeLocale = reminderLocale || "en";
     emailContent = emailReminderTemplate({
       isEditingMode: false,
-      locale: reminderLocale,
-      t: await getTranslation(reminderLocale || "en", "common"),
+      locale: safeLocale,
+      t: await getTranslation(safeLocale, "common"),
📝 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
const reminderLocale = isEmailAttendeeAction
? attendeeToBeUsedInMail.language?.locale
: evt.organizer.language.locale;
const reminderLocale = isEmailAttendeeAction
? attendeeToBeUsedInMail.language?.locale
: evt.organizer.language.locale;
const safeLocale = reminderLocale || "en";
emailContent = emailReminderTemplate({
isEditingMode: false,
locale: safeLocale,
t: await getTranslation(safeLocale, "common"),
// …other template props
});
🤖 Prompt for AI Agents
In packages/features/ee/workflows/lib/reminders/emailReminderManager.ts around
lines 196 to 198, the reminderLocale assignment can be undefined when
attendeeToBeUsedInMail.language?.locale or evt.organizer.language.locale is
missing; change the expression to provide a fallback (e.g., append || "en" to
the chosen value) so reminderLocale is always a defined locale string before
passing it to emailReminderTemplate and date/time formatting.

Comment on lines +165 to +174
// Use the recipient's locale for proper date/time localization
// This ensures variables like {EVENT_DATE_ddd} are localized to the recipient's language
const locale =
action === WorkflowActions.SMS_ATTENDEE
? attendeeToBeUsedInSMS.language?.locale
: evt.organizer.language.locale;
smsMessage =
smsReminderTemplate(
false,
evt.organizer.language.locale,
locale,
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 | 🟡 Minor

Add fallback locale to handle undefined values.

The locale selection doesn't provide a fallback when attendeeToBeUsedInSMS.language?.locale is undefined, potentially passing undefined to smsReminderTemplate. This could cause issues with date/time formatting and template rendering.

Apply this diff to add a fallback:

-        const locale =
-          action === WorkflowActions.SMS_ATTENDEE
-            ? attendeeToBeUsedInSMS.language?.locale
-            : evt.organizer.language.locale;
+        const locale =
+          action === WorkflowActions.SMS_ATTENDEE
+            ? attendeeToBeUsedInSMS.language?.locale || "en"
+            : evt.organizer.language.locale || "en";

This matches the pattern used in scheduleWhatsappReminders.ts at lines 78-81.

🤖 Prompt for AI Agents
In packages/features/ee/workflows/lib/reminders/smsReminderManager.ts around
lines 165 to 174, the locale selection can be undefined when
attendeeToBeUsedInSMS.language?.locale is missing; update the assignment to
provide a fallback (use the organizer's locale and then a global default like
'en' as final fallback) so smsReminderTemplate never receives undefined;
implement the same fallback chain used in scheduleWhatsappReminders (e.g.,
attendee locale || organizer locale || 'en').

Comment on lines +85 to +88
const locale =
action === WorkflowActions.WHATSAPP_ATTENDEE
? evt.attendees[0].language?.locale
: evt.organizer.language.locale;
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 | 🟡 Minor

Add fallback locale to handle undefined values.

The locale selection doesn't provide a fallback when evt.attendees[0].language?.locale is undefined. This locale is used extensively for date/time formatting via dayjs.locale() (lines 96, 99) and in multiple template function calls, where undefined values could cause formatting issues.

Apply this diff to add a fallback:

   const locale =
     action === WorkflowActions.WHATSAPP_ATTENDEE
-      ? evt.attendees[0].language?.locale
-      : evt.organizer.language.locale;
+      ? evt.attendees[0].language?.locale || "en"
+      : evt.organizer.language.locale || "en";

This matches the pattern used in scheduleWhatsappReminders.ts at lines 78-81.

📝 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
const locale =
action === WorkflowActions.WHATSAPP_ATTENDEE
? evt.attendees[0].language?.locale
: evt.organizer.language.locale;
const locale =
action === WorkflowActions.WHATSAPP_ATTENDEE
? evt.attendees[0].language?.locale || "en"
: evt.organizer.language.locale || "en";
🤖 Prompt for AI Agents
In packages/features/ee/workflows/lib/reminders/whatsappReminderManager.ts
around lines 85 to 88, the locale selection can end up undefined when
evt.attendees[0].language?.locale is missing; change the assignment so that when
action === WorkflowActions.WHATSAPP_ATTENDEE you use
attendees[0].language?.locale with a fallback to evt.organizer.language.locale
(i.e., use the attendee locale if present, otherwise fall back to the organizer
locale), matching the pattern used in scheduleWhatsappReminders.ts lines 78–81
so dayjs.locale() and template calls never receive undefined.

@Devanshusharma2005
Copy link
Contributor

hey @Bhavyabhardwaj thanks for the Pr. But this issue still needs approval. It is advised not to start working on an issue which has a "needs approval" tag. Closing the pr for now. Happy to reopen the if the issue got approval.

@Bhavyabhardwaj
Copy link
Contributor Author

@Devanshusharma2005 Thanks for the clarification! I wasn't aware of the "needs approval" workflow. Will avoid working on such issues in the future and wait for proper approval. Appreciate the guidance!

@Bhavyabhardwaj
Copy link
Contributor Author

Hi @Devanshusharma2005
I see that issue #24280 now has the "needs approval" label removed and appears to be approved. Since you mentioned you'd be "happy to reopen if the issue got approval," could we please reopen this PR?
Thanks!

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

Labels

🐛 bug Something isn't working community Created by Linear-GitHub Sync ✨ feature New feature or request i18n area: i18n, translations 🚨 needs approval This feature request has not been reviewed yet by the Product Team and needs approval beforehand size/M workflows area: workflows, automations

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Option to localise date variables

3 participants