Files
carmanagement/docs/project-design/NOTIFICATION_LOCALIZATION_POLICY.md
T
2026-05-26 19:28:44 -04:00

16 KiB
Raw Blame History

Notification Language and Localization Policy

1. Objective

The notification system must send all customer-facing notifications in the language selected by the user during account creation.

Supported initial languages:

EN
AR
FR

Language mapping:

User Selection Locale Code Notification Language
EN en English
AR ar Arabic
FR fr French

This applies to account creation, workspace creation, invitations, trial notifications, subscription status notifications, billing notifications, invoice notifications, payment failure notifications, refunds, credits, in-app notifications, email notifications, SMS notifications if enabled, and customer-facing webhook labels if applicable.

Internal admin alerts may use the internal teams default language unless configured otherwise.


2. Source of Truth for Notification Language

The users selected language at account creation must be stored and used as the primary language preference.

Required User Field

ALTER TABLE users
ADD COLUMN preferred_language TEXT NOT NULL DEFAULT 'en';

Allowed values:

en
ar
fr

Account Creation Requirement

During account creation, the user must select or confirm a language.

Example payload:

{
  "email": "user@example.com",
  "name": "Example User",
  "preferred_language": "ar"
}

Rules:

  • preferred_language is required at account creation.
  • If not provided, default to en.
  • The selected language must be saved on the user profile.
  • The selected language must be used for all customer-facing notifications.
  • Users may update their preferred language later from account settings.
  • Updating the language affects future notifications only, not historical notifications.

3. Language Resolution Policy

When sending a notification, resolve the language in this order:

recipient user preferred_language
workspace default_language
billing account preferred_language
organization default_language
system default_language

Default:

en

Example:

User preferred_language = ar
Workspace default_language = fr
System default_language = en

Selected notification language = ar

The recipients own language wins. Not the workspace. Not the billing account. Not a hardcoded backend default.


4. Workspace and Billing Language Fields

In addition to the users language, store default language on workspace and billing account.

Workspace Field

ALTER TABLE workspaces
ADD COLUMN default_language TEXT NOT NULL DEFAULT 'en';

Billing Account Field

ALTER TABLE billing_accounts
ADD COLUMN preferred_language TEXT NOT NULL DEFAULT 'en';

Purpose:

Field Purpose
users.preferred_language Primary language for direct user notifications
workspaces.default_language Fallback for workspace-level notifications
billing_accounts.preferred_language Fallback for finance/billing notifications
system.default_language Final fallback

5. Template Localization Policy

Every customer-facing notification template must exist in all supported languages.

Required locales:

en
ar
fr

Template Table Update

CREATE TABLE notification_templates (
  id UUID PRIMARY KEY,

  template_key TEXT NOT NULL,
  category TEXT NOT NULL,
  channel TEXT NOT NULL,

  locale TEXT NOT NULL,

  subject TEXT,
  body TEXT NOT NULL,

  required_variables JSONB,
  optional_variables JSONB,

  version INTEGER NOT NULL DEFAULT 1,
  is_active BOOLEAN NOT NULL DEFAULT TRUE,

  created_at TIMESTAMP NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMP NOT NULL DEFAULT NOW(),

  UNIQUE(template_key, channel, locale, version)
);

Preferred template structure:

template_key = account.created.email
locale = en

template_key = account.created.email
locale = ar

template_key = account.created.email
locale = fr

Do not encode the locale into the template key if the table already has a locale column. Duplicating state is how small mistakes become expensive folklore.


6. Template Lookup Policy

When rendering a notification:

1. Resolve recipient language.
2. Find active template for template_key + channel + resolved locale.
3. If unavailable, fall back to English.
4. If English template is unavailable, fail notification creation and alert admins.

Lookup flow:

event received
  ↓
resolve recipient
  ↓
resolve recipient language
  ↓
find localized template
  ↓
render template
  ↓
send notification

Fallback rules:

Condition Action
ar template exists Send Arabic notification
fr template exists Send French notification
Requested locale missing Fall back to English
English fallback missing Fail and alert internal admins
Template variables missing Fail and alert internal admins

Fallback to English is allowed only as a safety net. It should be monitored as a product defect.


7. Arabic Language Requirements

Arabic notifications must support right-to-left rendering.

For locale:

ar

Apply:

<html lang="ar" dir="rtl">

or for partial rendering:

<div lang="ar" dir="rtl">
  ...
</div>

Arabic requirements:

  • Use RTL layout for email and in-app notifications.
  • Align Arabic text to the right.
  • Use Arabic translations for all customer-facing labels.
  • Use localized date formatting where possible.
  • Keep invoice numbers, amounts, and technical IDs readable.
  • Avoid mixing English UI labels into Arabic notifications unless they are brand or product names.
  • Test Arabic templates separately.

8. French Language Requirements

For locale:

fr

Apply:

<html lang="fr">

French requirements:

  • Use French templates for all customer-facing messages.
  • Use localized date formatting.
  • Use localized money formatting where appropriate.
  • Avoid partial English/French mixed messages.
  • Keep plan names and product names unchanged unless officially translated.

9. English Language Requirements

For locale:

en

Apply:

<html lang="en">

English is the default fallback language.


10. Localized Formatting Policy

Notifications should localize:

  • Subject lines
  • Body text
  • Button labels
  • Status labels
  • Dates
  • Currency display
  • Invoice labels
  • Subscription status labels
  • Error messages
  • Call-to-action text

Date formatting examples:

Locale Display
en June 15, 2026
fr 15 juin 2026
ar ١٥ يونيو ٢٠٢٦

Currency formatting should respect both billing currency and locale.

Example for USD:

Locale Display
en $1,200.00
fr 1 200,00 $US
ar ١٬٢٠٠٫٠٠ US$

Do not store localized amounts as the source of truth. Store money as integer minor units and format at render time.


11. Localized Subscription Status Labels

English

Internal Status English Label
trialing Trial active
active Active
payment_pending Payment pending
past_due Payment overdue
suspended Suspended
canceled Canceled
expired Expired

French

Internal Status French Label
trialing Essai actif
active Actif
payment_pending Paiement en attente
past_due Paiement en retard
suspended Suspendu
canceled Annulé
expired Expiré

Arabic

Internal Status Arabic Label
trialing الفترة التجريبية نشطة
active نشط
payment_pending الدفع قيد الانتظار
past_due الدفع متأخر
suspended معلّق
canceled ملغى
expired منتهي

12. Localized Invoice Labels

English

Internal Invoice Status English Label
draft Preparing
open Due
payment_pending Payment processing
paid Paid
partially_paid Partially paid
past_due Past due
void Canceled
uncollectible Contact support
refunded Refunded
partially_refunded Partially refunded

French

Internal Invoice Status French Label
draft En préparation
open À payer
payment_pending Paiement en cours
paid Payée
partially_paid Partiellement payée
past_due En retard
void Annulée
uncollectible Contacter le support
refunded Remboursée
partially_refunded Partiellement remboursée

Arabic

Internal Invoice Status Arabic Label
draft قيد الإعداد
open مستحقة الدفع
payment_pending الدفع قيد المعالجة
paid مدفوعة
partially_paid مدفوعة جزئياً
past_due متأخرة
void ملغاة
uncollectible تواصل مع الدعم
refunded مستردة
partially_refunded مستردة جزئياً

13. Notification Creation Logic

When an event creates a notification, include the resolved locale.

Notification Record Update

ALTER TABLE notifications
ADD COLUMN locale TEXT NOT NULL DEFAULT 'en';

Example notification record:

{
  "event_type": "invoice.finalized",
  "recipient_email": "finance@example.com",
  "recipient_role": "billing_owner",
  "channel": "email",
  "template_key": "invoice.finalized.email",
  "locale": "fr",
  "status": "pending"
}

14. Notification Rendering Pseudocode

type SupportedLocale = "en" | "ar" | "fr";

function resolveNotificationLocale(recipient, workspace, billingAccount): SupportedLocale {
  return (
    recipient.preferredLanguage ||
    workspace.defaultLanguage ||
    billingAccount.preferredLanguage ||
    "en"
  );
}

async function createNotification(event, recipient) {
  const locale = resolveNotificationLocale(
    recipient.user,
    event.workspace,
    event.billingAccount
  );

  const template = await findTemplate({
    templateKey: event.templateKey,
    channel: event.channel,
    locale
  });

  const fallbackTemplate = await findTemplate({
    templateKey: event.templateKey,
    channel: event.channel,
    locale: "en"
  });

  const selectedTemplate = template || fallbackTemplate;

  if (!selectedTemplate) {
    throw new Error("Missing notification template");
  }

  return {
    eventType: event.type,
    recipientEmail: recipient.email,
    channel: event.channel,
    templateKey: event.templateKey,
    locale: selectedTemplate.locale,
    renderedContent: renderTemplate(selectedTemplate, event.payload)
  };
}

15. Account Creation Flow Update

During account creation:

user selects language
  ↓
system stores preferred_language
  ↓
account.created event emitted
  ↓
notification system resolves preferred_language
  ↓
localized welcome notification sent

Account Creation API Update

POST /accounts

Request:

{
  "name": "Example User",
  "email": "user@example.com",
  "password": "secure_password",
  "preferred_language": "ar"
}

Response:

{
  "account_id": "acct_123",
  "user_id": "user_123",
  "preferred_language": "ar"
}

Validation:

preferred_language must be one of: en, ar, fr

16. Notification Preference Update

Language preference should be separate from notification category preferences.

Example user settings:

preferred_language = ar
invoice.email.enabled = true
billing.email.enabled = true
onboarding.email.enabled = false

Rules:

  • Language controls the language of notifications.
  • Preferences control whether allowed notifications are sent.
  • Critical billing, invoice, payment, and security notifications still follow mandatory delivery rules.
  • Changing language does not unsubscribe the user from notifications.
  • Changing language affects future notifications only.

17. Testing Requirements

Unit Tests

Test:

User with preferred_language=en receives English template
User with preferred_language=ar receives Arabic template
User with preferred_language=fr receives French template
Missing Arabic template falls back to English
Missing French template falls back to English
Missing English fallback fails notification creation
Arabic email renders with dir="rtl"
French email renders with lang="fr"
English email renders with lang="en"

Integration Tests

Test:

Account created with EN → welcome email sent in English
Account created with AR → welcome email sent in Arabic
Account created with FR → welcome email sent in French
Invoice finalized for AR billing owner → Arabic invoice notification
Payment failed for FR billing owner → French payment failure notification
Subscription suspended for EN admin → English suspension notification

End-to-End Tests

Test:

User creates account and selects Arabic
  ↓
Arabic welcome email is sent
  ↓
User starts trial
  ↓
Arabic trial notification is sent
  ↓
Invoice is generated
  ↓
Arabic invoice notification is sent
  ↓
Payment fails
  ↓
Arabic payment failure notification is sent

18. Monitoring Requirements

Track localization metrics:

notifications_sent_by_locale
notifications_failed_by_locale
template_missing_by_locale
fallback_to_english_count
rtl_rendering_test_failures
language_preference_update_count

Alert on:

Missing Arabic template
Missing French template
Fallback-to-English spike
Arabic rendering failure
Localized template variable error

Fallback-to-English should be treated as a defect, not a harmless convenience.


19. Updated Notification Localization Section

Replace the earlier notification localization section with this stricter version.

Notification Localization

Notification templates must support the users selected account language.

Supported locales:

en
ar
fr

Template lookup order:

recipient user preferred_language
workspace default_language
billing account preferred_language
system default_language

The language selected during account creation is the primary source of truth for user-facing notifications.

Arabic notifications must render in RTL mode.

French and English notifications must use localized date, currency, and status labels.

Fallback to English is allowed only when a localized template is missing, and every fallback must create an internal alert.


20. Final Localization Policy

Use this as the baseline rule:

The language selected by the user during account creation is the primary language for all customer-facing notifications.
Supported languages are English, Arabic, and French.
English uses locale en.
Arabic uses locale ar and must render right-to-left.
French uses locale fr.
Each customer-facing notification template must exist in en, ar, and fr.
If a localized template is missing, the system may fall back to English, but must log and alert the missing localization.
Billing, invoice, subscription, and account notifications must use the recipients preferred language.
Language preference is separate from notification opt-in preferences.
Changing language affects future notifications only.
Internal admin alerts may use the internal default language unless configured otherwise.

21. Definition of Done

The notification localization system is complete when:

  • Account creation stores preferred_language.
  • Supported languages are limited to en, ar, and fr.
  • Notification records store the resolved locale.
  • Email templates exist in English, Arabic, and French.
  • In-app notification templates exist in English, Arabic, and French.
  • Arabic templates render correctly in RTL.
  • French templates render with French labels and formatting.
  • Dates and currency are localized during rendering.
  • Missing localized templates fall back to English and create alerts.
  • Tests cover account, subscription, billing, invoice, and payment notifications for all supported languages.