16 KiB
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 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
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_languageis 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 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
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 user’s 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 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, andfr. - 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.