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.
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>ordir="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.
| Defect | Symptom on screen | Usual cause | How to find it |
|---|---|---|---|
| Wrong meaning (context) | Order status "Open" shown as the command "افتح" | String translated without the screen; one key used in two contexts | Read every short string on its screen; linguistic review with screenshots |
| Untranslated string | "Field is required" in English on the Arabic form | Key missing from the target file; string added late in the sprint | Compare the key sets of source and target files; switch locale and scan errors and emails |
| Broken placeholder | Raw braces "{رقم الطلب}" printed in the shipping message | Placeholder translated, deleted or reordered by the translator | Compare placeholder sets per key; fill every placeholder with a real value in every locale |
| Wrong plural form | Cart badge "2 منتج" instead of "منتجان" | Form chosen with count === 1; message without the CLDR categories | Count table per locale: 0, 1, 2, 3, 11, 100 for Arabic; 0, 1, 2 for Hindi |
| Truncation or overflow | Hindi product name cut inside a syllable, leaving a half consonant with a visible virama | Fixed-width control; longer translation; limit counted in bytes | Realistic long names in every locale; measure against hard limits in the unit the system counts |
| Mixed-direction order | Order id 1042-A shown as A-1042 inside an Arabic sentence | Placeholder value not isolated from the Arabic around it, so its digits and its Latin letter are laid out as separate runs | Fill 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.shippedon screen with1042-A, once the placeholder is fixed: the id displays asA-1042inside 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.itemsas "{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
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.
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": "कोई नहीं"- Compare the placeholder set of each translation with its source string.
- Check each counted message for the plural categories its locale needs.
- Read each short string and ask which meaning the key needs on this screen.
- List the realistic values you would fill into the placeholders to test mixed-direction display.
Show the 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 ProjectThe 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 AlgorithmThe 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 HTMLHow the bidirectional algorithm treats inline runs — numbers, names, URLs inside Arabic text — and the markup (bdi, dir) that isolates them.
- The Unicode StandardThe 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.
Generate Arabic names, addresses, sentences, numbers (Arabic-Indic digits) and RTL edge cases for localisation testing.
Generate Hindi (Devanagari) names, addresses, sentences and numerals for localisation testing.
Compare two JSON documents semantically and highlight added, removed and changed values.
Measure string length in characters, code points, UTF-8 bytes and UTF-16 units.
Convert text to Unicode escape sequences (\u0041), code points (U+0041) or HTML numeric entities.
Go deeper
- Localization TestingLanguage and translation quality
- Localization TestingPseudo-localization: find i18n defects before translation
- RTL Testing for Arabic InterfacesBidirectional text and the Unicode Bidirectional Algorithm
- How to Write a Bug ReportHow to write a bug report developers can act on: the fields that matter, a copy-ready template, a worked example, severity vs priority, and mistakes to avoid.
Your progress on this topic
Not started
Mark the topic complete when you have studied it and done the exercise.
Sign in to track your progress
Mark topics complete, continue where you left off and unlock specialisation exams.