# 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: ```text 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 team’s default language unless configured otherwise. --- ## 2. Source of Truth for Notification Language The user’s selected language at account creation must be stored and used as the primary language preference. ### Required User Field ```sql ALTER TABLE users ADD COLUMN preferred_language TEXT NOT NULL DEFAULT 'en'; ``` Allowed values: ```text en ar fr ``` ### Account Creation Requirement During account creation, the user must select or confirm a language. Example payload: ```json { "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: ```text recipient user preferred_language workspace default_language billing account preferred_language organization default_language system default_language ``` Default: ```text en ``` Example: ```text User preferred_language = ar Workspace default_language = fr System default_language = en Selected notification language = ar ``` The recipient’s 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 user’s language, store default language on workspace and billing account. ### Workspace Field ```sql ALTER TABLE workspaces ADD COLUMN default_language TEXT NOT NULL DEFAULT 'en'; ``` ### Billing Account Field ```sql 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: ```text en ar fr ``` ### Template Table Update ```sql 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: ```text 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: ```text 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: ```text 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: ```text ar ``` Apply: ```html ``` or for partial rendering: ```html
...
``` 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: ```text fr ``` Apply: ```html ``` 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: ```text en ``` Apply: ```html ``` 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 ```sql ALTER TABLE notifications ADD COLUMN locale TEXT NOT NULL DEFAULT 'en'; ``` Example notification record: ```json { "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 ```ts 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: ```text user selects language ↓ system stores preferred_language ↓ account.created event emitted ↓ notification system resolves preferred_language ↓ localized welcome notification sent ``` ### Account Creation API Update ```http POST /accounts ``` Request: ```json { "name": "Example User", "email": "user@example.com", "password": "secure_password", "preferred_language": "ar" } ``` Response: ```json { "account_id": "acct_123", "user_id": "user_123", "preferred_language": "ar" } ``` Validation: ```text 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: ```text 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: ```text 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: ```text 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: ```text 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: ```text 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: ```text 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 user’s selected account language. Supported locales: ```text en ar fr ``` Template lookup order: ```text 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: ```text 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 recipient’s 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.