Back to Blog

How I translate this blog with AI

2025-08-217 min read

I am a native Spanish speaker. I live in the United States, so I use English every day. I write my posts in English to practice and to reach more people.

Google Analytics showed me something important. More than half of my visitors are from countries where English is not the main language. That told me I was leaving value on the table. So I decided to translate the blog with AI.

What I focus on

  • Clarity: I keep the meaning clear over literal word for word.
  • Structure preserved: I do not let translations change HTML, code, or URLs.
  • Stable URLs: Each language has a fixed slug so links do not break.
  • Speed: One command translates everything.

My setup

  • Content format: Each post is a JSON file with title, date, excerpt, content, readTime, tags, categories, translatedSlugs, and slug.
  • Framework: Next.js and next-intl for locale aware routing.
  • Model: I call Google's Gemini API from scripts/translate-es-gemini.ts. It uses REST by default and has a fallback model. The prompt is strict: translate values only, do not touch HTML or URLs.
  • One command: scripts/translate-all-languages.ts runs translations for all locales, syncs slug mappings, and validates completeness.
  • Language switcher: It uses translatedSlugs to send readers to the right URL for each language.

My workflow

  1. I write the post in English as app/[locale]/blog/posts/<slug>/index.json. The content field is HTML. Code blocks are fenced.
  2. I translate with one command. The model translates title, excerpt, content, and readTime. Meta like date, tags, and categories stay the same.
  3. I keep slugs in sync with a translatedSlugs map in every file, English and translations.
  4. I validate that each language exists and the slug map is complete.

Why AI works for me

  • Follows instructions: The prompt protects HTML, code, and links.
  • Fast and good: A fast model with an automatic fallback.
  • Consistent tone: Low temperature keeps the style steady across languages.

Safety rails

  • HTML safe translation: I only send the values of JSON keys, not tags or attributes.
  • Slug discipline: translatedSlugs holds the slug for en, es, fr, de, ru, nl, it, and zh.
  • Validation: A command checks that each language file exists and that the slug map is complete.
  • Polite to the API: I add a small delay between calls.

Translations and SEO

Hreflang tells search engines which language page to show. It helps avoid duplicate content and sends the right version to readers. My sitemap lists every language and an x-default version so crawlers can find each one.

  • Help readers: People trust content in their language. They stay longer and share more.
  • URLs matter: A translated slug can include the words people search for in that language.
  • One page per language: Link language versions with hreflang to avoid duplicates.
  • Sitemaps: Include all locales so search engines can find them.
  • Stability: Translate slugs but keep them stable. Changing URLs often can hurt.

The commands I run

# Translate one post to all languages
npm run translate-all translate my-new-post

# Validate that all language files and slug maps exist
npm run translate-all validate my-new-post

# Re run and overwrite translations after editing English
npm run translate-all translate my-new-post --force

That is it. One to translate, one to validate. The switcher works because each JSON file lists the per language slug.

Tips if you try this

  • Write simply. Short sentences translate well.
  • Fence code blocks and wrap inline code in <code>.
  • Avoid wordplay if you will not review the target text.
  • Use semantic HTML. Headings and lists help readers and models.

FAQ

Do I edit translations?

Sometimes, especially titles and intros. I want a fast starting point, then I polish where it matters.

Privacy?

Content goes to the Gemini API. I do not send secrets. API keys live in .env.local (GOOGLE_API_KEY or GEMINI_API_KEY).

Models?

I use a fast Gemini model and fall back automatically if it is unavailable. You can override with GEMINI_MODEL.

Takeaway

AI does not replace your voice. It removes the busywork. Keep your source clean, automate the repeatable parts, validate, and ship.