Localization and RTL Bug Reports

Written By  Crosscheck Team

Content Team

August 1, 2026 9 minutes

Localization and RTL Bug Reports

Localization and RTL bug reports

A tester in Cairo opens https://staging.example.com/ar/checkout. The page loads right to left, which is correct. But the progress bar still fills from left to right, and the "next" arrow still points right, which now means "back". She files a ticket that says "Arabic page looks wrong".

The developer opens the page in English, sees nothing wrong, and closes it as "cannot reproduce".

Localization bugs die like this every week. The fix is not more effort. It is naming the locale, the string, and the exact rule that broke.

Short version

  • Localization (l10n) means adapting your product for a language and region. A locale is that language plus region, written as a code like de-DE.
  • RTL means right-to-left languages such as Arabic and Hebrew, where text and layout run the other way.
  • The five bug families are text expansion, RTL mirroring, date and number formats, missing translations, and hardcoded strings.
  • Always attach the locale code, the string key, and a screenshot next to the English one.
  • Pseudo-locale testing finds most of these before real translations exist.

The words you need first

Localization (l10n) is the work of making your product fit a language and a region. Not just translation. Also dates, numbers, currency, and layout direction.

Locale is a language plus a region, written as a code: de-DE is German in Germany, ar-EG is Arabic in Egypt, ja-JP is Japanese in Japan. Region matters. en-US and en-GB are both English, and they format dates differently.

RTL stands for right-to-left. Arabic, Hebrew, Persian, and Urdu are read from right to left. The whole interface flips, not just the words.

String key is the name a developer gives a piece of text in the translation file, for example checkout.button.submit. You will see these keys in bug reports and sometimes on screen when a translation is missing.


Family 1: text expansion

English is short. Most other languages are not.

German and Finnish strings run about 30 to 40 percent longer than English. A short English word can triple. "Settings" becomes "Einstellungen". "Cancel" becomes "Abbrechen".

This breaks three things:

  1. Buttons. The text is wider than the button, so it wraps to two lines or spills over the edge.
  2. Truncation. The text is cut with an ellipsis, so the user reads "Zahlungsmethode hinzu…" and cannot tell what the button does.
  3. Overlap. A long label pushes into the field next to it, and the two sit on top of each other.

Bad: German text is too long

Good: checkout.button.add_payment overflows the button by 42px in de-DE on https://staging.example.com/de/checkout

The second one gives the developer a key to search for and a page to open.

Watch the short strings hardest. Long paragraphs wrap fine. Two-word buttons, table headers, and menu items are what break.


Family 2: RTL mirroring

In an RTL locale, most of the interface mirrors. The sidebar moves to the right. Text aligns right. Padding swaps sides. Arrows point the other way.

Common RTL bugs:

  • Layout does not mirror at all, because a stylesheet uses margin-left instead of a direction-aware property.
  • Icons do not mirror. A "next" arrow still points right, so it now reads as "back".
  • Progress bars and sliders still fill left to right.
  • Text aligns left inside an otherwise mirrored page.
  • Mixed content breaks. An Arabic sentence with an English brand name in it puts the punctuation in the wrong place.

Now the part people forget. Some things must not mirror:

  • Phone numbers. +20 100 555 0142 stays in that order.
  • Numbers and code samples.
  • Media controls. The play button still points right in every locale.
  • Logos and product screenshots.
  • Clock icons and musical notation.

So "the play button is backwards in Arabic" is a real bug, and so is "the play button did not mirror" being reported as a bug when it is correct. Say what you expected and why.

Good: Progress bar in ar-EG fills left to right. Expected right to left, matching the page direction (dir="rtl").


Family 3: date, number, and currency formats

This family causes the most silent damage, because nothing looks broken. The number is just wrong.

08/01/2026 means 1 August 2026 in en-GB and 8 January 2026 in en-US. If your invoice screen hardcodes one order, half your users read the wrong date and nobody files a ticket for months.

Things that change per locale:

Whaten-USde-DEar-EG
Date8/1/202601.08.2026٠١‏/٠٨‏/٢٠٢٦
Number1,234.561.234,56١٬٢٣٤٫٥٦
Currency$1,234.561.234,56 €‏١٬٢٣٤٫٥٦ ج.م.‏
First day of weekSundayMondaySaturday

Note the decimal comma in German. 1.234,56 is one thousand two hundred thirty four point five six, not one point two three. If your input field rejects a comma, German users cannot type a price.

Also check currency position. The dollar sign goes before the amount. The euro sign goes after it, with a space.

When you report one of these, always write both the value you saw and the value you expected.

Good: Order total shows 1,234.56 € in de-DE. Expected 1.234,56 € (decimal comma, thousands dot).


Family 4: untranslated strings and missing keys

Three different bugs look similar on screen.

Raw key showing. You see checkout.button.submit instead of a word. The key exists in the code but not in the translation file. This is the easiest one to fix, and the easiest to report: copy the key exactly.

English fallback. The page is German but one button says "Submit". The key is missing and the app falls back to English. Less obvious, so scan for it deliberately.

Wrong translation. The words are German but wrong for the context. "Submit" translated as the verb for surrendering, not sending a form. A tester who speaks the language has to catch this one.

Hardcoded strings are the fourth case, and the worst. The text sits inside the code, so it never reaches the translation file at all. It will be English in every locale forever. Common places: error messages, alert() text, placeholder text, aria-label values, and email subjects.

Concatenated sentences break translation in a quieter way. Code that builds a sentence by joining pieces looks fine in English and falls apart elsewhere, because word order changes. "You have " + count + " new " + itemType cannot be translated properly. Report the visible symptom and mention that the sentence looks assembled from parts.


Pseudo-locale testing

A pseudo-locale is a fake language your app can switch to. It takes your English text and pads it, adds accents, and wraps it in markers. "Checkout" becomes [!!! Ĉĥéçķöûţ !!!].

It is still readable in English, so anyone on the team can test it. And it does three jobs at once:

  1. Finds text expansion. The padding makes every string longer, like German or Finnish. If a button breaks in the pseudo-locale, it will break in real German.
  2. Finds hardcoded strings. Any text still in plain English, with no accents and no brackets, never went through the translation system. It stands out immediately.
  3. Finds concatenation. A sentence built from pieces shows brackets in the middle, like [!!! Ýöû ĥåvé !!!] 3 [!!! ñéŵ !!!].

The best part is timing. You can run pseudo-locale tests weeks before a single real translation arrives. Most localization bugs are found and fixed before the translators start.

Pseudo-locale screenshots are strong evidence for another reason: a developer who speaks no German can look at the image and see the problem instantly. There is nothing to translate and nothing to argue about.


What a good localization bug report includes

Every localization report needs these, on top of your normal steps to reproduce:

  1. Locale code. ar-EG, not "Arabic".
  2. URL with the locale in it. https://staging.example.com/de/checkout
  3. String key. checkout.button.submit
  4. Source string. The English text.
  5. Translated string. Exactly what appeared, copied not retyped.
  6. Expected behaviour. The rule, not just "should be correct".
  7. Browser language settings. Some apps pick the locale from the browser, not the URL. Say what yours was set to.
  8. Two screenshots side by side. The English one and the broken one, at the same window width.

That last point is what turns a "cannot reproduce" into a fix. The comparison shows the bug even to someone who cannot read the language.

Screenshots and environment details are the parts people skip when they are testing eight locales in an afternoon. Tools like Crosscheck capture the screenshot, console logs, network requests, and browser settings when you report the bug from the page, which leaves you only the locale-specific fields to fill in.


A copy-paste template

Title: [Problem] in [locale] on [page]

Locale: de-DE
URL: https://staging.example.com/de/checkout
Browser language: de-DE, Chrome 141 on Windows 11
Tester: [email protected]

String key: checkout.button.add_payment
Source (en-US): Add payment method
Translated (de-DE): Zahlungsmethode hinzufügen

Steps
1. Set browser language to German.
2. Open https://staging.example.com/de/checkout
3. Look at the payment section.

Expected
Button grows or text wraps. Full label stays readable.

Actual
Label is cut to "Zahlungsmethode hinzu…". Button width is fixed at 180px.

Console
No errors.

Attachments
- de-DE-checkout.png
- en-US-checkout.png (same window width, 1440px)
- pseudo-locale-checkout.png

Fill in what applies. A report with the locale code, the key, and two screenshots already beats most of what lands in the tracker.


Frequently asked questions

Do I need to speak the language to test it? No, for layout, format, and expansion bugs. Yes, for translation quality. Pseudo-locale testing covers most of the first group without any language skills.

Which locales should I test if I cannot test all of them? Pick four: German for text expansion, Arabic for RTL, Japanese for line breaking and short text, and en-GB for date formats. That set catches most problems.

Is a truncated label really a bug? Yes, when the user cannot tell what the control does. "Zahlungsmethode hinzu…" fails that test. A cut-off paragraph with a "read more" link does not.

Should I file one ticket per locale or one per problem? One per problem. If the same button overflows in German, Finnish, and Russian, that is one bug about a fixed-width button. List every affected locale in the description.

How do I know if something should mirror in RTL? Ask whether the meaning depends on real-world direction. Reading order mirrors. Physical objects such as play buttons, clocks, and phone numbers do not.

Related Articles

Contact us
to find out how this model can streamline your business!

Trusted by thousands ofengineering teams worldwide.

Add to Chrome
200+ reviews · 100k+ users
Crosscheck browser extension capture controls

Join the Crosscheck Community

Stay in the loop with Crosscheck's newest features and insights.