Localizing Images with Embedded Text

Within Asset Duplication & CDN Sync, this guide deals with the assets that cause most localization work: images with text inside them. Banners with headlines, infographics, screenshots of interfaces and diagrams with labels all need a version per language, and each version must be created, stored, tracked and kept in step with the original. The guide covers three strategies, from avoiding baked-in text altogether to generating variants automatically, and how to track which locales are missing.

Text in images is a problem beyond workload. Search engines and screen readers cannot read it unless alt text repeats it, it does not reflow on small screens, and it cannot be updated without a designer. For a single-language site these are minor costs. With ten locales, every banner becomes ten files, every typo fix ten exports, and every new market a backlog of images nobody has time to recreate.

Three strategies, from best to last resortThe preferred strategy is live text over a text-free image, rendered by the page from localized CMS fields; next is generating image variants from a template with localized text; the last resort is manually produced variants uploaded per locale.Live text overlayno variants neededtext-free imageHTML text from CMSTemplate generationvariants automatedtemplate + localized textrendered at build or edgeManual variantslast resortdesigner exportsuploaded per locale
Move each image kind as high up this stack as its design allows.

The Problem

A consumer electronics brand ran monthly promotions in 11 languages. Each promotion had four banner sizes with the headline and price baked into the image, so a promotion meant 44 exports from the design team, uploaded by hand into localized asset fields. Missing variants fell back to English, so Polish visitors regularly saw English banners on Polish pages. A price correction in the middle of a promotion required 44 new exports and took two days, during which the old price stayed visible.

How to Localize Text in Images

Live text overlays. Separate the text from the image. The designer delivers a text-free background, and the page renders the headline, price and call to action as HTML on top of it, from localized CMS fields. Text is searchable, accessible, responsive and editable by editors in every locale immediately. This covers most banners and hero images.

Template generation. Some images must be images: social sharing cards, email banners, app store graphics, anything consumed outside the page. Generate them from a template and localized text at build time or at the edge, for example with an SVG template rendered to PNG. Editors change the text in the CMS; the variant regenerates automatically.

Manual variants. Screenshots of localized interfaces, infographics with complex layouts and photos of printed material cannot be generated. Keep them as manual variants in localized asset fields, and track their completeness so missing locales are visible.

Generating a social card from a templateA publish of a localized entry triggers the generator, which fills the SVG template with the entry's localized title and price, renders it to PNG, stores it by content hash and records it in the manifest for that locale.Entry publishedtitle, price (pl)SVG templatedesigner-ownedGeneratorfill + render PNGObject storeby hashManifestcard / pl
The designer owns the template; editors own the words; the pipeline produces every locale.

Implementation

For live overlays, model the banner as a block with a text-free image and localized text fields, and render the text in HTML. Contrast and position are controlled by fields the designer sets once per banner.

TSX
// components/blocks/promo-banner.tsx
interface PromoBanner {
  background: { url: string; width: number; height: number; alt: string };  // text-free image, decorative alt
  headline: string;                                                           // localized field
  priceLabel?: string;                                                        // localized field
  cta: { label: string; href: string };                                       // localized field
  textPosition: "left" | "center" | "right";
  textTone: "light" | "dark";
}

export function PromoBannerView(b: PromoBanner) {
  return (
    <section className={`promo promo--${b.textPosition} promo--${b.textTone}`}>
      <img src={b.background.url} width={b.background.width} height={b.background.height} alt={b.background.alt} />
      <div className="promo__text">
        <h2>{b.headline}</h2>
        {b.priceLabel && <p className="promo__price">{b.priceLabel}</p>}
        <a className="promo__cta" href={b.cta.href}>{b.cta.label}</a>
      </div>
    </section>
  );
}

For generated images, a small renderer fills an SVG template and converts it to PNG. The example uses Satori-style rendering through @vercel/og, which accepts JSX and fonts; any SVG-to-PNG renderer works.

TSX
// app/og/[locale]/[slug]/route.tsx
import { ImageResponse } from "next/og";
import { getProduct } from "@/lib/cms/product";

export async function GET(_: Request, { params }: { params: Promise<{ locale: string; slug: string }> }) {
  const { locale, slug } = await params;
  const product = await getProduct(slug, locale);
  if (!product) return new Response("not found", { status: 404 });
  const font = await fetch(new URL("../../../../assets/Inter-SemiBold.ttf", import.meta.url)).then((r) => r.arrayBuffer());

  return new ImageResponse(
    (
      <div style={{ display: "flex", flexDirection: "column", justifyContent: "flex-end", width: "100%", height: "100%", padding: 64, background: "#0b1f3a", color: "#fff", fontFamily: "Inter" }}>
        <div style={{ fontSize: 64, lineHeight: 1.1 }}>{product.title}</div>
        <div style={{ fontSize: 40, marginTop: 24, color: "#ffb454" }}>{product.priceLabel}</div>
      </div>
    ),
    { width: 1200, height: 630, fonts: [{ name: "Inter", data: font, weight: 600 }], headers: { "Cache-Control": "public, s-maxage=86400" } },
  );
}

The route is cached at the CDN per locale and slug, and revalidated or purged when the product entry changes. Use fonts that cover every script your locales need; a Latin-only font renders Japanese or Arabic as empty boxes.

Tracking manual variants

For images that stay manual, report completeness per locale. A scheduled job lists assets with localized fields, checks which locales have their own variant and which fall back, and publishes a report for the localization team. Assets flagged as “text in image” in the CMS and falling back in a locale are the ones to prioritize, because readers in that locale see a foreign language.

Moving text out of images is also the single biggest accessibility improvement most localized sites can make. Live text can be resized, read by screen readers, translated by browser tools and indexed by search engines in each market. For images that must keep text, write alt text that contains the same words in the same locale, and make it a required localized field when the asset is flagged as containing text. Generated social cards should set their alt text from the same fields that fill the template, so the two never disagree. A quick audit query, assets flagged as text-in-image whose alt text is empty in any locale, gives the localization team a concrete list to work through.

Configuration Reference

Image kind Strategy Notes
Hero and promo banners live text overlay Text-free background, localized fields.
Social cards, email banners template generation Cached per locale, regenerated on publish.
Screenshots of the product UI manual variants Capture per locale; track completeness.
Infographics manual or rebuilt as HTML/SVG HTML versions are accessible and translatable.
Photos without text no variant Share one asset across locales.

Gotchas & Edge Cases

  • Text expansion. German and Finnish headlines are often 30 percent longer than English ones. Test overlays and templates with the longest locale, and set maximum lengths in CMS validation.
  • Right-to-left languages. Overlays and templates must mirror layout for Arabic and Hebrew. Set dir from the locale and test at least one right-to-left locale.
  • Fonts and scripts. Template renderers need fonts for every script used. Missing glyphs fail silently as boxes.
  • Alt text for generated images. Generated images still need localized alt text, usually the same text they display.

Worked Example

The electronics brand converted its promotion banners to text-free backgrounds with localized headline, price and call-to-action fields, and generated social and email banners from two templates. A promotion now required four background images, one per size, instead of 44 exports. The next price correction was made by editors in the CMS and was live in all 11 markets within minutes. Manual variants remained only for product screenshots, and the completeness report showed the localization team which of those were missing in each market.

Design exports per monthly promotionThe number of image files the design team produced per monthly promotion with baked-in text for 11 languages and four sizes, compared with text-free backgrounds and generated banners.Baked-in text44 exported filesOverlays + templates4 exported files
Text moved into the CMS, and design effort moved into templates that are reused every month.

Working with Designers and Translators

The technical change is small compared with the change in workflow. Designers must deliver backgrounds with safe areas for text rather than finished images, and templates rather than one-off exports. Brief them on text expansion and right-to-left layouts, and give them a preview page that renders their background with the longest real headline in each locale, so they can check the composition before handing over. Translators gain from the change: text in CMS fields goes through the normal translation workflow and translation memory, instead of arriving as screenshots to transcribe. Agree on maximum lengths per field with both groups, and enforce them in the CMS, because an overflowing headline is the most common failure of live overlays and the easiest to prevent.

Rollout Checklist

  • Classify image kinds by strategy: overlay, template or manual.
  • Convert banners to text-free backgrounds with localized text fields.
  • Build templates for images consumed outside the page, cached per locale.
  • Choose fonts that cover every script your locales use.
  • Report missing manual variants per locale, prioritizing images with text.
  • Test with the longest locale and a right-to-left locale.

Frequently Asked Questions

Is live text worse for design quality?

Not with good templates. Web typography handles most banner designs, and designers keep control through fonts, positions and tones set in the block.

Can machine translation fill missing image text?

For generated images, yes, as a draft for review. For manual variants, it helps translators but someone still has to recreate the image.

How do we handle legal text in images?

Avoid it. Legal notices must be readable and accessible, so render them as HTML, localized and reviewed like any other legal text.

What about video with burned-in subtitles?

Use separate subtitle tracks per locale instead, delivered as WebVTT files alongside one video and managed as localized fields in the CMS. Burned-in subtitles have the same problems as text in images, multiplied by file size, storage and encoding time.

Do generated images slow down pages?

No. They are generated once per locale and version, then cached at the CDN like any other image.