Sindh IT Portal — Facilitation DeskSpecification documents
Englishاردوسنڌي
← All documents

Internationalization & Localization

How the Sindh IT Portal — Facilitation Desk (SITP) is built trilingual (English master → Urdu → Sindhi), right-to-left native, dual-calendar aware, and glossary-consistent across every surface — public site, docs, notifications, official letters, and AI output.

Field Value
Doc ID 09
Status Draft
Owner S&ITD / MAAHIR
Languages EN (master) · UR · SD
Applies to modules A (PUB) primary · cross-cutting: B (TKT), E (AI), G (NOT), J (KB), L (DOC), M (MTG), N (SUG), O (TRN), P (OFC)
Related docs /specs/en/15-tech-architecture/ §15, /specs/en/16-branding-design-system/, /specs/en/10-ux-sitemap-flows/, /specs/en/07-ai-ocr-spec/, /specs/en/13-test-strategy/, _glossary.md, _context.md §2 & §7

1. Scope & How to Read This Document

This document is the authoritative specification for everything multilingual in SITP. It covers:

The high-level platform treatment of i18n lives in /specs/en/15-tech-architecture/ §15; this document expands that section into a full, build-ready specification. The trilingual term dictionary in _glossary.md is the single source of approved translations — this document governs how those translations are applied, not what they are.


2. Language Strategy & Locale Model

2.1 The three locales

Code Language Script Direction Role Native name
en English Latin LTR Master / source of truth English
ur Urdu Arabic (Nastaliq) RTL Parallel translation اردو
sd Sindhi Arabic (Naskh, extended) RTL Parallel translation سنڌي

English is the authoring locale. Every UI string, KB article, circular, SOP, notification template, official letter template, and email/SMS/WhatsApp template is authored in English first and then produced as a faithful parallel translation in Urdu and Sindhi. No content ships in UR or SD without an EN master. The only exception is citizen-submitted free text, which is stored verbatim in whatever language the submitter wrote it in, and translated on demand by the AI Translation capability (see §6).

This mirrors the documentation set itself: each doc folder contains {en,ur,sd}.md, EN master (see _conventions.md §2). The same discipline applies to product content.

2.2 Locale identifiers

Internally, locale is represented by the ISO 639-1 code (en, ur, sd) without region subtags, because the variety targeted is the Pakistan provincial standard for each. Where a third-party library requires a region subtag (e.g., en-PK, ur-PK, sd-PK), the subtag PK is appended for that interaction only; the canonical stored value remains the bare two-letter code.

2.3 Script and direction association

Direction (ltr or rtl) is a function of locale, never a separate user setting. Selecting ur or sd flips the entire layout to RTL; selecting en flips it back to LTR. There is no "English in RTL" or "Urdu in LTR" mode. This keeps CSS, layout, and component logic simple and predictable, and matches user expectation.


3. Locale Storage & Resolution

3.1 Where locale is stored

Locale is stored in three places, in resolution order:

# Store Scope Set by Notes
1 URL path prefix (/en/, /ur/, /sd/) Per request / per page User navigation, locale switcher Canonical and shareable. Always present on public pages.
2 usr_user.locale column Per user User, on registration or via profile/preference center Default for authenticated sessions when no URL prefix is present.
3 org_organization.default_locale column Per organization (company or department) Org Admin Fallback when a user has no explicit locale (e.g., newly invited staff).

Anonymous visitors get locale from (a) explicit URL prefix, else (b) Accept-Language header negotiated against [en, ur, sd], else (c) en (the master). The resolved locale is persisted to a first-party cookie (sitp_locale) so subsequent visits are sticky, but the URL prefix always wins — this keeps deep links shareable and unambiguous.

3.2 How locale propagates

Once resolved at the edge, locale is propagated everywhere it is needed, with no re-prompting of the user:

3.3 Locale switching

A visible locale switcher is present in the header of every page (public site, docs, portal app, mobile PWA). Switching locale:

  1. Rewrites the current URL to the target locale prefix.
  2. Updates the sitp_locale cookie.
  3. If authenticated, persists the new locale to usr_user.locale (so it sticks across devices).
  4. Re-renders the page in the new locale and direction without a full reload where possible (Next.js App Router supports this natively).

The switcher never drops the user's place: the same route, the same ticket, the same KB article — just in the other language.

3.4 Per-org default for staff

Government staff (officers, section heads, watchers) typically work in their department's default locale, which may differ from a citizen's preferred locale. When an officer views a ticket filed by a Urdu-locale company, the system chrome (menus, buttons, status labels) renders in the officer's locale, while the ticket content (title, description, messages) is shown in the author's original locale with an on-demand "translate" affordance (see §6). This separation prevents a Sindhi-speaking officer from being forced to read Urdu chrome, and vice versa, while preserving the integrity of the original record.


4. String Externalization (No Hardcoded Strings)

4.1 The rule

No user-facing string is ever hardcoded in source code. Every label, button, tooltip, error message, status name, email subject, SMS body, placeholder, aria-label, toast, empty-state, and validation message lives in a message catalog keyed by a stable identifier. Components reference the key; the runtime resolves the key to the active locale's string.

This applies to:

4.2 Enforcement

Hardcoding is prevented by a combination of:

4.3 Interpolation and pluralization

Strings support ICU MessageFormat for:

Plural rules differ across locales (English has one/other; Arabic-script locales have zero/one/two/few/many/other). The message-format library handles this; translators supply all required plural forms per key.


5. Translation-File Workflow

5.1 Catalog structure

UI strings live in per-locale message catalogs, organized by feature surface so files stay reviewable:

locales/
  en/
    common.json
    auth.json
    tickets.json
    notifications.json
    letters.json
    dashboard.json
    errors.json
    ...
  ur/
    common.json
    auth.json
    ...
  sd/
    common.json
    auth.json
    ...

Each catalog is a flat JSON object keyed by stable dotted identifiers:

{
  "tickets.status.new": "New",
  "tickets.status.resolved": "Resolved",
  "tickets.emptyState.title": "No tickets yet",
  "tickets.emptyState.body": "File your first ticket to get started."
}

Keys are namespaced by feature (tickets., auth., letters., …) and never renamed once shipped — renaming a key breaks translations in flight. Obsolete keys are deprecated, not deleted, until no code references them and all three locales have dropped them.

5.2 Long-form content (MDX)

Long-form content — KB articles, circulars, SOPs, the docs site pages themselves — is authored as MDX per locale rather than JSON, because the content mixes prose, components, and media. The same file-and-folder convention as the docs set applies: each content item is a folder with en.mdx, ur.mdx, sd.mdx. Front matter carries the locale, last-translated timestamp, source EN revision it was translated from, and review status (see §6).

5.3 Per-locale JSON/MDX parity

For every feature release:

  1. EN catalogs and MDX are updated.
  2. A diff is generated: new keys, changed keys, deleted keys.
  3. UR and SD catalogs are updated (AI-assisted first, human-reviewed second — see §6).
  4. A parity check runs in CI: every key present in en/*.json must be present in ur/*.json and sd/*.json. Missing keys fail the build (forcing an explicit decision: translate now, or intentionally mark as fallback-to-EN with a tracked debt item).

5.4 Status tracking per content item

Each translatable artifact (UI key set per feature, KB article, SOP, letter template) carries a translation status:

Status Meaning
source-only EN authored; UR/SD pending.
ai-draft AI translation generated; awaiting human review.
in-review Assigned to a native reviewer; not yet approved.
approved Native reviewer signed off; safe to publish.
published Live in the locale.
stale EN source changed since last approval; re-translation needed.

Status is stored per locale per artifact and surfaced in the translation dashboard (see §15).


6. AI-Assisted Translation Pipeline + Human Native Review

6.1 Pipeline overview

Source content authored in EN is translated into UR and SD through a hybrid pipeline: AI does the first pass (fast, cheap, consistent), a native human reviewer does the final pass (correctness, register, cultural fit, terminology). Nothing publishes in UR or SD on AI output alone. This is the same AI Translation capability described in /specs/en/07-ai-ocr-spec/ and /specs/en/15-tech-architecture/ §6.3 #6, constrained by the glossary.

6.2 Workflow diagram

flowchart TD SRC["EN source authored<br/>(UI catalog / KB MDX / letter template / notification)"] DIFF["Diff against prior EN revision<br/>(new, changed, deleted keys/content)"] GLOSS["Load glossary constraints<br/>(from _glossary.md → terminology DB)"] AI["AI translation pass<br/>(cloud LLM · glossary-injected · locale-targeted)"] QUEUE["Per-locale review queue<br/>(UR reviewer · SD reviewer)"] REV["Native human review<br/>(correctness · register · terminology · RTL fit)"] DEC{Approved?} EDIT["Reviewer edits<br/>(inline diff vs AI draft)"] PUB["Publish to locale catalog<br/>(status: approved → published)"] FB["Feedback to AI tuning set<br/>(reviewer corrections seed future runs)"] FALL["If untranslated:<br/>fallback to EN with visible marker (see §12)"] SRC --> DIFF DIFF --> GLOSS GLOSS --> AI AI --> QUEUE QUEUE --> REV REV --> DEC DEC -- no --> EDIT EDIT --> DEC DEC -- yes --> PUB EDIT --> FB PUB --> FB DIFF -. untranslated .-> FALL

6.3 Written description of the workflow

Source content is authored in English (UI catalog entry, KB MDX file, letter template, or notification template). A differ compares the new EN revision against the previously-translated EN revision and emits three buckets: new strings (never translated), changed strings (EN edited since last translation — marked stale), and deleted strings (drop from the locale catalog).

For new and changed items, the glossary constraints are loaded from the terminology database (itself derived from _glossary.md — see §7) and injected into the AI call as forced translations and forbidden mappings. The AI translation pass runs per target locale (ur, then sd) via the pluggable LLM (see /specs/en/15-tech-architecture/ §6.1), producing a draft that already respects approved terminology.

The draft lands in a per-locale review queue. A native human reviewer (Urdu-native for UR, Sindhi-native for SD — never the same person for both, never a non-native speaker) opens the draft alongside the EN source and the glossary, and checks four things: (1) correctness — does it say what the EN says; (2) register — is the formality right for a government-facing product; (3) terminology — are glossary terms used exactly as approved, with the Department-vs-Ministry distinction (§16) intact; (4) RTL fit — does the string read naturally when rendered right-to-left in the target font, with no broken bi-directional mixing. The reviewer either approves or edits inline; edits are tracked as a diff against the AI draft.

On approval, the string is published to the locale catalog and becomes live. Reviewer corrections are fed back into the AI tuning set (a curated corpus of EN→UR and EN→SD pairs with reviewer-accepted outputs), which improves future AI first-pass quality and reduces reviewer load over time. Items that are not yet translated fall back to English with a visible marker in the UI (see §12), so the product is never blocked on translation — but the gap is tracked and closed in the next review cycle.

6.4 On-demand translation of user content

The same pipeline, minus the human gate, runs on demand for user-submitted free text — ticket descriptions, chat messages, MoM uploads, inbound email/SMS/WhatsApp replies. An officer viewing a Urdu ticket in an English-locale session clicks "Translate"; the AI returns an EN rendering inline, clearly labelled as machine translation, with the original preserved. The original is the record; the translation is a convenience. For official documents (resolution certificates, letters), the human-reviewed catalog translations are used, never raw AI output.

6.5 Reviewer roster

Reviewers are engaged against a native-language requirement: Urdu reviewers are Urdu-native (typically based in Sindh, familiar with Pakistani government register); Sindhi reviewers are Sindhi-native. Reviewers are accredited through the Training & Certification module (O) with an exam-gated "Native Reviewer" certification before handling live content — mirroring the staff certification pattern. At least two reviewers per locale are maintained for redundancy and cross-checking on sensitive content (official letters, legal/RTI wording).


7. Glossary-Driven Term Consistency

7.1 The glossary as contract

_glossary.md is the authoritative trilingual term dictionary for SITP. Every government, legal, ticketing, role, technical, and acronym term has an approved EN/UR/SD rendering. Translators, reviewers, and the AI translation pipeline must use these renderings exactly; deviation is a defect caught in QA (see §15).

7.2 From markdown to a queryable terminology DB

The markdown glossary is the human-readable source. A build step compiles it into a terminology database (a JSON map keyed by English term, with ur, sd, definition, and notes fields) that:

7.3 Glossary growth

When a document or translation introduces a term not in the glossary, the convention (see _conventions.md §2) is to add it to the glossary first, then use the approved translation everywhere. The glossary is therefore a living artifact; changes to it are versioned and broadcast to all active reviewers so they re-check in-flight translations against the new term.

7.4 Consistency checks in CI

A terminology linter runs in CI over every locale catalog and MDX file:


8. RTL Handling

8.1 Direction as a layout primitive

Urdu and Sindhi render right-to-left. RTL is not a CSS afterthought; it is a first-class layout dimension handled by three mechanisms working together.

8.2 Mechanism 1 — the dir attribute

The document <html> element carries dir="ltr" for en and dir="rtl" for ur and sd. Docusaurus sets this automatically from the locale; the Next.js portal sets it from the resolved locale on the root layout. The dir attribute cascades to every descendant, so the entire component tree flips with no per-component work. The lang attribute is set in parallel (lang="en", lang="ur", lang="sd") for screen readers and search engines (see §14).

8.3 Mechanism 2 — CSS logical properties

All layout CSS uses logical properties instead of physical ones, so a single rule serves both directions:

Physical (forbidden) Logical (used)
margin-left margin-inline-start
margin-right margin-inline-end
padding-left / padding-right padding-inline-start / padding-inline-end
left / right (positioning) inset-inline-start / inset-inline-end
float: left restructure with flex/grid + inline-start
text-align: left text-align: start
border-left border-inline-start

TailwindCSS (locked stack) supports logical properties via its ps-/pe-/ms-/me-/start-/end- utilities and the rtl:/ltr: variant modifiers for the rare case where a literal mirror is needed. The team standardizes on the logical utilities; physical pl-/pr-/ml-/mr- are flagged by lint unless explicitly justified.

8.4 Mechanism 3 — icon and layout mirroring

Directional icons mirror in RTL: a "back" arrow that points left in LTR points right in RTL; a "next" chevron flips; a sidebar pinned to the left in LTR pins to the right in RTL. This is handled by:

8.5 Bi-directional text mixing

When Urdu or Sindhi text contains embedded Latin (ticket IDs like SITP-2026-LBR-000123, acronyms like SECP, numbers, URLs), the Unicode Bidirectional Algorithm handles rendering. To prevent spillover errors at boundaries, the team wraps embedded LTR runs in <bdi> and uses dir="auto" on user-submitted content fields so the browser picks direction from the first strong directional character. Ticket IDs, CNICs, and NTNs are always rendered LTR even inside RTL prose, using an explicit <span dir="ltr"> wrapper.

8.6 What RTL is not

RTL is not a separate design or a separate component tree. There is one design system (see /specs/en/16-branding-design-system/) rendered in two directions. There are no Component.ltr.tsx and Component.rtl.tsx files. The few exceptions (an icon that must not mirror, a hero illustration with embedded directional meaning) are flagged and reviewed individually.


9. Typography & Fonts

9.1 Locked font stack

Per _context.md §7:

Locale Primary font Fallback
en Inter (UI) / Poppins (display/headings) system sans-serif
ur Noto Nastaliq Urdu Jameel Noori Nastaleeq (system), sans-serif
sd Noto Naskh Arabic (Sindhi-extended glyph coverage) system Arabic, sans-serif

9.2 Loading strategy

Fonts are self-hosted (not loaded from Google Fonts at runtime, for privacy and performance) and subset by locale:

9.3 Line-height and vertical rhythm

Nastaliq (Urdu) and Naskh (Sindhi) scripts need taller line-height than Latin text — Nastaliq in particular has a large vertical extent (descenders and stacked diacritics). The design system ships per-locale line-height and letter-spacing tokens: EN tokens default to ~1.5 line-height; UR tokens default to ~2.0; SD tokens default to ~1.8. These are applied via CSS variables keyed off the lang attribute, not per-component overrides.

9.4 Font sizes and readability

Urdu and Sindhi render physically smaller than Latin at the same font-size due to script geometry. The design system applies a per-locale font-size scaling factor (UR/SD body text is ~10–15% larger than EN at the same visual hierarchy level) so visual readability is constant across languages.


10. Dual Calendar System (Gregorian + Hijri)

10.1 Government convention

Per _context.md §2, SITP displays both Gregorian and Hijri dates throughout — the convention for Pakistan government correspondence. Wherever a date is shown to a user (ticket created-on, SLA due date, MoM meeting date, official letter date, notification timestamp), both calendars appear, with Gregorian primary and Hijri derived beside or beneath it.

10.2 Storage vs. presentation

10.3 Date pickers

Every date picker in the portal (SLA due-date override, meeting scheduler, report date-range filter, holiday calendar editor) offers dual input: the user picks a Gregorian date and the corresponding Hijri date is shown beside it (and vice versa — picking a Hijri date back-computes the Gregorian). Both values travel to the backend; the Gregorian is authoritative.

10.4 Holiday calendar

The Sindh public holiday calendar (used for SLA pauses per _context.md §5) carries both Gregorian and Hijri dates for each holiday, because Islamic holidays are Hijri-defined (Eid, Ashura, Eid Milad-un-Nabi) while civil holidays are Gregorian-defined (Independence Day, Labour Day). The SLA engine consumes the Gregorian normalized form.


11. Number, Date, Currency & Phone Formatting

All formatting goes through a single locale-aware formatter (built on Intl with locale set from the resolved locale). No format string is constructed by hand.

Concern EN format UR format SD format Notes
Gregorian date 17 Jul 2026 ۱۷ جولائی ۲۰۲۶ ۱۷ جولاءِ ۲۰۲۶ Locale-aware month names; Eastern Arabic numerals in UR/SD by default (configurable — see §11.1).
Time 2:30 PM ۲:۳۰ بجہ دوپہر ۲:۳۰ بجہُ دوپھر 12-hour with locale AM/PM string; PKT.
Integer 1,234 ۱٬۲۳۴ ۱٬۲۳۴ Grouping separator locale-aware.
Currency (PKR) Rs 15,000 / ₨ 15,000 روپے ۱۵٬۰۰۰ روپيا ۱۵٬۰۰۰ Always PKR; stored as integer paisa (see /specs/en/15-tech-architecture/ §5.3).
Phone (PK) +92 300 1234567 +۹۲ ۳۰۰ ۱۲۳۴۵۶۷ +۹۲ ۳۰۰ ۱۲۳۴۵۶۷ E.164 stored; displayed with PK grouping.
Percentage 45% ۴۵٪ ۴۵٪ Locale numeral + locale percent sign.
Ticket ID SITP-2026-LBR-000123 SITP-2026-LBR-000123 SITP-2026-LBR-000123 Always Latin numerals, always LTR — IDs are identifiers, not prose.

11.1 Numeral policy

Pakistan commonly uses Eastern Arabic numerals (۰۱۲۳۴۵۶۷۸۹) in Urdu and Sindhi prose, but Latin numerals in technical/data contexts. SITP's default is Eastern Arabic in prose for UR/SD, Latin in data-dense UI (tables, dashboards, ticket IDs, SLA countdowns) for legibility and consistency with the analytics exports. The numeral variant is a per-locale token configurable by the Super Admin, so a department that prefers all-Latin can switch.

11.2 Phone formatting

Phone numbers are stored in E.164 (+92...), validated at input, and rendered through a PK-aware formatter. CNIC and NTN formats follow their official patterns (CNIC: XXXXX-XXXXXXX-X; NTN: 7 digits) and are always rendered LTR even in RTL locales, wrapped in <span dir="ltr">.

11.3 Currency

All currency is PKR (Pakistani Rupee). The portal does not handle foreign currency natively; the IT-industry beneficiary context is domestic. Currency is stored as integer minor units (paisa) and formatted at presentation.


12. Content Fallback Strategy

12.1 The rule

If a translation is missing in the active locale, the system falls back to English and shows a visible marker so the gap is never silent. Silent fallback (showing English with no indication) is forbidden because it hides translation debt from users and reviewers.

12.2 The visible marker

A missing-key resolution renders as:

12.3 Fallback chain

active-locale string  →  (missing)  →  English string  →  (missing)  →  the key itself in [brackets]

The final [key.itself] state is a hard failure caught in CI (§5.3) and should never reach production. The middle state (English fallback with marker) is the acceptable interim; the goal is zero of either in a released locale.

12.4 Long-form content

For MDX content (KB articles, SOPs), if a locale's translation is stale or missing, the page renders the English version with a banner at the top: "This article is not yet available in [Urdu/Sindhi]. Showing the English original." The banner carries a feedback link so users can request prioritization, and the gap is logged.


13. SEO: hreflang & Sitemap per Locale

13.1 hreflang

Every public page emits <link rel="alternate"> tags for each locale, plus x-default:

<link rel="alternate" hreflang="en" href="https://sindhitportal.maahir.io/en/..." />
<link rel="alternate" hreflang="ur" href="https://sindhitportal.maahir.io/ur/..." />
<link rel="alternate" hreflang="sd" href="https://sindhitportal.maahir.io/sd/..." />
<link rel="alternate" hreflang="x-default" href="https://sindhitportal.maahir.io/en/..." />

x-default points to the EN master. The locale-prefixed URL is canonical (see §3.1); there is no un-prefixed locale to avoid duplicate-content ambiguity. hreflang is emitted by both the Next.js portal (per route) and the Docusaurus docs site (built-in i18n support).

13.2 Sitemap

A per-locale sitemap index is generated at build time:

/sitemap.xml          → index listing the per-locale sitemaps
/sitemap-en.xml       → all EN public URLs
/sitemap-ur.xml       → all UR public URLs
/sitemap-sd.xml       → all SD public URLs

Each per-locale sitemap lists only URLs in that locale's prefix, with lastmod reflecting the content's last translation approval (not the EN source edit), so search engines see when the UR or SD version actually changed.

13.3 Localized metadata

<title>, <meta description>, Open Graph, and Twitter Card tags are all sourced from the locale catalog — never hardcoded, never auto-translated by the SEO layer. Each public page's metadata is a reviewed translation. OG images carry localized text overlays where the design system supports it (see /specs/en/16-branding-design-system/).

13.4 robots and crawl budget

The /ur/ and /sd/ trees are fully crawlable (not blocked); they are first-class content. The search engine's crawl budget is monitored in observability; if a locale is consistently under-indexed, the cause (slow render, missing hreflang, thin content) is investigated and fixed.


14. Accessibility per Locale

WCAG 2.1 AA conformance (locked in _context.md §2) applies to all three locales equally. Accessibility is not a single-locale concern.

14.1 Language attribution

14.2 RTL screen reader support

14.3 Color contrast and typography

14.4 Keyboard navigation

Tab order follows the visual order in both LTR and RTL. Keyboard shortcuts that imply direction (e.g., Alt+Left for back) are mirrored in RTL (Alt+Right for back) or made direction-neutral where possible. Skip-to-content links work in both directions.

14.5 Assistive technology testing

Each release includes an assistive-tech sweep across NVDA + Firefox and VoiceOver + Safari in all three locales, with particular attention to Nastaliq and Naskh pronunciation. Findings are tracked to closure before the locale is marked published.


15. Translation QA & Review Gates

15.1 The QA pipeline

Translation quality is enforced at four gates:

Gate When What runs Failure action
G1 — Lint On every commit No-hardcoded-strings rule; logical-properties-only rule; glossary terminology check. Build fails.
G2 — Parity On every PR touching locales Every EN key present in UR and SD; no orphan keys. Build fails (or explicit debt item opened).
G3 — Native review Before publish Native human reviewer signs off per §6. Item stays in in-review.
G4 — Visual sweep Before release LTR and RTL screenshots of every changed screen; bi-di mixing check; font-render check. Release blocked.

15.2 The translation debt dashboard

An internal dashboard (Super Admin and Department Admin visible) reports:

15.3 Linguistic QA sampling

Beyond per-item review, a periodic linguistic QA sweep samples published content per locale and checks for: terminology drift since the glossary was last updated, register consistency, tone across the product, and cultural appropriateness. Findings feed back into the glossary and the AI tuning set.

15.4 Visual regression in both directions

The visual regression suite (part of /specs/en/13-test-strategy/) runs every story in both dir="ltr" and dir="rtl". A change that looks right in EN but breaks layout in UR or SD fails the suite.


16. Official Terminology & Disambiguation

16.1 The Department vs Ministry distinction

The most consequential terminology rule in SITP, locked in _glossary.md (top critical-distinction note):

S&ITD is a provincial Department — Urdu محکمہ / Sindhi محڪمو. It is NOT a Ministry — Urdu وزارت / Sindhi وزارت. Translators must never render "Department" as "وزارت" or vice-versa.

This matters because Pakistan's federal ministries and provincial departments are constitutionally distinct; misnaming S&ITD as a "Ministry" in an official letter or public page is a factual and political error, not a stylistic one. The AI translation pipeline is given this as a hard forbidden mapping; the QA linter (§7.4, §15 G1) fails any translation that produces وزارت for "Department" or محکمہ for "Ministry".

16.2 Other locked distinctions

Term Correct Wrong Why it matters
Department (provincial) محکمہ / محڪمو وزارت / وزارت Provincial vs federal (§16.1).
Notification (gazette) نوٹیفکیشن / نوٽيفڪيشن اطلاع / اطلاع A binding legal order vs a system alert (glossary §1 vs §7).
Notification (system alert) اطلاع / اطلاع نوٹیفکیشن / نوٽيفڪيشن Same word, opposite mapping — context determines which.
Complaint شکایت / شڪايت other renderings Standard citizen-facing term.
Authorized Representative مجاز نمائندہ / مجاز نمائندو نمائندہ alone "Authorized" carries the legal empowerment; dropping it weakens the term.
Tracking ID ٹریکنگ آئی ڈی / ٽريڪنگ آءِ ڊي other renderings Public-facing identifier; consistency aids look-up.

16.3 Never-translated terms

Some terms are kept in their original form across all three locales, by glossary rule:

Translators and the AI pipeline are told to leave these as-is; attempting to "translate" NADRA into Urdu script is a defect.

16.4 Transliteration fallback

Where the glossary marks a term (معیاری ترجمہ درکار) ("standard translation needed"), the term is transliterated into native script and flagged for future glossary refinement. These items appear in the debt dashboard (§15.2) so the glossary owners close them.


17. Functional Requirements

ID Requirement MoSCoW
FR-PUB-101 The system shall support exactly three locales: en (master, LTR), ur (RTL), sd (RTL). [Must]
FR-PUB-102 The system shall resolve locale from (in order) URL prefix, user preference, org default, Accept-Language, and finally en. [Must]
FR-PUB-103 The system shall propagate the resolved locale through the JWT, every BullMQ job payload, the NestJS request context, every template render, every search query, and every AI call. [Must]
FR-PUB-104 No user-facing string shall be hardcoded in source code; all strings shall be sourced from per-locale message catalogs. [Must]
FR-PUB-105 The system shall provide a per-locale message catalog (JSON) for UI strings and per-locale MDX for long-form content. [Must]
FR-PUB-106 The system shall provide a locale switcher on every page that rewrites the URL prefix, updates the cookie, persists to the user record, and preserves the user's current location. [Must]
FR-PUB-107 The system shall render Urdu and Sindhi locales right-to-left via the dir attribute and CSS logical properties. [Must]
FR-PUB-108 The system shall mirror directional icons in RTL and provide a data-no-mirror escape hatch for non-directional icons. [Must]
FR-PUB-109 The system shall load only the active locale's font family (Inter/Poppins for EN, Noto Nastaliq Urdu for UR, Noto Naskh Arabic for SD), self-hosted, subset, woff2. [Must]
FR-PUB-110 The system shall display every user-facing date in both Gregorian and Hijri, with Gregorian as the stored source of truth. [Must]
FR-PUB-111 The system shall provide dual-input date pickers that show Gregorian and Hijri side by side. [Should]
FR-PUB-112 The system shall format numbers, dates, currency, and phone numbers through a single locale-aware formatter (Intl-based). [Must]
FR-PUB-113 Currency shall always be PKR, stored as integer paisa, formatted at presentation. [Must]
FR-PUB-114 Ticket IDs, CNICs, NTNs, and acronyms shall always render in Latin script and LTR direction, even within RTL prose. [Must]
FR-PUB-115 On a missing translation in the active locale, the system shall fall back to the English string with a visible marker. [Must]
FR-PUB-116 Silent fallback (English shown with no marker) shall not occur. [Must]
FR-PUB-117 Every public page shall emit hreflang alternate links for en, ur, sd, and x-default (pointing to EN). [Must]
FR-PUB-118 The system shall generate a per-locale sitemap (sitemap-en.xml, sitemap-ur.xml, sitemap-sd.xml) under a sitemap index. [Must]
FR-PUB-119 The system shall apply glossary-approved translations as forced constraints in the AI translation pipeline. [Must]
FR-PUB-120 The system shall refuse to publish any UR/SD content that has not passed native human review. [Must]
FR-PUB-121 The system shall track translation status (source-only, ai-draft, in-review, approved, published, stale) per locale per artifact. [Must]
FR-PUB-122 The system shall provide an on-demand "translate" affordance for user-submitted content (ticket text, messages, MoM), clearly labelled as machine translation, with the original preserved. [Should]
FR-PUB-123 The system shall render the Sindh public holiday calendar with both Gregorian and Hijri dates, consumed by the SLA engine. [Must]
FR-PUB-124 The system shall provide a translation debt dashboard reporting fallback events, stale items, and reviewer throughput. [Should]
FR-PUB-125 The CI pipeline shall fail on (a) hardcoded strings, (b) catalog key-parity gaps, (c) forbidden glossary mappings (e.g., Department → وزارت). [Must]
FR-PUB-126 The system shall set <html lang="..." dir="..."> correctly on every page. [Must]
FR-PUB-127 The visual regression suite shall run every screen story in both LTR and RTL. [Must]
FR-PUB-128 The system shall maintain at least two accredited native reviewers per locale for redundancy. [Should]
FR-PUB-129 Numeral rendering (Eastern Arabic vs Latin in UR/SD prose) shall be configurable per locale by the Super Admin. [Could]

18. Non-Functional Requirements

ID Requirement MoSCoW
NFR-PUB-101 Locale resolution shall complete in under 5 ms at the edge (cookie/URL read); no DB call on the hot path. [Must]
NFR-PUB-102 The active locale's font payload (woff2, subset) shall be under 200 KB on first paint. [Must]
NFR-PUB-103 Switching locale on a page shall not trigger a full page reload where the framework supports it (Next.js App Router native). [Should]
NFR-PUB-104 RTL and LTR layouts shall use the same component tree (no duplicated components per direction). [Must]
NFR-PUB-105 The product shall conform to WCAG 2.1 AA in all three locales, verified per release. [Must]
NFR-PUB-106 Machine translation latency (on-demand user-content translation) shall be under 3 seconds p95 for content under 2,000 characters. [Should]
NFR-PUB-107 The translation debt dashboard shall refresh at least daily. [Should]
NFR-PUB-108 Hijri conversion shall match Pakistan official Hijri dates (moon-sighting overrides) for declared public holidays. [Must]
NFR-PUB-109 All three locales shall remain continuously crawlable (no locale blocked in robots.txt). [Must]
NFR-PUB-110 Catalog key stability: no in-use translation key shall be renamed without a deprecation window. [Must]

19. User Stories

US-PUB-101 — Switch locale without losing place [Must]

As a Company Representative I want to switch the portal from English to Urdu mid-session So that I can read content in my preferred language without losing the ticket or page I was viewing.

Acceptance Criteria (Gherkin)

Scenario: Locale switch preserves location
  Given a Company Representative is viewing ticket SITP-2026-LBR-000123 in the English locale
  When they click the locale switcher and select Urdu
  Then the URL rewrites to the /ur/ prefix for the same ticket
  And the page re-renders in Urdu with right-to-left direction
  And the same ticket SITP-2026-LBR-000123 remains on screen
  And the sitp_locale cookie is set to "ur"
  And their user record's locale is persisted as "ur"

US-PUB-102 — See dates in both Gregorian and Hijri [Must]

As an Officer I want every date on a ticket to show both Gregorian and Hijri So that my official correspondence matches government convention.

Acceptance Criteria (Gherkin)

Scenario: Dual calendar display
  Given an Officer is viewing a ticket with created-at 2026-07-17 14:30 PKT
  Then the created-at timestamp shows "17 Jul 2026" (Gregorian)
  And beside or beneath it shows the corresponding Hijri date
  And both are rendered in the Officer's locale numeral format

US-PUB-103 — Translate an inbound Urdu ticket on demand [Should]

As an Officer with English locale I want to click "Translate" on a ticket filed in Urdu So that I can understand it without leaving my English session.

Acceptance Criteria (Gherkin)

Scenario: On-demand machine translation
  Given an Officer with locale "en" is viewing a ticket whose description was authored in Urdu
  When they click the "Translate" affordance
  Then the system returns an English rendering via the AI translation capability
  And the rendering is clearly labelled "Machine translation"
  And the original Urdu text is preserved as the record
  And an audit row is written recording the translation call

US-PUB-104 — Never see silent English fallback [Must]

As a Sindhi-locale user I want to know when a piece of content is showing in English because the Sindhi version is missing So that I am not confused by an unexpected language switch.

Acceptance Criteria (Gherkin)

Scenario: Visible fallback marker
  Given the Sindhi locale catalog is missing the key "tickets.newBadge.tooltip"
  When a Sindhi-locale user views the ticket list
  Then the tooltip shows the English string
  And the tooltip is rendered with the fallback marker (dotted underline or EN badge)
  And the missing key is logged to the translation debt dashboard

US-PUB-105 — Reviewer approves an AI translation draft [Must]

As a Native Urdu Reviewer I want to review the AI-generated Urdu draft of a newly authored KB article So that only correct, glossary-consistent Urdu reaches the public site.

Acceptance Criteria (Gherkin)

Scenario: Native review gate
  Given a KB article was authored in English and the AI translation pass produced an Urdu draft
  And the draft's status is "ai-draft"
  When the reviewer opens the review workbench
  Then they see the English source, the Urdu draft, and the glossary-approved terms side by side
  And they can edit the draft inline
  And on approval the status moves to "approved" and then "published"
  And their edits are saved to the AI tuning corpus

20. Test Cases

ID Covers Scenario
TC-PUB-101-01 FR-PUB-102 Visit /ur/tickets/... anonymously; assert locale resolves to ur, dir=rtl, cookie set.
TC-PUB-104-01 FR-PUB-104 Run lint over a PR that introduces a hardcoded JSX string; assert build fails.
TC-PUB-105-01 FR-PUB-105 Add key tickets.foo to en/tickets.json only; assert CI parity check fails for missing ur/sd.
TC-PUB-107-01 FR-PUB-107 Render the ticket list story in ur; assert <html dir="rtl"> and logical-property padding on the leading edge.
TC-PUB-108-01 FR-PUB-108 Render a "back" icon button in ur; assert the icon is mirrored vs en.
TC-PUB-110-01 FR-PUB-110 Render a ticket created-at in ur; assert both Gregorian and Hijri strings appear.
TC-PUB-114-01 FR-PUB-114 Render a ticket ID inside an Urdu paragraph; assert it is wrapped dir="ltr" and Latin.
TC-PUB-115-01 FR-PUB-115 Delete key x from sd/common.json; render the page in Sindhi; assert English fallback with marker.
TC-PUB-119-01 FR-PUB-119 AI-translate an EN string containing "Department"; assert output uses محڪمو (SD), never وزارت.
TC-PUB-120-01 FR-PUB-120 Attempt to publish an ai-draft UR item without review; assert publish is refused.
TC-PUB-125-01 FR-PUB-125 Submit a PR whose UR catalog renders "Department" as وزارت; assert CI forbidden-mapping check fails the build.
TC-PUB-127-01 FR-PUB-127 Run the visual regression suite for a changed tickets-page story in both ltr and rtl; assert both pass.

21. Open Questions / TBD

# Item Status
1 Numeral default in UR/SD prose: Eastern Arabic by default, or Latin? Proposal: Eastern Arabic in prose, Latin in data-dense UI, configurable. Proposal · TBD sign-off
2 Hijri conversion source: Umm al-Qura algorithm vs Pakistan Ruet-e-Hilal Committee moon-sighting overrides for declared holidays. Proposal: algorithm + override table maintained by ops. TBD
3 Whether to add en-PK / ur-PK / sd-PK region subtags in hreflang for finer SEO targeting, or stay with bare en/ur/sd. TBD
4 Number of accredited native reviewers per locale at launch (minimum 2 proposed in FR-PUB-128). TBD staffing
5 Whether the on-demand machine translation of user content should be persisted (cached) or always re-generated. TBD
6 Self-hosted font subsetting tooling (pyftsubset vs fonttools pipeline) — confirmed at build setup. TBD tooling
7 Whether citizen-submitted free text in a fourth language (e.g., Pashto, Balochi) is in scope for V1 or deferred. Deferred (V2 signal)

End of document.