# 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.