NieuwProduct Score, 4T Segmentation, Price War en Broken Size zijn live.Bekijk wat er nieuw is
Feedance
Artikel

Turkse producttitels naar kleine letters zonder İ en ı te breken: een playbook voor feedregels

Standaard lowercase maakt van İZMİR i̇zmi̇r en van ISPARTA isparta. Test, herstel en borg Turkse casing in feedregels met een testset van 5 rijen.

Inci DindarInci Dindar
9 min. leestijd
Product tags with one misplaced dot being inspected by a magnifier, illustrating Turkish casing errors in feed titles

Google staat een producttitel van 1 tot 150 tekens toe en zegt dat adverteerders geen hoofdletters moeten gebruiken om iets te benadrukken (Merchant Center Help). Turkse catalogi die uit ERP-systemen komen, zijn vaak volledig in hoofdletters geschreven. De voor de hand liggende oplossing is dus een regel die elke titel omzet naar kleine letters of titlecase. Juist die regel zorgt ervoor dat Turkse data ongemerkt kapotgaat. In onze test gaf een standaard lowercase van İZMİR ÇİZGİLİ KIŞLIK MONT 30 codepoints terug in plaats van 25, en werd ISPARTA isparta in plaats van ısparta. Deze gids is bedoeld voor feedmanagers en ontwikkelaars die met Turkse producttekst werken. Aan het einde kun je je stack testen, de casingregel repareren en een controle toevoegen die het probleem bij elke sync opvangt.

Waarom Turkse casing gewone regels breekt

Turks kent twee aparte lettersparen: de punt-loze ı met hoofdletter I, en de i met punt met hoofdletter İ. Het Unicode-bestand voor case-mapping zegt het letterlijk: "I and i-dotless; I-dot and i are case pairs in Turkish and Azeri" (Unicode SpecialCasing.txt).

Standaard (taalneutrale) casing weet dit niet. Die zet I om naar i, en İ naar i plus een combinerende punt erboven (U+0307). De Turkse regels in hetzelfde bestand zetten I om naar ı en İ naar een gewone i. Azerbeidzjaans volgt dezelfde regel.

In een feed gaan er drie dingen mis:

  • Verkeerde letters. KADIN wordt kadin, YAĞI wordt yaği. Het woord is nog leesbaar, maar fout gespeld.
  • Extra tekens. İZMİR wordt i̇zmi̇r, een string met twee extra codepoints die onzichtbaar lijken. Op het scherm ziet het er bijna goed uit, maar het komt niet overeen met izmir in een filter, een join of een zoekopdracht.
  • Verkeerde hoofdletters in de andere richting. istanbul wordt ISTANBUL in plaats van İSTANBUL, en titlecase geeft Iç in plaats van İç.

Stap 1: Ontdek wat je stack nu doet

Controleer voordat je een regel aanpast hoe de code die je titels transformeert zich gedraagt. We hebben dezelfde twee invoerwaarden door de runtimes gehaald die de meeste feedpipelines gebruiken. De invoer was ISPARTA İSTANBUL voor lowercase en istanbul ışık voor uppercase.

Runtime en aanroepResultaat lowercaseResultaat uppercaseCorrect voor het Turks?
JavaScript toLowerCase() / toUpperCase()isparta i̇stanbulISTANBUL IŞIKNee
JavaScript toLocaleLowerCase("tr") / toLocaleUpperCase("tr")ısparta istanbulİSTANBUL IŞIKJa
Python 3.13 str.lower() / str.upper()isparta i̇stanbulISTANBUL IŞIKNee
PHP 8.3 mb_strtolower()i̇stanbul (voor İSTANBUL)n.v.t.Nee
PHP 8.3 strtolower()isparta (voor ISPARTA)n.v.t.Nee
Perl lc() / uc()isparta i̇stanbulISTANBUL IŞIKNee

Twee details zijn belangrijk. Ten eerste gebruikt de gewone toLocaleLowerCase() van JavaScript zonder argument de standaardlocale, waardoor dezelfde code op een server anders kan werken dan op een laptop. In de documentatie geeft "İstanbul".toLocaleLowerCase("en-US") als resultaat i̇stanbul en toLocaleLowerCase("tr") als resultaat istanbul (MDN). Geef "tr" daarom altijd expliciet mee.

Ten tweede is strtolower() in PHP 8.2 aangepast: de functie hangt niet langer af van setlocale() en converteert alleen ASCII-tekens (PHP-handleiding). Het instellen van een Turkse locale verandert daar in een actuele versie niets aan.

Stap 2: Bouw een testset met echte titels

Neem 10 tot 15 titels uit je eigen catalogus die elke Turks-specifieke letter bevatten: İ, I, ı, i, Ş, Ğ, Ç, Ö, Ü. Neem een titel op die met I begint, een die met İ begint en een met een eenheid zoals ML of GB. Hieronder staat een beginset, met de uitvoer van een standaard lowercase naast de juiste uitvoer.

BrontitelStandaard lowercaseTurkse lowercase
ISPARTA GÜL YAĞI 50 MLisparta gül yaği 50 mlısparta gül yağı 50 ml
İZMİR ÇİZGİLİ KIŞLIK MONTi̇zmi̇r çi̇zgi̇li̇ kişlik montizmir çizgili kışlık mont
KADIN İÇ ÇAMAŞIRI SETİkadin i̇ç çamaşiri seti̇kadın iç çamaşırı seti
IŞIK GEÇİRMEZ PERDEişik geçi̇rmez perdeışık geçirmez perde
ÇOCUK OKUL ÇANTASIçocuk okul çantasiçocuk okul çantası

Kijk naar de laatste rij. Er is maar één letter anders, en een visuele steekproef van een paar titels zou dat gemakkelijk missen. Daarom moet de testset elke letter dekken, en daarom vergelijk je strings in plaats van op indrukken af te gaan.

Stap 3: Repareer de casingfunctie

Waar je tool je de locale laat kiezen, stel je die in op tr. Waar dat niet kan, wikkel je de transformatie zelf in. In JavaScript of Node is de oplossing één argument:

title.toLocaleLowerCase("tr")
title.toLocaleUpperCase("tr")

De standaard stringmethoden van Python hebben geen locale-argument. Een betrouwbare workaround is om de vier speciale letters te vervangen voordat je de standaardmethode aanroept. We hebben deze versie getest op de eerste vier rijen hierboven:

def tr_lower(s):
    return s.replace("İ", "i").replace("I", "ı").lower()

def tr_upper(s):
    return s.replace("i", "İ").replace("ı", "I").upper()

De volgorde is belangrijk. Vervang eerst İ en I en zet daarna om naar kleine letters. Als je eerst omzet naar kleine letters, is de informatie over welke hoofdletter het was al verloren.

Stap 4: Behandel titlecase en eenheden apart

Titlecase brengt twee extra problemen met zich mee. Het met een hoofdletter schrijven van de eerste letter van elk woord moet de Turkse uppercase gebruiken, anders wordt iç çamaşırı met de title() van Python Iç Çamaşırı. Daarnaast zet een algemene regel ook eenheden met hoofdletter: 50 ML wordt 50 Ml.

Het patroon dat wij gebruiken is: de hele titel met de Turkse functie naar kleine letters omzetten, de eerste letter van elk woord met de Turkse functie naar hoofdletter omzetten, en elk token overslaan dat met een cijfer begint of op een korte eenhedenlijst staat (ml, gb, cm, kg). Op ISPARTA GÜL YAĞI 50 ML levert dit Isparta Gül Yağı 50 ml op. Zonder de eenhedenlijst geeft dezelfde pipeline 50 Ml. Let op: Isparta is correct, want de plaatsnaam begint met een hoofdletter I zonder punt.

Merknamen zijn een apart geval. Een merk dat bewust in hoofdletters is geschreven (IKEA, HP) heeft een uitsluitingslijst nodig, omdat Google alleen vraagt om hoofdletters niet voor nadruk te gebruiken en ze wel toe te passen waar dat past, zoals bij afkortingen (Merchant Center Help). Houd de lijst kort en bewaar hem op dezelfde plek als de regel.

Als je deze regels beheert in een tool voor feedbeheer, controleer dan hoe die casing toepast. De Feed Rules van Feedance bieden hoofdletters, zinscase en beginhoofdletters als opties, en de pagina vermeldt niet welke locale ze gebruiken. Daarom draaien we deze testset op elke tool, ook die van onszelf, voordat we hem vertrouwen met Turkse tekst. Voor een breder beeld van wanneer een regel volstaat en wanneer een AI-model de moeite waard is, lees je onze vergelijking van regelgebaseerde en AI-producttitels.

Stap 5: Spoor resterende schade in bestaande data op

Als een foutieve regel al is uitgevoerd, zit de combinerende punt nu in je opgeslagen data. Unicode-normalisatie verwijdert die niet: in onze test bleef i gevolgd door U+0307 na NFC-normalisatie twee codepoints, omdat er geen voorgecomponeerde vorm bestaat om in samen te voegen. Je moet het teken zelf opsporen en verwijderen.

Deze controle meldt elke titel die de combinerende punt bevat:

import re
bad = [t for t in titles if re.search("̇", t)]

Nadat je de gecorrigeerde regel opnieuw op İZMİR hebt uitgevoerd, geeft dezelfde controle false terug. Voer hem uit op title, description, brand, product_type en elk custom_label-veld, want casingregels worden vaak op meer dan alleen titels toegepast.

Een aparte kwestie: als een kanaal een encodingfout meldt, is dat een andere fout. De pagina "Invalid UTF-8 encoding" van Merchant Center zegt dat de oorzaak een probleem met de encoding van de tekst is en vertelt je de encoding van het bestand te declareren of te converteren (Merchant Center Help). De casingbug levert geldige UTF-8 op en veroorzaakt die fout dus niet. Hij glipt er geruisloos doorheen, en dat is precies de reden om ernaar te testen.

Stap 6: Maak er een poort van bij elke sync

Een oplossing die niemand opnieuw controleert, gaat achteruit zodra iemand een regel toevoegt of van tool wisselt. Gebruik deze checklist als releasepoort voor elke wijziging aan regels voor titel, beschrijving of categorienaam.

ControleSlaagvoorwaarde
Locale is explicietElke casefunctie wordt aangeroepen met tr of ingepakt zoals hierboven
Testset slaagtAlle rijen komen teken voor teken overeen met de Turks-correcte uitvoer
Geen combinerende puntNul velden bevatten U+0307
Eenheden behoudenTokens zoals ml, gb, cm krijgen geen titlecase
Merkuitzonderingen toegepastOpgenomen merken behouden hun bedoelde hoofdletters
Lengte ongewijzigdUitvoer is in codepoints niet langer dan de invoer en blijft binnen 150

De lengtecontrole vangt de extra codepoints op die de standaard lowercase toevoegt. Het is een handige struikeldraad, ook als je nog niet weet welke regel de wijziging heeft veroorzaakt.

Waar deze aanpak tekortschiet

Dit is een methode voor Turks en Azerbeidzjaans, de twee talen die het Unicode-bestand voor deze regel noemt. Ze dekt geen velden in Arabisch schrift; lees voor die velden hoe je Arabische en Engelse productdata structureert.

We hebben geen bewijs dat Google of een marktplaats een product afkeurt vanwege een verkeerde i met of zonder punt. De gedocumenteerde kosten zijn indirect: foutgespelde titels voor de ogen van shoppers, en strings die niet meer overeenkomen met je filters, joins en interne zoekfunctie. Beschouw het als een datakwaliteitsfout, niet als een beleidskwestie.

De vervangingstruc uit Stap 3 behandelt de vier speciale letters, maar is geen volledige implementatie van de Unicode-casingregels. Bibliotheken op basis van ICU en tools met een locale-instelling dekken meer randgevallen dan een met de hand geschreven wrapper. Als een tool die je gebruikt al een correcte Turkse localeoptie heeft, gebruik die dan en bewaar alleen de testset. We hebben niet getest hoe Channable, DataFeedWatch of Productsup met de Turkse locale omgaan, dus we doen daar geen uitspraken over; draai de testset erop zoals je dat bij elke tool zou doen. Marktplaatsen hanteren daarbovenop eigen titelregels, die we behandelen in onze gidsen over feeds voor Akakçe, Cimri, N11 en ÇiçekSepeti.

FAQ

Waarom wordt İZMİR i̇zmi̇r als ik het naar kleine letters omzet?

Standaard Unicode-lowercasing zet de hoofdletter İ met punt om naar een gewone i plus een combinerende punt erboven (U+0307). De Turkse regel zet İ om naar een gewone i. Het resultaat ziet er op het scherm bijna goed uit, maar bevat extra codepoints.

Weigert Google Merchant Center titels met de combinerende punt?

We vonden daar geen gedocumenteerde afkeuring voor. De string is geldige UTF-8 en veroorzaakt dus niet de fout "Invalid UTF-8 encoding". De schade bestaat uit foutgespelde titels en mislukte matching in je eigen tools.

Moet ik titels in hoofdletters, kleine letters of titlecase versturen?

Google zegt dat je geen hoofdletters moet gebruiken voor nadruk en de belangrijkste details vooraan moet zetten, omdat gebruikers meestal alleen de eerste 70 tekens of minder zien. Zinscase of titlecase met correcte Turkse letters voldoet allebei. Welke beter converteert, is een test voor je eigen account.

Is toLowerCase("tr") genoeg in JavaScript?

Nee. toLowerCase() accepteert geen locale. Gebruik toLocaleLowerCase("tr") en geef de locale expliciet mee, want de standaard hangt af van de omgeving.

Waarom lost setlocale strtolower van PHP niet op?

Sinds PHP 8.2 negeert strtolower() de locale en converteert de functie alleen ASCII-letters. mb_strtolower() verwerkt niet-ASCII-tekst, maar gaf in onze test voor İSTANBUL nog steeds i̇stanbul terug. Pas de tekenvervanging uit Stap 3 toe voordat je de functie aanroept.

Kan Unicode-normalisatie de verdwaalde punt verwijderen?

Nee. In onze test liet NFC i plus U+0307 als twee codepoints staan. Verwijder het teken expliciet en voer daarna de gecorrigeerde casingregel opnieuw uit op de originele brontekst.

Heeft dit invloed op Arabisch of andere talen?

De regel geldt voor Turks en Azerbeidzjaans. Andere talen hebben hun eigen casing- en normalisatieproblemen, die deze gids niet behandelt.

Hoeveel testrijen zijn genoeg?

Genoeg om elke Turks-specifieke letter te dekken, op elke positie waar die kan voorkomen: begin van het woord, midden, einde en naast een cijfer. Voor de meeste catalogi zijn dat 10 tot 15 titels. Voeg een rij toe wanneer er een nieuw defect in productie opduikt.

Check je eigen feed

Wil je zien hoe je huidige feed scoort op titel- en attribuutkwaliteit? Laat hem dan door onze gratis tool voor productfeedaudits lopen.

Wil je dat iemand anders ook naar je feed kijkt? We nemen hem samen met je door en laten zien waar de gaten zitten, nog voor je volgende inzending.
Doe een gratis audit
Inci Dindar
Geschreven door
Inci Dindar

Medeoprichter van Feedance, waar ze haar ruim 20 jaar ervaring in product- en user-experience-design inzet om te bepalen hoe catalogi creatief worden. Met een sterke focus op het verbinden van designsystemen en automatisering zet ze zich in om merken te helpen hun visuele kwaliteit op te schalen zonder dat de ontwerpinspanning meegroeit.

LinkedIn

Zie welke
producten opbrengen.

Koppel je feed en GA4. We tonen Product Score, 4T, Price War en Broken Size op je eigen catalogus.