How Do I Use a CSS File for Site Localization?

Software localization blog category featured image | Phrase

CSS is surprisingly important when it comes to i18n. Let's take a look at some of the ways we can provide a delightful localized UX for our users using good old Cascading Stylesheets.

🔗 Resource » First things first, give the official W3C document on i18n techniques a read. This is foundational stuff.

Layout direction

One of the most important ways to use CSS when working on a multilingual site is to control page and element layout direction. Some languages are laid out left-to-right, others right-to-left, and they need to be styled differently. Assuming we've designated our language and layout direction on the server. Our <html> tag could look like this:

<html lang="en" dir="ltr">

<!-- or -->

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

We can, then, have default styles that target left-to-right languages, and overrides for right-to-left ones.

sidebar p {

  // default styles

}

[dir="rtl"] .sidebar p {

  // right-to-left overrides

}

Also, consider using non-absolute rules and class names. In older days of CSS, we had to override layout direction using absolute rules.

.menu-item {

  margin-right: 1rem;

}

.menu-item:first-child {

  margin-right: 0;

}

[dir="rtl"] .menu-item {

  margin-right: 0;

  margin-left: 1rem;

}

[dir="rtl"] .menu-item {

  margin-left: 0;

  margin-right: 1rem;

}

This still works, but you might want to avoid the verbosity and confusion of these kinds of overrides and to use the newer logical layout rules.

.menu-item {

  /* Margin at end of text, depending on layout

     direction and writing direction */

  margin-inline-end: 1rem;

}

.menu-item:first-child {

  margin-inline-end: 0;

}

/* No need for directional overrides */

✋🏽 Heads Up » At time of writing, the newer logical rules are considered experimental. Check the Browser Compatibility section on MDN for up-to-date browser support info on these.

Targeting a language

Of course, we could target a specific locale/language if we wanted to as well, which is often handy.

.sidebar p {

  /* default styles */

}

.sidebar p:lang(fr) {

  /* French overrides */

}

/* or */

[lang="fr] .sidebar p {

  /* French overrides */

}

✋🏽 Heads Up » The :lang(en) and [lang="en"] selectors work a bit differently. :lang(en) will match elements whose lang is en, en_US, en_CA, etc. [lang="en"] will only match en specifically. Moreover, :lang() is a pseudo-selector, and will match an element even if it inherits its language from an ancestor. The W3C has a good article on the subject.

Injecting localized content

Sometimes it's convenient to inject a small amount of content in our pages with CSS. We can combine pseudo-elements and the :lang() pseudo-selector to inject our content in a localized way.

p:lang(en)::before {

  content: "Hello ";

}

p:lang(ar)::before {

  content: "أهلاً ب";

}

Using localized fonts

We can prefer system fonts to ensure maximum character coverage for our internationalized websites. We could also use language selectors to specify a font family per-locale.

// default

body { font-family: sans-serif; }

:lang(en) { font-family: Times, serif; }

:lang(ar) { font-family: Tahoma, sans-serif; }

And if you want an efficient and happy i18n workflow, where you focus on your business logic, check out Phrase. An all-in-one i18n platform, built by developers for developers, Phrase wires into your development tooling with an API and CLI. The platform also features over-the-air (OTA) translations (no more App Store reviews just to update some UI labels), supports a ton of web, mobile, and desktop stacks, and even gives you GitHub, GitLab, and Bitbucket sync. Put your i18n on autofill and get the creative code you love. Check out all of Phrase's features, and try Phrase for free.