The Feedance AI features is rolling out.
Check it out!

Score Your Feed-Driven Creative Templates for Turkish and Arabic Text Before They Ship

Google allows a product title of up to 150 characters, and shoppers usually see only the first 70 or fewer (Merchant Center Help: title). A creative template that pulls that title, a badge word and a price from a feed row has to survive every length and every script in the catalog. Most templates are signed off on three English rows. They then ship to Istanbul, Riyadh and Dubai, where "indirim" turns into the wrong word and punctuation in an Arabic title lands on the wrong side.

This guide is for performance and creative teams running feed-driven image, video or HTML5 ads in Turkish or Arabic. It gives you an eight-check scoring rubric, a worked example with real string behavior, and thresholds for when a template is safe to ship.

Why feed-driven text breaks in Turkish and Arabic

A designer controls the text in a hand-built ad. A template does not, because the text comes from a row. Three failure families cover almost everything we see.

  • Casing. Turkish has two letters i: dotted and dotless, with pairs i/İ and ı/I (MDN, text-transform). A generic uppercase function maps i to I, which is a different letter.
  • Direction. Arabic runs right to left, but feeds mix in Latin brand names, model numbers, prices and punctuation. The Unicode bidirectional algorithm decides where each run lands, and neutral characters such as spaces and punctuation take the direction of surrounding text only when both neighbors agree (Unicode UAX #9, rule N1).
  • Fit. The text must fit its box after substitution. A box sized on one sample row fails on the longest one.

The rubric below turns those three families into checks you can score on a sample of your own feed.

The scoring rubric: eight checks, 16 points

Score each check 0, 1 or 2 against a sample of at least 50 rows per language, including the longest titles, the shortest titles and every row with mixed scripts. This is our own rubric, not an industry standard.

#Check2 points1 point0 points
1Language tagsEvery text node carries lang and directionPage-level tag onlyNo tags
2Locale-aware casingTurkish rules applied on every case changeApplied to some fieldsDefault casing
3Bidi isolationEach dynamic field isolatedIsolated only when a Latin run is detectedNo isolation
4Text shapingArabic letters join correctly in every output formatCorrect in some formatsDisconnected letters seen
5Fit on worst-case rowsTested on longest 5% of rows, with rules for overflowTested on a few long rowsTested on sample rows only
6Font coverageAll Turkish and Arabic glyphs present, no fallbackFallback font visible on rare glyphsMissing-glyph boxes seen
7Price and number stringsCurrency, separators and order checked in each scriptChecked in one scriptUnchecked
8Layout directionArabic layout reviewed as its own designMirrored automatically, not reviewedLeft-to-right layout reused

Reading the total. 14 to 16: ship to all segments. 10 to 13: ship to a limited segment and fix the lowest-scoring checks first. Below 10: hold the template. Any 0 on checks 2, 3 or 4 is a hold regardless of the total, because those failures change the meaning of the text rather than just its look.

Check 1 and 2: language tags and Turkish casing

Casing is the cheapest failure to fix and the most embarrassing to ship. In HTML5 creative, text-transform: uppercase follows the lang attribute, so an element without lang="tr" falls back to default mappings (MDN). MDN also warns that support for language-specific casing varies between browsers, so test the browsers your ad servers actually render in.

In scripts, pass the locale explicitly. We ran these in Node 22 on 8 October 2026:

InputDefault callTurkish locale call
"indirim".toUpperCase()INDIRIM"indirim".toLocaleUpperCase("tr") gives İNDİRİM
"DİYARBAKIR".toLowerCase()di̇yarbakir (with a stray combining dot, code point 307)"DİYARBAKIR".toLocaleLowerCase("tr") gives diyarbakır
"ISPARTA".toLowerCase()isparta"ISPARTA".toLocaleLowerCase("tr") gives ısparta

The locale call is documented in MDN's toLocaleUpperCase page, which uses istanbul and İSTANBUL as its Turkish example. Note one trap from the same page: the method does not negotiate among locales. It uses the first locale you pass, so a fallback list such as ["tr", "en"] never reaches English.

One policy point. Google asks advertisers to avoid all caps for emphasis in titles (Merchant Center Help). Do the uppercase transformation in the creative layer, on the badge or headline, and leave the feed title in normal case. If your feed rules rewrite titles, keep casing changes out of the title attribute. A rules engine such as Feedance feed rules can reformat text and currency fields, but whichever tool you use, check that its case-change function takes a locale.

Check 3: bidirectional isolation for mixed-script fields

A single Arabic product row can contain an Arabic title, a Latin brand, a model number, a price with a currency code and a percent badge. Each is a separate run with its own direction. Without isolation, punctuation and numbers between runs can attach to the wrong side (UAX #9, rules N1 and N2).

The W3C's guidance for text that comes from a database is direct: the application cannot know the direction in advance, so wrap each inserted value in an element with dir="auto", or use bdi, which behaves as dir="auto" by default (W3C, inline markup and bidirectional text). Where markup is impossible, for example in an image generator's plain-string input, the same article describes the invisible Unicode isolates: U+2068 (first strong isolate) before the value and U+2069 (pop directional isolate) after it. UAX #9 explains why: characters inside an isolate cannot affect the ordering of characters outside it, and the reverse.

VersionMarkup
Before: fields concatenated<div lang="ar" dir="rtl">{brand} - {title} - {discount}</div>
After: each value isolated<div lang="ar" dir="rtl"><bdi>{brand}</bdi> - <bdi>{title}</bdi> - <bdi>{discount}</bdi></div>

Score 2 only if you have looked at rendered output for rows where the brand is Latin and the title is Arabic, and where the row ends in punctuation or a percent sign. That is where the failures hide.

Check 4: text shaping in image and video output

Arabic letters change shape depending on their neighbors. A renderer without a complex-text layout engine draws each letter in isolation and in the wrong order. Browsers handle this, so HTML5 creative rarely fails here. Server-side image and video generation often does.

If you generate images in Python, Pillow documents the split clearly: the basic layout engine does not support advanced features or text direction, while the Raqm engine does, and the direction, features and language parameters each require libraqm (Pillow, ImageFont). Check with PIL.features.check_feature("raqm") in the same environment that renders production creative, not on a laptop. A container without libraqm uses the basic engine. Whatever stack you use, the test is the same: render one Arabic row in every output format and read it.

Check 5: fit on worst-case rows

Take the length distribution of your actual feed, not a sample. Pull the longest 5% of titles per language, then render those first. Design the template with an explicit overflow rule: shrink to a minimum font size, then truncate at a word boundary, then fall back to a shorter field such as a product type. Never cut inside a word: that can split joined Arabic letters or separate a base letter from its combining mark.

Do not budget text expansion from published averages. The W3C's article on text size in translation gives expansion figures for European languages, for example a 130% average for English strings over 70 characters, and gives no figures for Arabic or Turkish (W3C, text size in translation). Be suspicious of any blog that quotes a precise Turkish or Arabic expansion percentage without a source. Measure your own rows instead. The W3C's advice that does apply: avoid fitting text snugly into graphic designs, and let it reflow.

Checks 6 to 8: fonts, numbers and layout direction

Font coverage

Render the glyphs ç ğ ı İ ö ş ü and a full Arabic sample in every brand font. A brand font that lacks Turkish glyphs falls back for single letters and the headline looks stitched together. Missing-glyph boxes score 0.

Price and number strings

Prices carry currency position, separators and, in Arabic text, a direction problem: UAX #9 rule W2 treats a European number that follows Arabic-script text as an Arabic number for ordering purposes, so a price beside a currency code can be reordered unless its run is isolated. The formatting itself, including VAT-inclusive TRY, AED and SAR values, is covered in our guide to price formats that fail Google and Meta checks. Here the check is visual: view the rendered price in each script and confirm digits, symbol and separator appear in the intended order.

Layout direction

Badge position, arrows and reading order in an Arabic ad are design decisions. Automatic mirroring is a starting point, not a review. Logos usually should not mirror.

Worked example: one TR row and one AR row

These are illustrative rows, not client data.

FieldTR rowAR row
titleSiyah Deri Omuz Çantasıحقيبة كتف جلدية سوداء
brandNovaNova
sale_price1299.00 TRY349.00 SAR
custom_label_0indirimdiscount

The template shows the badge from custom_label_0 in capitals. On the TR row, a default uppercase call gives INDIRIM, which fails check 2. On the AR row, the Latin brand sits inside an RTL sentence, so the dash and price either side of it need isolation or they can drift (check 3).

Scale makes this worth doing before launch. In one published case, a branded template mapped to product feed fields produced 10,000 creatives in about two hours. One uncorrected casing bug at that volume ships 10,000 times.

Where this guide breaks down

  • It catches failures, not elegance. A human designer will still beat any template engine on Arabic typographic polish, such as letter-spacing and line justification.
  • The rubric is ours and has not been validated against performance data. We make no claim that a score of 16 lifts click-through rate.
  • We have not tested Confect, Hunch, Marpipe or other creative tools against these checks, so we do not rank them. We have also not published right-to-left capability claims for our own creative pages, so ask any vendor, us included, to run your sample rows and show the output.
  • Browser support for language-specific casing varies, so a pass in one browser is not a pass in all.
  • Other scripts and locales, for example Persian digits or Kurdish, need their own checks.

Frequently asked questions

Why does my Turkish badge say INDIRIM instead of İNDİRİM?

The code uppercased the text with default Unicode rules, which map i to I. Turkish needs i to map to İ. Use toLocaleUpperCase("tr") in scripts, or set lang="tr" on the element when using CSS text-transform.

Do I need to change my feed for Arabic creative?

Usually not. Keep the feed in normal case and in the language of the data source, since Google expects the majority of product data to match that language (Merchant Center Help). Fix direction and casing in the creative layer.

What does bdi do and when do I use it?

The bdi element isolates its content from surrounding text and sets direction from the first strong character. Use it around any value inserted from a database, such as a brand, a title or a discount.

Why do Arabic letters look disconnected in my generated images?

The renderer is probably using a basic text layout without a complex-text engine. In Pillow, the Raqm layout engine and libraqm are required for direction and language support, and the library falls back to basic layout when Raqm is absent.

How much longer is Turkish or Arabic text than English?

We could not find a reliable published figure for either. The W3C's expansion averages cover European languages and say nothing on Arabic or Turkish. Measure the longest rows in your own feed.

Should the lowercase conversion also use the Turkish locale?

Yes. In our Node test, default lowercase turned DİYARBAKIR into di̇yarbakir with a stray combining dot, and ISPARTA into isparta instead of ısparta.

How many sample rows are enough?

Fifty per language is a workable minimum for this rubric, provided it includes the longest 5% of titles and every row with a Latin brand in Arabic text. Larger catalogs with many brands deserve more.

Run the rubric on your own templates

If you build feed-driven image, video or HTML5 creative and want your Turkish and Arabic rows scored against these eight checks, book a 15-minute demo and bring your worst-case rows. We will walk through the output from the Creative Suite together and score it against the rubric.

Prev Article
Fixing Google Content API 410 Errors: Migrating Your Feed Pipeline to Merchant API

Related to this topic:

Schedule your 15-minute demo now

Schedule my demo

We’ll tailor your demo to your immediate needs and answer all your questions. Get ready to see how it works!