没有不值得去解决的问题,也没有不值得去学习的技术!

My First RTL Tour of Go: Launching the Arabic Version and the Pitfalls I Hit

[Figure 4: Result after fixing the RTL desktop course layout]

作者:

在

Recently, I continued adding new languages to my A Tour of Go multilingual project.

This time, the language was:

Arabic / العربية / Arabic

Official URL:

https://ar-go-dev.shuijingwanwq.com

Project repository:

https://github.com/shuijingwan/go-tour-i18n

Compared to the German, French, Japanese, Korean, Spanish, Italian, Dutch, Portuguese, Turkish, Swedish, Polish, Traditional Chinese, Indonesian, and Vietnamese versions I did before, this language has one very obvious difference:

This is the first RTL (Right-to-Left) language in the project.

Because of this, what actually took time this time was not just the translation.

If you simply view a new language as “translating English into another language,” Arabic might not seem particularly complex. But once it actually enters the web pages, code editors, navigation, mobile layouts, course catalogs, SEO, ads, and Production, RTL exposes all the layout assumptions originally hidden in LTR pages.

This article mainly documents the process of supporting RTL for the first time, along with the actual problems I encountered.


1. First, the final result

The Arabic homepage is now displayed correctly in an RTL direction.

[Figure 1: Final RTL result for the Arabic homepage]
[Figure 1: Final RTL result for the Arabic homepage]

The course catalog page also adopted a right-to-left reading direction.

[Figure 2: RTL result for the Arabic A Tour of Go course catalog]
[Figure 2: RTL result for the Arabic A Tour of Go course catalog]

On the surface, this seems to just be:

HTML
<html lang="ar" dir="rtl">

Then letting the browser handle the direction itself.

In practice, it is far from that simple.


2. The translation process itself didn’t change much

Arabic still reused the project’s relatively mature official translation process.

Currently, a language roughly goes through:

Plaintext
locale initialization
→ glossary
→ UI / article metadata
→ TranslationUnit generation
→ automatic validation
→ Candidate Snapshot
→ independent TranslationUnit Quality Check
→ revision
→ QC all A
→ promotion
→ Course SEO
→ Locale Surface Review
→ Preview
→ HUMAN visual gate
→ publish
→ Production
→ Google / Bing / IndexNow

The TranslationUnits are still:

  • 103 Pages
  • 19 Examples
  • 122 Units total

This part is essentially no different from languages like Vietnamese or Indonesian.

Arabic only really started getting complex after the translation was completed.


3. Encountering real RTL layout issues for the first time

The most obvious issue occurred on the desktop course page.

The A Tour of Go course page itself uses a typical two-column layout:

Plaintext
Course content | Code editor

In a normal LTR page:

Plaintext
Left: lesson
Right: editor

This layout has worked fine over the past few years.

But the first time it switched to RTL, the page immediately exposed a problem:

The course content area and the code editor visibly overlapped.

[Figure 3: Desktop course area and editor overlapping after enabling RTL for the first time]
[Figure 3: Desktop course area and editor overlapping after enabling RTL for the first time]

The problem wasn’t simply a text text-align:right.

The original layout actually contained many “physical direction” assumptions, such as:

CSS
left: 50%;
float: left;

These rules were fine in LTR pages, but once the entire document entered RTL:

  • The content flow direction changed;
  • The positioning logic of some elements still followed physical left/right;
  • The two sets of direction logic overlapped, causing the overlap.

The final direction for the fix was:

The course layout should use logical directions, rather than continuing to assume that the lesson is always on the physical left and the editor is always on the physical right.

Ultimately:

Plaintext
LTR
lesson: left
editor: right

RTL
lesson: right
editor: left

After the fix, the Arabic desktop course page returned to normal.

[Figure 4: Result after fixing the RTL desktop course layout]
[Figure 4: Result after fixing the RTL desktop course layout]

This was also the first time I clearly felt:

RTL support isn’t just “flipping text”; it’s re-evaluating what belongs to the “reading direction” and what belongs to a “fixed technical direction” across the entire page.


4. The course catalog and language menu also had to truly adapt to RTL

The course catalog page and the in-course table of contents menu also needed to be read naturally starting from the right side.

[Figure 5: Arabic course catalog and chapter navigation]
[Figure 5: Arabic course catalog and chapter navigation]

The language menu was the same.

[Figure 6: Language selection menu in the RTL page]
[Figure 6: Language selection menu in the RTL page]

There is an easily overlooked issue here:

Not everything should follow RTL.

For example:

  • Arabic text: RTL
  • Page navigation: RTL
  • Course chapter relationships: RTL
  • Go source code: must remain LTR
  • URLs: usually remain LTR
  • Technical identifiers: should not be rearranged by the browser as normal Arabic text

In other words, a page actually contains two sets of directions simultaneously.


5. The Arabic page is RTL, but the Go code must still be LTR

This is particularly important.

The code editor cannot just turn into RTL because the entire page is set to:

CSS
direction: rtl;

and follow along.

Go code:

Go
package main

import "fmt"

func main() {
    fmt.Println("Hello")
}

Regardless of the page’s language, the logical direction of the code should remain:

Plaintext
Left → Right

Therefore, CodeMirror, the source code area, and the related editor must explicitly remain LTR.

[Figure 9: Go code remaining LTR in the RTL course page]
[Figure 9: Go code remaining LTR in the RTL course page]

The final page actually became a hybrid layout:

Plaintext
Page structure: RTL
Natural language: RTL
Code editor: LTR

This is much more reasonable than simply “flipping the entire page”.


6. A more hidden issue appeared on mobile

After fixing the desktop, I originally thought RTL was basically handled.

As a result, a new issue was found during the mobile HUMAN visual gate:

The code editor was only about 143px wide.

[Figure 7: Editor abnormally squeezed narrow in RTL mobile]
[Figure 7: Editor abnormally squeezed narrow in RTL mobile]

This problem initially looked like the editor itself was missing:

CSS
width: 100%;

So it was tempting to just add a width patch to the editor.

But after further investigation, I found the real root cause wasn’t in the editor.

In the original mobile design, the action buttons above the editor were supposed to be:

Plaintext
One button
One line

One button
One line

One button
One line

The original CSS used in the mobile breakpoint:

CSS
float: none;

But a new high-priority rule added for RTL changed some buttons to:

CSS
float: left;

As a result, these floats broke out of the original layout.

Subsequently, to avoid the floating elements, the editor was squeezed into a very narrow area by the browser.

In other words:

It looked like an editor width issue, but the real root cause was that the buttons above unexpectedly restored float under RTL.

Ultimately, I didn’t just force it through with:

CSS
#file-editor {
    width: 100%;
}

Instead, I fixed the actual responsive logic:

  • Desktop RTL can use the corresponding float as needed by the layout;
  • mobile always restores float:none;
  • continues to keep one button per line;
  • the editor naturally fills the parent container.

After the fix, the mobile version returned to normal.

[Figure 8: Editor restoring full width after fixing RTL mobile float]
[Figure 8: Editor restoring full width after fixing RTL mobile float]

This issue was also the most typical one this time:

Don’t just write width:100% wherever something gets narrow.

Sometimes the real problem comes from a sibling element preceding it.


7. RTL also changes the linguistic semantics of “left” and “right”

There was another rather interesting issue this time.

The A Tour of Go Welcome page tells users:

  • Where the previous page is;
  • Where the next page is;
  • What arrows to use for navigation.

The original Arabic TranslationUnit translation itself had no linguistic errors.

But during the initial review, the entire Tour still basically ran on an LTR UI, so the descriptions of “left arrow” and “right arrow” in the translation were based on the actual interface at the time.

Later, after the RTL layout was actually completed:

The physical direction of the page changed.

This meant that a sentence which had already passed translation review became inaccurate again due to the UI behavior change.

So this time, I had to rerun:

Plaintext
TranslationUnit revision
→ validation
→ Candidate Snapshot
→ independent QC
→ A
→ promotion

Subsequently, because the Page identity changed, it continued to trigger:

Plaintext
Course SEO refresh
→ Locale Surface Review r2

This served as a reminder to me:

Language quality is not completely independent of the UI.

Especially for the following words:

Plaintext
left
right
above
below
previous
next
top-left
top-right

As long as the layout changes, they can go from a “correct translation” to an “incorrect description”.


8. The first RTL also forced me to re-verify LTR

After modifying the shared CSS, I didn’t just proceed to launch Arabic.

Because this modification was to:

Plaintext
shared layout
shared app.css

Verifying only Arabic was not enough.

So I separately started a full French projection to regress the existing LTR pages.

Focus on confirming:

  • desktop lesson/editor was not adversely affected;
  • mobile editor width was normal;
  • Run / Format / Reset were normal;
  • CodeMirror was normal;
  • PageUp / PageDown were normal;
  • existing LTR layout did not degrade.

The French test ultimately passed.

Although this step added some time, I felt it was very necessary.

Because the first RTL language was actually no longer simply:

“adding a new locale”

But rather doing:

“modifying the layout infrastructure reused by all locales”.


9. While testing PageUp / PageDown, I incidentally found an upstream issue

While comparing keyboard shortcuts for French and Arabic, I noticed another phenomenon:

Sometimes:

Plaintext
PageDown

was very responsive, turning exactly one page per press.

Sometimes it seemed to stop working.

At first I suspected:

Did RTL introduce some keyboard event issue again?

Later, after running automated tests, I found it wasn’t.

In French and Arabic:

Plaintext
12 consecutive PageDowns

As long as the focus remained in the editor / lesson area, it could achieve:

Plaintext
12 / 12

The issue was truly related to the focus position.

For example, if the focus was on:

Plaintext
CodeMirror textarea

PageDown:

Plaintext
/tour/welcome/1
→ /tour/welcome/2

Worked normally.

But when the focus was on the top:

Plaintext
Toggle theme

or:

Plaintext
A Tour of Go Logo

PageDown would not turn the page.

More interestingly, I then directly tested the official:

https://go.dev/tour/welcome/1

The result was also reliably reproducible.

Therefore, it can be confirmed:

This is not an Arabic or an RTL bug, but a general focus dependency issue that exists in the current official A Tour of Go.

Finally, I submitted to the official Go project:

https://github.com/golang/go/issues/81596
[Figure 10: Submitting the PageUp / PageDown focus issue to Go upstream as Issue #81596]
[Figure 10: Submitting the PageUp / PageDown focus issue to Go upstream as Issue #81596]

The local project temporarily didn’t maintain a fork-specific patch for this issue, but instead recorded it as a Deferred Issue, waiting for upstream to handle it.

This is also the maintenance approach I tend to prefer now:

If an issue can be confirmed as upstream, try to send it upstream first, rather than adding long-term divergence in your own fork every time you encounter a problem.


10. The first RTL language ultimately took about 7 hours

For the previous language, Vietnamese, I actually spent about:

5 hours.

Arabic took about:

7 hours.

The extra time was about:

2 hours.

Which is an increase of about:

40%

However, these 2 hours weren’t because the Arabic text itself was much harder to translate.

The actual increase was mainly from:

Plaintext
RTL desktop layout
RTL mobile responsive layout
direction-sensitive TranslationUnit revision
Course SEO refresh
second round of Locale Surface Review
LTR regression
PageUp/PageDown upstream diagnosis
shared-assets deployment

Additionally, during the Production publish, I hit a local /tmp tmpfs quota:

Plaintext
disk quota exceeded

Finally, after cleaning up about:

Plaintext
4.4G

of historical Go build / gocache temporary directories, the publish succeeded.

Therefore, a more accurate understanding of these 7 hours should be:

The first RTL locale + the one-time RTL infrastructure construction cost.

It should not be simply understood as:

Arabic will always take 40% longer than Vietnamese.


11. The next RTL language shouldn’t take as long

After completing this, the project now has a relatively complete RTL foundation for the first time.

Including:

Plaintext
HTML dir=rtl
desktop lesson/editor mirrored layout
RTL splitter
mobile explorer controls
mobile editor full-width
CodeMirror LTR
RTL course navigation
RTL language selector
RTL browser regression
LTR shared-layout regression

So if I add:

  • Hebrew
  • Persian
  • Urdu

For these types of RTL languages, at least the infrastructure level no longer needs to be built from scratch.

Of course, different languages may still expose new issues.

But I expect the cost of the next RTL locale to realign with a normal locale.

My current actual baseline can roughly be noted as:

Plaintext
Mature LTR locale: about 5 hours
First RTL locale: about 7 hours

If I do two or three more later, I can further confirm whether this estimate is stable.


12. What was truly important this time wasn’t “launching another language”

After Arabic went live, the A Tour of Go multilingual project of course gained another new production locale.

But for me, what was more important this time was:

The project truly crossed the LTR-only boundary for the first time.

Before this, even with support for over a dozen languages, everyone’s page direction was essentially still the same.

RTL was the first to force me to re-check:

  • left/right in CSS;
  • float;
  • responsive breakpoint;
  • editor direction;
  • UI spatial relationships;
  • directional words in copy;
  • shared assets;
  • LTR regression;
  • browser interaction;
  • HUMAN visual gate.

Many long-standing but never exposed issues were also seen for the first time during this process.

This is also what makes multilingual projects more interesting as you go further:

At the very beginning, you are doing:

Translation.

As you continue, it gradually becomes:

Internationalization engineering.

Continuing further, you are actually maintaining:

A long-term publishing system that allows different languages, different text directions, and different search markets to work together.

And Arabic marks this project’s first true entry into the RTL world.

系列导航

关于作者 · 持续学习与技术实践

我是一名拥有 15 年以上开发经验的技术从业者,自 2013 年起持续运营个人技术博客,记录工作与个人项目中遇到的真实问题,以及解决问题过程中的探索、实践和思考。

除了技术写作,我也在持续开发和维护自己的独立项目,探索新技术和新工具在实际场景中的应用。我始终相信,没有不值得去解决的问题,也没有不值得去学习的技术。

如果这篇文章对你有所帮助,欢迎浏览博客中的其他文章,也欢迎交流技术经验与想法。

关于我  ·  GitHub  ·  邮件联系