How I Built a Multilingual Developer News Hub in a Weekend
I built a news aggregator that automatically translates article summaries to 5 languages the moment they're published. Here's how with RSS feeds, Claude AI, and a translation API.
Key takeaway
I built a news aggregator that automatically translates article summaries to 5 languages the moment they're published. Here's how with RSS feeds, Claude AI, and a translation API.
I built a news aggregator that automatically translates article summaries to 5 languages the moment they're published. Here's how I did it with RSS feeds, Claude AI, and my own translation API.
The Problem
I wanted a developer news feed on shipi18n.com - curated content about React, Next.js, AI, and i18n. But our users speak different languages. Building separate feeds for each language? That's a maintenance nightmare.
What if every article was automatically available in Spanish, French, German, Japanese, and Chinese?
The Architecture
RSS Feeds → Superfeedr Webhook → Lambda → AI Summary → Translation API → DynamoDB
↓
React Frontend (i18next)
Three key components:
- Feed aggregation - Superfeedr pushes new articles via webhook
- AI summarization - Claude generates concise summaries
- Auto-translation - Every summary gets translated instantly
Step 1: Setting Up RSS Aggregation
Instead of polling dozens of feeds, I use Superfeedr - they monitor RSS feeds and POST new items to my webhook.
// Lambda webhook handler
export async function handleSuperfeedrWebhook(req, res) {
const payload = JSON.parse(req.body);
for (const item of payload.items) {
// Store article
const result = await storeArticle(item, feedUrl);
// Translate immediately
if (result.created) {
await queueTranslation(result.articleId, result.article);
}
}
}
Feeds I'm aggregating:
- Frontend: Smashing Magazine, CSS-Tricks, Vercel Blog
- AI: OpenAI, Anthropic, Hugging Face
- i18n: W3C Internationalization
- SaaS: Indie Hackers, Stripe
Step 2: AI-Generated Summaries
Most RSS feeds have terrible summaries - often just the first paragraph with HTML junk. Claude Haiku fixes that:
async function generateAISummary(article) {
const response = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: {
'x-api-key': process.env.ANTHROPIC_API_KEY,
'anthropic-version': '2023-06-01',
},
body: JSON.stringify({
model: 'claude-3-haiku-20240307',
max_tokens: 150,
messages: [{
role: 'user',
content: `Write a 1-2 sentence summary of this article for developers.
Be concise and informative.
Title: "${article.title}"
URL: ${article.url}`
}]
})
});
const data = await response.json();
return data.content[0].text;
}
Haiku is perfect for this - fast, cheap ($0.25/M input tokens), and the summaries are actually good.
Step 3: The Translation Magic
Here's where it gets seamless. I built Shipi18n specifically for this use case - translating strings programmatically without managing translation files.
async function queueTranslation(articleId, article) {
const targetLangs = ['es', 'fr', 'de', 'ja', 'zh'];
const translations = {};
for (const lang of targetLangs) {
// Translate title
const titleResult = await translateText(article.title, 'en', lang);
// Translate summary
const summaryResult = await translateText(article.summary, 'en', lang);
translations[lang] = {
title: titleResult.translatedText,
summary: summaryResult.translatedText,
};
}
await updateArticleTranslations(articleId, translations);
}
The translateText function calls the translation engine directly:
import { translateJSON } from '@shipi18n/core'
const { result } = await translateJSON({
content: { text },
from: 'en',
to: targetLang,
provider: 'anthropic', // uses ANTHROPIC_API_KEY from the environment
})
const translated = result.text
One function call, no service in between. The Lambda holds the LLM key and talks to the provider directly.
Step 4: Frontend with i18next
The React frontend uses i18next for UI translations, and the article translations come from the API:
const { i18n } = useTranslation();
const currentLang = i18n.language?.split('-')[0] || 'en';
// Get translated content based on user's language
const getTranslatedContent = (article) => {
if (currentLang === 'en' || !article.translations?.[currentLang]) {
return { title: article.title, summary: article.summary };
}
return {
title: article.translations[currentLang]?.title || article.title,
summary: article.translations[currentLang]?.summary || article.summary,
};
};
When a Japanese user visits, they see:
React 19's new compiler dramatically improves performance
Reactチームが新しいコンパイラを発表。手動のメモ化なしで...
When a Spanish user visits:
El nuevo compilador de React 19 mejora drásticamente el rendimiento
El equipo de React anunció un nuevo compilador que...
Same article, automatic localization.
The Result
What I got:
- News hub with 5 categories (i18n, Frontend, AI, SaaS, Creative)
- Every article translated to 5 languages instantly
- Language switcher that respects user's browser locale
- Globe icon to preview all translations
Cost breakdown:
- Superfeedr: ~$5/month for 30 feeds
- Claude Haiku: ~$2/month for summaries
- Shipi18n: free and open source; I only pay Anthropic for the tokens, and incremental mode means repeat runs cost nothing
Time to build: One weekend
Key Takeaways
-
Don't poll RSS feeds - Use a service like Superfeedr that pushes updates
-
AI summaries > raw excerpts - Claude Haiku is cheap enough to run on every article
-
Translate at ingest, not render - Doing it server-side means instant page loads
-
Cache translations - Shipi18n's 90-day cache means I only pay once per string
Next Steps
Update (August 2026): the news hub itself has been retired — it ran on the hosted backend we shut down when Shipi18n went fully open source. The architecture below still stands on its own, and you can see the same translation pipeline at work on this site: use the language switcher in the top navigation and watch every page switch between English, Spanish, Japanese, Arabic and seven more, all translated by the CLI described here.
Want to add automatic translations to your own project?
- Get started with Shipi18n — open source, Apache-2.0, bring your own LLM key
- Check out the CLI integration for translating and checking JSON files
- Use
@shipi18n/coreprogrammatically in Node.js
Ship your app in every language.
Does your CI check your translations?
One command, no account, no API key — the structural check runs anywhere. Apache-2.0, bring your own LLM for the semantic pass.
Star on GitHub →