Translation and Linguistic Testing

Translation testing checks the translated text of a product as users will meet it: on the real screen, in the real layout, with real data. It asks whether every string says what the source meant, fits its space, keeps its placeholders, chooses the right plural form and still reads correctly when Arabic and English, or Hindi and English, share one sentence. A product whose Arabic cart badge says "2 منتج" (singular) instead of "منتجان" can pass every functional test and still ship a translation defect.

It has two halves done by two different people. A linguistic review, performed by a qualified native speaker, judges meaning, grammar, terminology and tone. Functional localization testing, performed by a tester at any language level, checks that the translated build behaves: nothing untranslated, nothing cut off, nothing broken by a placeholder, and the right message for every count.

Why it matters

Translators usually work from a spreadsheet or a translation-management system with no view of the screen, so a correct translation of the wrong meaning is common: the English "Open" is both a status and a command, and "Save" means storing data on one screen and paying less on another. Developers rarely read the target language, so a translated placeholder, a missing plural category or an Arabic sentence with a reversed order number passes code review. The first person who sees the defect is often the user.

For the product, these defects cost trust rather than crashes: a shop that cannot count its own products in Arabic, or a bank whose Hindi confirmation is cut off mid-word, looks careless in the market it is trying to win. For the tester, translation testing is a chance to add value with structure: a list of locales, a table of counts, a set of mixed-direction strings and a screenshot per string key find most of these defects without speaking the language.

Linguistic review and functional localization testing are different jobs

A linguistic review (some teams say linguistic QA or in-context review) is done by a qualified native speaker, ideally one who did not translate the text, against the glossary and the style guide. It judges accuracy (does the Arabic mean what the English meant?), fluency, terminology, grammar and spelling, register (how the product addresses the user) and cultural fit. Its output is a list of corrections per string key, not a bug report.

Functional localization testing is done by a tester with the translated build, test data and a checklist, and does not require fluency. It verifies that the translation is loaded and complete, that layout, placeholders, plurals, sorting, search and input work in the locale, and that features behave as they do in the source language. Its output is defects. The two activities meet in one artefact: screenshots of each string in context, which give the reviewer the context the translator never had and give the developer the key to fix.

  • Linguistic review needs: the glossary, the style guide, the source text and screenshots; it records string key, current text, proposed text and reason.
  • Functional testing needs: the build in each locale, realistic localized test data, a plural count table and a mixed-direction string set; it records string key, locale, screen, expected and actual.
  • Order: run pseudo-localization and functional testing first so missing strings do not block the reviewer; run the linguistic review when the strings are stable; retest (confirmation testing) after the corrections land.

What breaks in translated strings: meaning, placeholders, plurals, length

Context defects come from strings translated without seeing where they appear. Short strings are the riskiest: "Open", "Close", "Post", "Clear", "None" and "Home" each have several meanings, and one key reused on two screens with two meanings cannot be right on both. Ask for one key per context and check every short string on its screen.

Placeholders are the parts of a message the code fills in: {name}, {{count}}, %s, %1$s, {0}. A translator may translate one or delete one. Plain %s placeholders are filled strictly in order, so if the target sentence puts the city before the date, the date lands where the city should be; numbered placeholders such as %1$s and %2$s exist so that a translation can reorder them. Test every message that has a placeholder with a real value in every locale, and read the resource files side by side: the set of placeholders in the translation must equal the set in the source.

Plural forms follow the locale, not English. The CLDR plural categories (two for English and Hindi, six for Arabic) and the reason code that picks a form with count === 1 fails in Arabic are covered in the localization testing guide and the lesson on internationalization. The part that belongs to translation testing is the count table: one value per category of the locale, for Arabic 0, 1, 2, 3, 11 and 100, run against every counted message on screen to confirm that each delivered translation carries all the categories its locale needs.

Length and truncation: translated text is often longer than the English source, and Devanagari needs more height for the marks above and below the line. Fixed-width buttons, tabs, table headers, badges, push notification titles and SMS are where it shows. A cut inside an Arabic word gives the last remaining letter its final form, so the fragment can read as a different word; a cut inside a Hindi syllable can leave a half consonant with a visible virama, and a split message can start its next part with a vowel sign that many fonts draw on a dotted circle. Where a hard limit exists, for example a notification title or an SMS segment, measure the translated string against the limit in the unit the system counts.

  • Untranslated strings (English left in the Arabic or Hindi interface, see the localization testing guide): compare the key sets of the source and target resource files to find them before opening the app.
  • Concatenation (see the lesson on internationalization): a sentence built from fragments in code cannot be translated with the right word order; the fix is one message with parameters, made by the developer.
  • Gender and register (see the localization testing guide): the linguistic review checks that the product applies its choice of address, masculine, neutral or by profile, in every string.

Try it: JSON Diff Try it: String Length Counter

Mixed LTR and RTL text inside a translated string

The RTL testing guide explains the Unicode Bidirectional Algorithm (UAX #9) and the bidi test set; translation testing adds one question to them. The translator decides where each placeholder sits in the target sentence, and the values that fill placeholders are often left-to-right: brand names, order ids, emails, URLs, file names and anything a user typed in English. A translated string that reads correctly with an Arabic value can break with a Latin one, so every placeholder needs both.

Three cases come up again and again. First, a value whose digits are followed by a hyphen and Latin letters is reordered inside an Arabic sentence: the order id 1042-A displays as A-1042, while A-1042, which begins with a letter, keeps its order because its digits take the direction of the letter before them. Second, Western digits that follow a Latin value with only spaces or punctuation between them join its left-to-right run: in تقييم {user}: {score} with the user "Sara", the score is laid out next to "تقييم", before the name. Third, a translation that starts with a placeholder: plain text shown without a set direction takes its paragraph direction from the first strong letter (UAX #9 rules P2 and P3), and dir="auto" does the same, so {app} يذكّرك بموعدك غداً. filled with a Latin app name becomes a left-to-right paragraph, aligned left, with the full stop on the wrong side.

  • For every message with a placeholder, note where the placeholder sits in each translation (start, middle or end) and test it twice: with an Arabic value and with a Latin value such as a brand, an email or a hyphenated id.
  • Ask how the value is isolated: <bdi> or dir="auto" on the element that holds it in HTML, or FSI (U+2068) and PDI (U+2069) around it in plain text. Isolation fixes all three cases: the value is laid out on its own, and UAX #9 skips isolated text when it looks for the first strong letter. Direction marks (U+200E, U+200F) typed or pasted into a translation file are invisible in review and fix only the value they were tested with; convert a suspicious string to code points to see them.
  • Check the same string in the Hindi locale too: Hindi is left-to-right, so a defect that appears only in Arabic points at direction handling, and one that appears in both points at the placeholder itself.
Six kinds of translation defect, from wrong meaning to mixed-direction order, each with an example symptom on screen, its usual cause and the check that finds it.
DefectSymptom on screenUsual causeHow to find it
Wrong meaning (context)Order status "Open" shown as the command "افتح"String translated without the screen; one key used in two contextsRead every short string on its screen; linguistic review with screenshots
Untranslated string"Field is required" in English on the Arabic formKey missing from the target file; string added late in the sprintCompare the key sets of source and target files; switch locale and scan errors and emails
Broken placeholderRaw braces "{رقم الطلب}" printed in the shipping messagePlaceholder translated, deleted or reordered by the translatorCompare placeholder sets per key; fill every placeholder with a real value in every locale
Wrong plural formCart badge "2 منتج" instead of "منتجان"Form chosen with count === 1; message without the CLDR categoriesCount table per locale: 0, 1, 2, 3, 11, 100 for Arabic; 0, 1, 2 for Hindi
Truncation or overflowHindi product name cut inside a syllable, leaving a half consonant with a visible viramaFixed-width control; longer translation; limit counted in bytesRealistic long names in every locale; measure against hard limits in the unit the system counts
Mixed-direction orderOrder id 1042-A shown as A-1042 inside an Arabic sentencePlaceholder value not isolated from the Arabic around it, so its digits and its Latin letter are laid out as separate runsFill every placeholder with an Arabic and a Latin value; convert strings to code points to see hidden marks

Try it: Multilingual Test Data Generator Try it: Unicode Encoder

Worked example: the checkout strings in Arabic and Hindi

A shop externalises its checkout strings in one JSON file per locale. The Arabic and Hindi files arrive from the translation vendor; the tester reads them side by side with the English source before opening the app, then verifies on screen with the counts 0, 1, 2, 3, 11 and 100 and the order id 1042-A.

  • cart.items: the Arabic drops the plural structure; for 2 it shows "2 منتج" instead of "منتجان", for 3 it should read "3 منتجات" and for 11 "11 منتجاً". Functional defect, found with the count table; the fix is a message with the six CLDR categories.
  • order.shipped: the placeholder {orderId} was translated to {رقم الطلب}, so the formatter prints the raw braces. Functional defect, found by comparing the placeholder sets of the two files.
  • order.shipped on screen with 1042-A, once the placeholder is fixed: the id displays as A-1042 inside the Arabic sentence until the value is isolated with <bdi>. Functional defect, found by filling the placeholder with a Latin value.
  • status.open: "افتح" is the command "open it"; the key is an order status and should read "مفتوح". Linguistic defect, visible only in context, reported with a screenshot of the orders table.
  • Hindi file: cart.items as "{count} आइटम" is acceptable because Hindi has two categories and the loanword does not change, but the reviewer flags "सेव करें" on this screen and "सहेजें" on the settings screen as a terminology inconsistency against the glossary.
en.json
  "cart.items":    "{count, plural, one {# item} other {# items}}"
  "order.shipped": "Order {orderId} shipped to {city}"
  "status.open":   "Open"
  "button.save":   "Save"

ar.json (as delivered)
  "cart.items":    "{count} منتج"
  "order.shipped": "تم شحن الطلب {رقم الطلب} إلى {city}"
  "status.open":   "افتح"
  "button.save":   "حفظ"

hi.json (as delivered)
  "cart.items":    "{count} आइटम"
  "order.shipped": "ऑर्डर {orderId} {city} को भेज दिया गया"
  "status.open":   "खुला"
  "button.save":   "सेव करें"

Try it: Arabic Test Data Generator Try it: Hindi Test Data Generator

Common mistakes

  • Reviewing translations only in the spreadsheet or the translation tool and never on the screen where the string appears.
  • Treating the linguistic review as the whole of localization testing, or skipping it because "the tester checked the Arabic".
  • Testing plurals with 1 and 2 only; Arabic needs one value from each of its six categories, for example 0, 1, 2, 3, 11 and 100.
  • Accepting a resource file without comparing its keys and placeholders with the source, then discovering raw braces in production.
  • Reporting "the Arabic looks wrong" without the string key, the locale, the screen and a screenshot, so the fix cannot be placed.
  • Testing with short placeholder data such as "Test" instead of realistic long names, addresses and mixed-script values, so truncation and direction defects never appear.

The QA perspective

On a real team translation testing starts before the translation exists. At the string freeze (when the source text stops changing and goes to translation), the tester exports the source resource file, lists every placeholder and every counted message, and asks three questions: is there a glossary and a style guide, which library formats the plurals, and is there a pseudo-locale build. When the translated files arrive, the file comparison (keys, placeholders) takes minutes and catches the cheapest defects first; the on-screen pass with the count table and the mixed-direction set follows in each locale.

Record every finding with the string key, the locale, the screen, expected and actual, and a screenshot, and mark it functional or linguistic. A linguistic finding goes to the reviewer or the vendor. A functional finding goes to whoever owns the layer that is wrong, the same split between internationalization and localization as in the lesson on internationalization: to the developer when the code is wrong (a hard-coded or concatenated string, a plural chosen with count === 1, a value shown without isolation), and back to the translator or vendor when the delivered resource file is wrong (a translated placeholder, missing plural categories, a missing key). Keep the screenshots: they are the context the linguistic reviewer needs, and the evidence for the retest once the corrected files are imported.

Practice exercise

Review the resource file of a notifications screen

Your task

A notifications screen has four source strings and their Arabic and Hindi translations below. Without running the app, find every defect you can from the files alone, then list what you would still need to verify on screen. Classify each finding as functional or linguistic and write it as a bug title with the string key.

For notif.unread, only check whether each translation has the plural categories its locale needs. Spend the rest of the time on context and direction: what you would ask about where notif.clear and notif.none appear, and which values you would fill into notif.from and what you expect to see.

Material
en.json
  "notif.unread": "{count, plural, one {# unread message} other {# unread messages}}"
  "notif.from":   "From {sender} · {time}"
  "notif.clear":  "Clear"
  "notif.none":   "None"

ar.json
  "notif.unread": "{count} رسالة غير مقروءة"
  "notif.from":   "من {المرسل} · {time}"
  "notif.clear":  "واضح"
  "notif.none":   "لا شيء"

hi.json
  "notif.unread": "{count} अपठित संदेश"
  "notif.from":   "{sender} से · {time}"
  "notif.clear":  "साफ़ करें"
  "notif.none":   "कोई नहीं"
Steps
  1. Compare the placeholder set of each translation with its source string.
  2. Check each counted message for the plural categories its locale needs.
  3. Read each short string and ask which meaning the key needs on this screen.
  4. List the realistic values you would fill into the placeholders to test mixed-direction display.
Show the model answer
Model answer

notif.unread (functional, in ar.json, so it goes back to the vendor): the Arabic has no plural structure, so 2 would read "2 رسالة غير مقروءة" instead of "رسالتان غير مقروءتين"; the message needs all six Arabic categories (zero, one, two, few, many and other), which the count table confirms on screen once the corrected file arrives. The Hindi string needs no plural structure, because "अपठित संदेश" is the same in both Hindi categories.

notif.from (functional, in ar.json, for the vendor): the Arabic translated the placeholder {sender} into {المرسل}, so the formatter will print raw braces or fail. The Hindi keeps both placeholders and puts {sender} before "से", the correct Hindi word order for a postposition; this works because the line is one message with named placeholders, not "From " joined to the name in code.

notif.clear (linguistic): "واضح" means "clear" as in "obvious"; on a button that empties the list the key needs the action label "مسح". The Hindi "साफ़ करें" is the command and is correct.

notif.none (linguistic, needs context): "لا شيء" and "कोई नहीं" are literal; if the key labels an empty list, "لا توجد إشعارات" and "कोई सूचना नहीं" read naturally, and the reviewer should ask the product owner where the key appears.

Still to verify on screen: notif.from, once its placeholder is fixed, with an Arabic sender and with a Latin sender such as "Acme-2" or "support@example.com". If {time} is written with Western digits, they follow the Latin name with only the "·" separator between them, so they join its left-to-right run and the time can appear next to "من", before the sender; expect this defect unless {sender} is isolated. Also check whether a long sender name truncates the time, and whether the Hindi strings fit the height of the notification row.

Frequently asked questions

Do I need to speak Arabic or Hindi to test translations?

Not for functional localization testing: completeness, placeholders, plurals, truncation and mixed-direction display are checked with resource files, test data and a checklist. The linguistic review of meaning, grammar, terminology and tone does need a qualified native speaker, ideally not the translator who produced the text.

How is translation testing different from localization testing?

Localization testing covers everything that changes with the locale: formats, calendars, currency, layout direction, encoding and language. Translation and linguistic testing is the language part of it: the strings themselves, in context, on screen.

How many counts do I need to test a plural message?

One value per plural category of the locale, from the CLDR rules: for English 1 and 2; for Hindi 0, 1 and 2; for Arabic 0, 1, 2, 3, 11 and 100. Add 0 in every locale, since many products have a special "no items" message that is a separate string.

Can machine translation replace the linguistic review?

No. Machine output can be a first draft, but it has the same blind spot as a translator without context, and more: it cannot know that "Open" is a status on this screen. Test machine-translated strings exactly like human ones and keep the native-speaker review for anything users see.

References

  • Unicode CLDR ProjectUnicode ConsortiumThe Common Locale Data Repository: the locale data for date, time, number and currency formats and plural rules that most platforms use.
  • Unicode Standard Annex #9: Unicode Bidirectional AlgorithmUnicode ConsortiumThe algorithm that decides the display order of mixed right-to-left and left-to-right text — the source of most bidirectional-text bugs.
  • Inline markup and bidirectional text in HTMLW3CHow the bidirectional algorithm treats inline runs — numbers, names, URLs inside Arabic text — and the markup (bdi, dir) that isolates them.
  • The Unicode StandardUnicode ConsortiumThe universal character set and its encoding forms (UTF-8, UTF-16, UTF-32), normalization and the properties of every code point.

Practise with Mutqan tools

Generate the same records in multiple languages (English, Arabic, Hindi, and more) to test i18n and RTL/LTR mixing.

Test Data

Generate Arabic names, addresses, sentences, numbers (Arabic-Indic digits) and RTL edge cases for localisation testing.

Test Data

Generate Hindi (Devanagari) names, addresses, sentences and numerals for localisation testing.

Test Data

Compare two JSON documents semantically and highlight added, removed and changed values.

JSON & Data

Measure string length in characters, code points, UTF-8 bytes and UTF-16 units.

Formatting

Convert text to Unicode escape sequences (\u0041), code points (U+0041) or HTML numeric entities.

Encoding

Go deeper

Your progress on this topic

Part of the QA Roadmap