templates — Bilingual (EN/AR) Prompt Scaffolding

On this page

Rather than writing English prompts and bolting on a "respond in Arabic" instruction, every strategy's persona, section headers, and scaffolding text is natively authored in both English and Modern Standard Arabic (الفصحى). The module docstring states the rationale directly: this keeps reasoning quality consistent across languages, since the model is working from a prompt written for Arabic rather than a translated English one.

Table of contents


Lang

Python · 4 lines
class Lang(str, Enum):
    EN = "en"
    AR = "ar"
)

Only two supported native languages exist in this module. Every other requested language falls back to the EN templates plus a plain "Respond in <language>." note appended separately by BaseStrategy._language_line (see strategies).

resolve_lang()

Python
def resolve_lang(language: Optional[str]) -> Lang

None/empty → Lang.EN. Otherwise: Lang.AR if language.strip().lower() is in _ARABIC_ALIASES, else Lang.EN.

_ARABIC_ALIASES = {"ar", "arabic", "arab", "ar-eg", "ar-sa", "ar-ae", "ar_eg", "ar_sa", "msa", "فصحى", "عربي", "العربية", "مصري", "اللغة العربية"} — a fixed set of English and Arabic-script aliases. Regional dialect names beyond Egyptian/Saudi/UAE (e.g. "ar-ma" for Moroccan) are not in this set and will resolve to Lang.EN.

is_supported()

Python
def is_supported(language: Optional[str]) -> bool

True for empty/None, "en"/"english", or anything in _ARABIC_ALIASES; False otherwise. Not called anywhere else in the provided source — appears to be a public utility for callers who want to check support before calling build(), rather than something the library uses internally.

persona_line()

Python
def persona_line(lang: Lang, profile: UserProfile) -> str

Looks up PERSONA_LINES[lang][profile]. Falls back to the Lang.EN sub-dict if lang isn't a key (defensive; in practice lang is always EN or AR). Returns "" if profile isn't found in the sub-dict (defensive; all four UserProfile members are populated for both languages).

UserProfileEnglishArabic
TECHNICALUse precise technical language; include relevant details.استخدم لغة تقنية دقيقة، وأضف التفاصيل ذات الصلة.
ACADEMICUse formal academic language; cite evidence rigorously.استخدم لغة أكاديمية رسمية، واستشهد بالأدلة بدقة متناهية.
EXECUTIVEBe extremely concise; highlight business impact first.كن شديد الإيجاز، وأبرِز الأثر على العمل أولًا.
GENERALUse clear, accessible language; avoid unnecessary jargon.استخدم لغة واضحة وسهلة الفهم، وتجنّب المصطلحات غير الضرورية.

StrategyTemplate

Python · 7 lines
@dataclass
class StrategyTemplate:
    strategy: PromptStrategy
    intro:    Dict[Lang, str]
    extra:    Dict[Lang, List[str]] = field(default_factory=lambda: {Lang.EN: [], Lang.AR: []})
    labels:   Dict[Lang, Dict[str, str]] = field(default_factory=dict)
    blocks:   Dict[Lang, Dict[str, str]] = field(default_factory=dict)

The bilingual scaffold for one PromptStrategy. Four accessor methods, all with English fallback:

MethodSignatureFallback chain
get_intro(lang)-> strself.intro.get(lang, self.intro[Lang.EN]) — raises KeyError if Lang.EN itself is missing from intro (never happens in the seven built-in templates)
get_extra(lang)-> List[str]self.extra.get(lang, self.extra.get(Lang.EN, []))
label(lang, key, default=None)-> strlabels[lang][key] → labels[EN][key] → default → key.replace("_", " ").title()
block(lang, key, default="")-> strblocks[lang][key] → blocks[EN][key] → default

Seven built-in instances (module-private, _SIMPLE, _COT, _MULTI_HOP, _SELF_CONSISTENT, _STEP_BACK, _REACT, _LEAST_TO_MOST) — one per PromptStrategy member — are defined as module-level constants and collected into STRATEGY_TEMPLATES.

Section labels by strategy (English; Arabic equivalents exist for every one)

StrategyLabels used
Simplecontext, history, question, answer
Chain-of-Thoughtcontext, history, question, reasoning_process, final_answer
Multi-Hopcontext_documents, history, main_question, analysis, final_answer
Self-Consistentcontext, question, task, final_answer
Step-Backcontext, specific_question, final_answer
ReActavailable_info, available_tools, prior_conversation, task, thought
Least-to-Mostcontext, problem, solution

Each strategy's _build_user in strategies.md uses exactly these labels via tpl.label(lang, key).

STRATEGY_TEMPLATES / get_strategy_template()

Python · 4 lines
STRATEGY_TEMPLATES: Dict[PromptStrategy, StrategyTemplate] = { ... }  # all 7 members

def get_strategy_template(strategy: PromptStrategy) -> StrategyTemplate:
    return STRATEGY_TEMPLATES.get(strategy, _SIMPLE)

Never raises; unregistered strategies (not reachable in practice, since all 7 enum members are registered) silently fall back to the Simple template.

guardrail_text()

Python
def guardrail_text(name: str, lang: Lang, fallback: str = "") -> str

Looks up GUARDRAIL_TEXT[name][lang], falling back to GUARDRAIL_TEXT[name][Lang.EN], falling back to fallback if name isn't in the dict at all. GUARDRAIL_TEXT has a natively-authored English and Arabic entry for all 12 GuardrailLibrary names: grounding, uncertainty, no_fabrication, cite_sources, stay_on_topic, no_personal_opinions, safe_output, pii_protection, concise, no_markdown_leakage, show_reasoning, self_check. In practice, fallback (the guardrail's own .instruction from guardrails.py) is only ever used if a custom guardrail added via extra_guardrails has a name that isn't one of these 12 built-ins.

format_instruction_text()

Python
def format_instruction_text(fmt: OutputFormat, lang: Lang) -> Optional[str]

Looks up FORMAT_INSTRUCTIONS_TEXT[fmt][lang], English fallback, or None if fmt has no entry at all. Entries exist (bilingually) for JSON, BULLET_LIST, MARKDOWN, CITATION, STRUCTURED — not for TEXT, matching the same gap noted in guardrails.md.

guardrail_header() / output_format_header()

Python · 2 lines
GUARDRAIL_HEADER = {Lang.EN: "## Instructions & Constraints", Lang.AR: "## التعليمات والقيود"}
OUTPUT_FORMAT_HEADER = {Lang.EN: "\n## Output Format", Lang.AR: "\n## تنسيق الإخراج"}

Simple dict-lookup functions with Lang.EN fallback, used by GuardrailEngine._render.

Examples

1. Basic — resolve a language code

Python · 5 lines
from zerda.prompt.templates import resolve_lang, Lang

assert resolve_lang("AR") == Lang.AR
assert resolve_lang("Arabic") == Lang.AR
assert resolve_lang("fr") == Lang.EN   # no native French template

2. Intermediate — get a strategy template

Python · 5 lines
from zerda.prompt.templates import get_strategy_template
from zerda.prompt.types import PromptStrategy

tpl = get_strategy_template(PromptStrategy.CHAIN_OF_THOUGHT)
print(tpl.get_intro(Lang.AR))

3. Advanced — localized guardrail text with fallback

Python · 4 lines
from zerda.prompt.templates import guardrail_text, Lang

text = guardrail_text("grounding", Lang.AR)
text_unknown = guardrail_text("my_custom_guardrail", Lang.EN, fallback="Custom instruction text.")

4. Error handling — there's little to fail; everything degrades to English

Python
tpl = get_strategy_template(None)  # falls back to _SIMPLE, no exception

5. Production — building a fully bilingual system prompt manually

Python · 6 lines
from zerda.prompt.templates import resolve_lang, get_strategy_template, persona_line
from zerda.prompt.types import PromptStrategy, UserProfile

lang = resolve_lang("ar")
tpl = get_strategy_template(PromptStrategy.SIMPLE)
system = "\n\n".join(filter(None, [tpl.get_intro(lang), persona_line(lang, UserProfile.ACADEMIC)]))
  • strategies — the primary consumer of StrategyTemplate
  • guardrails — consumer of guardrail_text, format_instruction_text, the two header functions
  • types — PromptStrategy, OutputFormat, UserProfile

Related pages