tractatus/docs/plans/TRANSLATION_APPROACH.md
TheFlow 2298d36bed fix(submissions): restructure Economist package and fix article display
- Create Economist SubmissionTracking package correctly:
  * mainArticle = full blog post content
  * coverLetter = 216-word SIR— letter
  * Links to blog post via blogPostId
- Archive 'Letter to The Economist' from blog posts (it's the cover letter)
- Fix date display on article cards (use published_at)
- Target publication already displaying via blue badge

Database changes:
- Make blogPostId optional in SubmissionTracking model
- Economist package ID: 68fa85ae49d4900e7f2ecd83
- Le Monde package ID: 68fa2abd2e6acd5691932150

Next: Enhanced modal with tabs, validation, export

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-24 08:47:42 +13:00

233 lines
5.2 KiB
Markdown

# Translation Approach for Task 19: Te Reo Māori & Multilanguage Support
**Date:** October 12, 2025
**Status:** Planning - To be implemented after Task 12 (API Documentation)
**Priority:** CRITICAL (Values - Te Tiriti commitment)
---
## Translation Service: DeepL
**Decision:** Use DeepL API for translation services instead of i18next manual translations
### Deployment Architecture
**Local Development (Port 9000):**
- DeepL API integration in Node.js
- Local environment variable: `DEEPL_API_KEY`
- Translation caching in MongoDB
**Production Server (vps-93a693da.vps.ovh.net):**
- DeepL API integration deployed
- Secure environment variable configuration
- Production translation cache
---
## Implementation Plan
### 1. DeepL API Integration
```javascript
// Example integration approach
const deepl = require('deepl-node');
const translator = new deepl.Translator(process.env.DEEPL_API_KEY);
async function translateContent(text, targetLang) {
const result = await translator.translateText(text, null, targetLang);
return result.text;
}
```
### 2. Language Selector UI
- **Location:** Navigation bar (all pages)
- **Languages:** English (en), Te Reo Māori (mi)
- **Storage:** Browser localStorage + cookie
- **Behavior:** Persist selection across sessions
### 3. Translation Cache
**MongoDB Collection:** `translations`
```javascript
{
source_text: String,
source_lang: String,
target_lang: String,
translated_text: String,
verified: Boolean,
created_at: Date,
updated_at: Date
}
```
**Benefits:**
- Reduces API calls
- Faster page loads
- Cost optimization
- Human verification workflow
### 4. Priority Pages for Translation
**Phase 1 (Task 19):**
- Homepage (index.html)
- About/Values page (about.html)
- Core Framework Documentation
**Phase 2 (Future):**
- All audience paths (researcher, implementer, advocate)
- Interactive demos
- Blog posts
- API documentation
### 5. Māori Language Consultation
**Critical:** Despite using DeepL, Māori language consultation is REQUIRED
**Why:**
- Cultural appropriateness review
- Technical term accuracy
- Idiomatic expressions
- Values alignment
**Process:**
1. DeepL generates initial translation
2. Store in database as `verified: false`
3. Submit to Māori language consultant
4. Update with corrections
5. Mark as `verified: true`
### 6. Rate Limiting & Cost Management
**DeepL API Limits:**
- Free tier: 500,000 characters/month
- Pro tier: Pay per character
**Strategy:**
- Cache all translations
- Batch translation requests
- Monitor character usage
- Set monthly budget alerts
---
## Technical Implementation
### Routes
```javascript
// POST /api/translate
// Translate text to specified language
router.post('/translate', async (req, res) => {
const { text, targetLang } = req.body;
// Check cache first
const cached = await Translation.findOne({
source_text: text,
target_lang: targetLang,
verified: true
});
if (cached) {
return res.json({ translation: cached.translated_text });
}
// Call DeepL API
const translation = await translateContent(text, targetLang);
// Store in cache
await Translation.create({
source_text: text,
source_lang: 'en',
target_lang: targetLang,
translated_text: translation,
verified: false
});
res.json({ translation });
});
```
### Frontend Integration
```javascript
// Language selector component
class LanguageSelector {
constructor() {
this.currentLang = localStorage.getItem('lang') || 'en';
}
async switchLanguage(lang) {
localStorage.setItem('lang', lang);
await this.translatePage(lang);
}
async translatePage(lang) {
if (lang === 'en') {
// Reload original content
location.reload();
return;
}
// Translate all translatable elements
const elements = document.querySelectorAll('[data-translate]');
for (const el of elements) {
const originalText = el.textContent;
const translation = await this.translate(originalText, lang);
el.textContent = translation;
}
}
}
```
---
## Configuration
### Environment Variables
**Development (.env):**
```bash
DEEPL_API_KEY=your_dev_key
DEEPL_API_FREE_TIER=true
TRANSLATION_CACHE_ENABLED=true
```
**Production (remote):**
```bash
DEEPL_API_KEY=your_prod_key
DEEPL_API_FREE_TIER=false
TRANSLATION_CACHE_ENABLED=true
TRANSLATION_VERIFICATION_REQUIRED=true
```
---
## Success Criteria
- [ ] DeepL API integrated on both dev and production
- [ ] Language selector functional in navigation
- [ ] Translation caching working
- [ ] Homepage, About, Core Docs translated to Te Reo Māori
- [ ] Māori language consultant review completed
- [ ] All translations marked as verified
- [ ] User preference persists across sessions
- [ ] Performance: <500ms translation load time (cached)
---
## Notes
- **Cost Estimate:** Homepage + About + Core Docs 50,000 characters
- **DeepL Free Tier:** Sufficient for Phase 1
- **Future:** Add more languages (Samoan, Tongan, Cook Islands Māori, etc.)
- **Accessibility:** Ensure `lang` attribute updated on `<html>` tag
- **SEO:** Consider separate URLs vs. client-side switching
---
**To Be Implemented:** After Task 12 (API Documentation) completion
**Dependencies:** DeepL API account, MongoDB translations collection, Māori language consultant
**Timeline:** 5-7 days estimated