惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

月光博客
月光博客
Stack Overflow Blog
Stack Overflow Blog
L
LangChain Blog
Jina AI
Jina AI
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
雷峰网
雷峰网
T
Tailwind CSS Blog
MongoDB | Blog
MongoDB | Blog
博客园 - 【当耐特】
博客园 - 聂微东
V
Visual Studio Blog
博客园_首页
Engineering at Meta
Engineering at Meta
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
The Cloudflare Blog
人人都是产品经理
人人都是产品经理
Apple Machine Learning Research
Apple Machine Learning Research
阮一峰的网络日志
阮一峰的网络日志
Microsoft Security Blog
Microsoft Security Blog
GbyAI
GbyAI
F
Fortinet All Blogs
C
Check Point Blog
罗磊的独立博客
H
Hackread – Cybersecurity News, Data Breaches, AI and More

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
78 tarot cards x 5 languages: the content pipeline nobody...
Jakub · 2026-05-20 · via DEV Community

Last week I shipped Tarotas, a tarot reading app that supports five languages from day one. Czech, English, Polish, Slovak, German. 78 cards in each. That's 390 card objects, and each card carries a name, upright meaning, reversed meaning, a set of keywords, and a one-paragraph description. Multiply it out and you're looking at roughly 2,000 individual text fields.

I didn't translate them by hand. Obviously.

The source language problem

My first instinct was to write everything in English and translate outward. Wrong call. Tarot has deep roots in specific traditions, and the English terms aren't always the "canonical" ones across languages. The Czech name for The High Priestess is "Velekněžka," and if you translate back from English you get something slightly off.

So I wrote the Czech versions first (that's the language I think in), then generated the other four from Czech as source. This sounds backwards if you're used to EN-first localization, but it meant the source text had the most nuance and the translations could be validated against it.

AI translation with a trust boundary

I used Claude for the bulk translations. The pipeline was dead simple: feed it the Czech card object as JSON with all fields, ask for the target language, get back a JSON object with the same structure. One card at a time, not batched, because batching 78 cards in one prompt led to skipped fields and hallucinated keywords.

The prompt looked like this:

Translate this tarot card from Czech to {lang}.
Keep the JSON structure identical.
For the card name, use the standard tarot name
in {lang} tradition.
For keywords, translate meaning not words.

Enter fullscreen mode Exit fullscreen mode

That last line matters. "Nový začátek" in Czech literally means "new beginning," but the German tarot tradition might use "Aufbruch" (departure, setting out) for the same card. I wanted the AI to pick the term a German tarot reader would actually recognize.

Where the human still wins

I didn't review all 2,000 fields. That would defeat the purpose. Instead I set up three checkpoints:

  1. Card names. I manually verified every Major Arcana name (22 cards x 5 languages = 110 fields). These are the ones people actually search for and would notice if wrong.

  2. Reversed meanings spot-check. Reversed card meanings are where AI gets creative. "Stagnation" becomes "creative blockage" becomes "spiritual paralysis" if you don't catch it early. I checked 10 random Minor Arcana per language.

  3. Keyword deduplication. The AI sometimes generates near-synonyms as separate keywords. "Love" and "romance" on the same card, that kind of thing. I wrote a quick script to flag cards where two keywords had high semantic similarity.

Total human review time: about 4 hours. For 2,000 fields across 5 languages, I can live with that.

The storage side was simple. Postgres (via Supabase), one row per card-language pair:

create table cards (
  id uuid primary key,
  card_number int not null,
  arcana text not null,
  suit text,
  lang text not null,
  name text not null,
  meaning_upright text,
  meaning_reversed text,
  keywords text[],
  description text,
  unique(card_number, lang)
);

Enter fullscreen mode Exit fullscreen mode

390 rows. No joins for a card lookup: where card_number = X and lang = Y. The app reads the browser language or the user's explicit choice, passes it as a parameter, done. If I ever add language number six, it's 78 inserts and zero schema changes.

What it actually cost

The AI translation ran about $3 in API calls. 390 requests, a few hundred tokens each. The human review: 4 hours of my time spread over two evenings. The keyword dedup script: 30 minutes to write, ran in under a second.

I got quotes for professional tarot translation. $0.08 to $0.12 per word, because it's a niche. At roughly 50 words per card across all fields, that's 78 x 50 x 5 x $0.10 = about $1,950. For a product that has 37 visitors so far. Nope.

The AI route isn't flawless. I'm sure a native Polish tarot reader could find something to nitpick. But "mostly right with a clear correction path" beats "can't afford to ship multilingual at all" every single time.

Content scaling with AI is maybe 10% prompting and 90% knowing where the AI will screw up. For tarot, that's proper nouns (card names vary between traditions) and nuanced spiritual terminology (reversed meanings). For your domain, it'll be something completely different. But the pattern holds: translate structured data one object at a time, validate the high-stakes fields manually, accept "good enough" for the rest.

I shipped five languages in a week. The app is live at tarotas.com. It's early, it's small, and I still can't guarantee the German keywords are perfect. But 390 content units are out in the world instead of sitting in a "someday we'll translate" backlog forever.

Jakub, builder @ Inithouse