Go to content

This article shares a few key front-end tips for internationalisation that I learned while working on the website rebuild for W3C. It is not a comprehensive guide to internationalisation, and I strongly recommend visiting Internationalisation techniques: Authoring HTML & CSS from W3C.

I also wish to thank Ahmad Shadeed for his invaluable and authoritative website – RTL Styling 101 – and I encourage developers to visit his website for more detailed advice and examples.


Not all fonts work for all languages, so choose fonts that cover all the sets of characters you need for your project. Even better, select fonts that work well for all the languages of the website you are building (i.e. ones that remain legible in each language).

Having a decent set of font fallbacks is particularly important, because font selection is more involved than the browser just choosing the first font in the list that a user has available to them. In fact, font selection happens one character at a time. If a font doesn’t have the glyph needed for a certain character the browser will try the other fonts in the list.

This font lister resource provides a list of fonts available on Windows and Mac operating systems, grouped by script, to help inform decisions about font-family styles. It also includes examples of Google’s Noto fonts, which cover over 1,000 languages.

On changing language direction

CSS Flexbox and Grid are your friends

A challenging aspect of internationalisation is being able to manage both left-to-right (ltr) and right-to-left (rtl) languages, and for the website rebuild for W3C this needed to be handled at the page layout level, not just at the text level.

Text direction is set on the root HTML element using the dir attribute, with the default value being ltr. We can target this in our CSS and use it to change the direction of things like floats, margins and padding etc. to flip our page layouts as needed.

However, if you use flexbox or grid for layout you don’t need to worry so much about this step and can save having to write additional CSS. That’s because both flexbox and grid are based on the writing mode of the document and use this to determine how blocks are laid out on the page. In other words, layouts using flexbox or grid will automatically flip when the root text-direction changes.

CSS Logical Properties too

If you write justify-content: flex-end; then, assuming that the flex-direction hasn’t changed from the default of row, children of the flex container will always sit at the far end; on the right-hand side if the text-direction is left-to-right, and on the left-hand side if the text-direction is right-to-left.

Logical properties use a similar methodology and syntax, allowing us to replace more prescriptive values such as margin-left with the directionally ambivalent margin-inline-start. This means that the margin will always be on the appropriate side relative to the root text-direction, without us having to manually override it using the dir attribute.

Generally speaking – and from an English, left-to-right perspective – styles that would previously involve ‘left’ or ‘right’ in the declaration are replaced with ‘inline-start’ or ‘inline-end’, while styles that involve ‘top’ or ‘bottom’ are replaced with ‘block-start’ or ‘block-end’.

Logical properties cover much more than just margin and padding, however. Width, height, borders, overflow – a range of properties that we previously would declare with respect to directions or dimensions can now be mapped logically. There is a definitive list of CSS Logical Properties and Values on MDN and Adrian Roselli’s CSS Logical Properties article has a handy Codepen which helps to visually understand the mapping change.


When flipping the layout, it’s also important to consider how any icons will be affected. For example, your left-to-right design might use a right-pointing arrow as part of a custom link style. When the text-direction changes, that icon will still be pointing to the right and will look very odd.

I prefer using inline SVGs for icons, and it allows me to combine multiple named paths inside a single SVG file and hide or show the relevant one based on the `dir` attribute. Note that not all icons will need to be changed, as Ahmad explains.


Thinking about links, the default underlining of links does not work very well with Arabic, where part of the characters can be obscured by the underline. Using text-decoration-skip-ink: auto; helps, but it isn’t supported in Safari. However, Safari does support text-underline-offset, allowing us to lower the position of the underline.

Update: August 2022

Many thanks to Jen Simmons for clarifying the availability of text-decoration-skip-ink: auto; in Safari since March 2022, after my W3C work came to an end. Prior to this, text-decoration-skip: auto; has been available since Safari 7 for the same effect.

When linking to a resource that is in a different language, include the hreflang attribute to indicate the language of the resource to which you are linking. If the link text itself is in a different language, make sure that you include the lang attribute as well – the value will be the same for both attributes. Use the language subtag registry to pick the correct value for the relevant language.


Finally, remember to provide translations for any content that is dynamically inserted with JavaScript. When you have spent so much time on the other aspects of your website, you don’t want to get caught out by this!

There are powerful translation libraries available, such as i18next and i18n, which cover advanced functionalities such as interpolation and the management of plurals. That said, if all you need are a few strings to inject in your templates, there’s no need to load up a whole library: a simple JSON object and some regex can do the trick.

Illustration of two tin cans connected via a string. A person is shouting into one tin can, which is as large as the person, and at the other end is the planet Earth.