Multi-Language Content Generation
[To Build] · All writer agents ·
languagefield on Activity
Adds a language field to content activities so all writer agents can produce output in the tenant’s chosen language. Supports 7 languages in v1, with language-aware readability scoring and right-to-left layout support for Arabic.
Related: Blog Writer · Social Post Writer · Email Writer · Content Optimizer · Content Toolkit Overview
Overview
| Function | Generate content in 7 languages across all writer agents |
| Type | Platform Enhancement — All Writer Agents |
| Status | To Build |
| Priority | P3 — Growth |
| Languages | English · Spanish · French · German · Arabic · Hindi · Portuguese |
| Credits | No credit change — same cost per deliverable regardless of language |
| Plan | Starter: English only · Professional: all 7 languages |
Why This Is Needed
Most Leadmetrics tenants operate in non-English markets — particularly the Middle East (AED region) and India (INR region). A content platform that only produces English content has limited value for these tenants. Adding multi-language support directly expands the addressable market for the Professional plan without requiring new agent infrastructure.
Supported Languages — v1
| Language | Code | Region most relevant | RTL |
|---|---|---|---|
| English | en | All | No |
| Spanish | es | Latin America, Spain | No |
| French | fr | France, Canada, Africa | No |
| German | de | DACH | No |
| Arabic | ar | Middle East (AED region) | Yes |
| Hindi | hi | India (INR region) | No |
| Portuguese | pt | Brazil, Portugal | No |
Agents Affected
| Agent | Change Required |
|---|---|
blog-writer | Accept language in input; append language instruction to system prompt |
social-post-writer | Accept language; platform-specific emoji and hashtag norms vary per language |
email-writer | Accept language; subject line character limits are the same across languages |
gbp-post-writer | Accept language |
keyword-researcher | Accept language + locale; seed keywords may be non-English; output cluster in same language |
content-brief-writer | Accept language; brief headings and rationale in chosen language |
topic-researcher | Accept language; topic titles in chosen language |
research-note-writer | Accept language; notes in chosen language, sources may be in that language too |
Agents not affected in v1: strategy-writer, deliverable-planner, activity-planner, report-writer — these are internal operational documents that remain in English.
How Language Is Applied
Prompt Injection Pattern
No separate system prompts per language. Instead, a language instruction block is appended to the existing system prompt at runtime:
// In the worker, after loading the system prompt from DB:
if (input.language && input.language !== 'en') {
const languageBlock = buildLanguageInstruction(input.language);
systemPrompt = `${agentConfig.systemPrompt}\n\n${languageBlock}`;
}function buildLanguageInstruction(language: SupportedLanguage): string {
const languageNames: Record<SupportedLanguage, string> = {
es: 'Spanish',
fr: 'French',
de: 'German',
ar: 'Arabic',
hi: 'Hindi',
pt: 'Portuguese (Brazilian)',
};
return [
`## Language Requirement`,
``,
`Write ALL output in ${languageNames[language]}.`,
`- Headings, body text, meta description, and slug must all be in ${languageNames[language]}`,
`- Do not mix languages within the output`,
`- Use vocabulary and phrasing natural to a native ${languageNames[language]} speaker`,
`- Maintain the same structure and quality standards specified above`,
].join('\n');
}Keyword Research in Non-English
The keyword-researcher agent accepts seed keywords in any language. When language !== 'en':
- The agent is instructed to output the full keyword cluster in the specified language
- Volume and difficulty estimates are noted as approximate (most keyword data skews toward English)
- The agent supplements with localized variants — e.g. a Hindi seed keyword will return Hindi LSI terms
Note: SEMrush and DataForSEO both support non-English keyword data for most markets. If the tool integration layer supports locale-specific queries, volume/difficulty data will be accurate. Otherwise, the agent returns qualitative estimates flagged with
"volume": null, "difficultyNote": "estimated".
Language-Aware Readability Scoring
The Flesch-Kincaid formula is calibrated for English. Different target thresholds apply per language group in the Content Optimizer:
| Language | Readability target | Notes |
|---|---|---|
| English | Grade 8–10 (Flesch 60–70) | Standard |
| Spanish | Grade 9–11 | Spanish sentence structure allows longer sentences naturally |
| French | Grade 9–11 | Similar to Spanish |
| German | Grade 8–10 | German compound words inflate word-per-sentence counts; parser must handle compounds |
| Arabic | Syllable-based scoring not reliable | Switch to paragraph length + sentence count only; skip Flesch |
| Hindi | Skip Flesch; use sentence length + paragraph density only | Devanagari character count ≠ English word count |
| Portuguese | Grade 8–10 | Closest to English calibration |
Arabic RTL Support
Arabic is the only RTL language in v1 scope. Required UI changes:
- Blog editor:
dir="rtl"on the content editable area when language is Arabic - Score panel sidebar: layout flips to left side in RTL mode
- Brief export public view: RTL layout for Arabic briefs
- Social post preview cards: RTL text alignment
- Dashboard list views: text direction adapts per post’s language field
Activity Model Change
Add to Activity input metadata (already a Json field on the model — no migration needed for the field itself, but the type definition in packages/queue/src/types.ts updates):
// In ActivityJobData or equivalent
language?: SupportedLanguage;
type SupportedLanguage = 'en' | 'es' | 'fr' | 'de' | 'ar' | 'hi' | 'pt';The language field is inherited by child activities (social posts, emails) spawned from a blog activity, unless overridden.
Plan Gating
| Language | Plan required |
|---|---|
English (en) | Starter+ |
| All other languages | Professional+ |
The API validates the tenant’s plan before processing a non-English activity. If a Starter tenant submits a job with language: 'es', the API returns 403 with { error: "Multi-language generation requires the Professional plan" }.
Key Design Decisions
| Decision | Choice | Rationale |
|---|---|---|
| Language instruction appended, not separate prompt | Single system prompt with runtime language block | Avoids maintaining 7 versions of every system prompt; language is an output constraint, not a domain change |
| English-only for operational agents | strategy-writer, report-writer etc. stay English | These are internal documents used by DMs, not client-facing content |
| Approximate keyword data in non-English | Flag with difficultyNote rather than block | Better to surface approximate data than refuse; DM can verify manually |
| Inherit language from parent activity | Child activities (social, email) inherit parent language | Repurposed social posts should match the language of the source blog |
Implementation Phases
Phase 1 — Blog + Social (English-adjacent languages)
- Add
SupportedLanguagetype topackages/common/src/types.ts - Add
languagefield to all writer agent input types - Implement
buildLanguageInstruction()utility inpackages/agents/src/utils/ - Update
blog-writer.worker.tsto append language block whenlanguage !== 'en' - Update
social-post-writer.worker.tssimilarly - Language selector in blog + social activity creation forms (Starter hides non-English options)
- Test with Spanish + French (closest to English in prompt terms)
Phase 2 — Remaining Agents + Languages
- Update
keyword-researcher,content-brief-writer,email-writer,gbp-post-writer - Add Arabic + Hindi support; implement language-aware readability thresholds in Content Optimizer
- RTL UI changes for Arabic in blog editor and brief export
Phase 3 — Plan Gating
- Language plan validation in API middleware
- Dashboard language selector: non-English options locked with upgrade prompt for Starter tenants