Translation Adapter (Code Level)
C4 Level 4 detail of the PSI translation system. Shows the adapter interface, factory pattern, per-silo configuration, and content translation flow.
Adapter Class Hierarchy
classDiagram
class TranslationAdapter {
<<interface>>
+translate(text: string, fromLang: string, toLang: string) Promise~string~
}
class LLMTranslationAdapter {
-llmAdapter: LLMAdapter
+translate(text, fromLang, toLang)
}
class DeepLAdapter {
-apiKey: string
-apiUrl: string
+translate(text, fromLang, toLang)
}
class TextShuttleAdapter {
-apiKey: string
-apiUrl: string
+translate(text, fromLang, toLang)
}
class SRGSSRAdapter {
-apiUrl: string
-apiKey: string
+translate(text, fromLang, toLang)
}
TranslationAdapter <|.. LLMTranslationAdapter : TEXT_TRANSLATION_PROVIDER=llm (default)
TranslationAdapter <|.. DeepLAdapter : TEXT_TRANSLATION_PROVIDER=deepl
TranslationAdapter <|.. TextShuttleAdapter : TEXT_TRANSLATION_PROVIDER=textshuttle
TranslationAdapter <|.. SRGSSRAdapter : TEXT_TRANSLATION_PROVIDER=srgssr-crknews-translation-api
LLMTranslationAdapter --> LLMAdapter : uses for GPT translation
note for LLMTranslationAdapter "Uses OpenAI GPT with server/prompts/translate.txt.\nDefault adapter. No extra API key needed\n(uses existing OPENAI_KEY)."
note for DeepLAdapter "DeepL API for high-quality machine translation.\nRequires DEEPL_API_KEY."
note for TextShuttleAdapter "TextShuttle API for specialized translation.\nRequires TEXT_SHUTTLE_API_KEY."
note for SRGSSRAdapter "SRG SSR enterprise translation API.\nUsed by the SRG silo for Swiss multilingual content." Factory Pattern
graph TD
A[Server Initialization] --> B[Read TEXT_TRANSLATION_PROVIDER env var]
B --> C{Provider value?}
C -->|"llm" or undefined| D[createLLMTranslationAdapter<br/>Uses existing LLM Adapter]
C -->|"deepl"| E[createDeepLAdapter<br/>Requires DEEPL_API_KEY]
C -->|"textshuttle"| F[createTextShuttleAdapter<br/>Requires TEXT_SHUTTLE_API_KEY]
C -->|"srgssr-crknews-translation-api"| G[createSRGSSRAdapter<br/>Requires SRG_TRANSLATION_API_URL]
D --> H[TranslationAdapter instance]
E --> H
F --> H
G --> H
H --> I[Injected into contentTranslation module] Content Translation Flow
sequenceDiagram
participant User
participant Frontend as PSI Frontend
participant Backend as PSI Backend (Hono)
participant Module as contentTranslation Module
participant Store as ServerStore
participant Adapter as Translation Adapter
participant Service as Translation Service
User->>Frontend: Post comment in German
Frontend->>Backend: POST /api/contentTranslation/translateContent
Backend->>Module: translateContent(store, params)
Module->>Store: Check silo config: multiLanguage settings
Store-->>Module: {enabled: true, languages: ["de", "fr", "it", "rm"]}
loop For each target language != source
Module->>Adapter: translate(commentText, "de", "fr")
Adapter->>Service: API call (DeepL/TextShuttle/SRG SSR/OpenAI)
Service-->>Adapter: Translated text
Adapter-->>Module: "French translation"
Module->>Store: setModuleData(PUBLIC, {translation: "fr"}, translatedText)
end
Module-->>Backend: {translations: {fr: "...", it: "...", rm: "..."}}
Backend-->>Frontend: Translation results
Frontend->>User: Display comment with language toggle Per-Silo Configuration
Different silos use different translation providers and language sets:
graph LR
subgraph "Silo Configuration (psi.config.ts)"
SRG["SRG Silo<br/>multiLanguage: true<br/>languages: de, fr, it, rm<br/>provider: srgssr-crknews-translation-api"]
Global["Global Silo<br/>multiLanguage: false<br/>Single language: en"]
ZDF["ZDF Silo<br/>multiLanguage: false<br/>Single language: de"]
RC["RC Silo<br/>multiLanguage: false<br/>Single language: fr-CA"]
end
subgraph "Server Config (env vars)"
LLM["TEXT_TRANSLATION_PROVIDER=llm<br/>Default for most silos"]
SRGAPI["TEXT_TRANSLATION_PROVIDER=<br/>srgssr-crknews-translation-api<br/>For SRG silo"]
end
SRG --> SRGAPI
Global --> LLM
ZDF --> LLM
RC --> LLM Supported Languages
| Language | Code | Silos |
|---|---|---|
| English | en | Global, CBC |
| French (Standard) | fr | RTBF |
| French (Canadian) | fr-CA | Radio-Canada |
| German | de | ZDF, SRG |
| Italian | it | SRG |
| Dutch | nl | KRO-NCRV/NPO |
| Romansh | rm | SRG |
LLM Translation Prompt
The LLM adapter uses server/prompts/translate.txt which instructs GPT to:
- Translate the provided text to the target language
- Preserve the tone and register of the original
- Handle user-generated content idioms and colloquialisms
- Return only the translated text (no explanations)
Further Reading
- Adapter Pattern -- all adapter interfaces
- Text Translation Adapter (psi-product) -- detailed implementation guide
- Localization (psi-product) -- UI string translation (separate from content translation)