Internationalization

Cloud Phone Internationalization

Internationalization (i18n)

Why does it matter? Internationalization maximizes your application’s reach among a global user base, giving you the largest available addressable market. Without internationalization, users may be unable to fully utilize an otherwise valuable service.

What is i18n? Internationalization (abbreviated i18n) encompasses translation, iconography, colors, formatting, information architecture, and anything that enables users from different countries, cultures, and who speak different languages, to understand and use your product.

Translations

Translations are the first and most obvious component of Internationalization. Translations are stored as Unicode strings either bundled into application code or dynamically loaded from an external service.

Cloud Phone has the same extensive Unicode support as Chrome.

Bundled Strings

Bundled strings are stored and packaged within your app’s codebase at build time. Each locale is compiled into the final bundle.

Advantages

  • Simplicity: No asynchronous calls or error handling needed
  • No Latency: No waiting for HTTP requests to load strings

Disadvantages

  • Increased Bundle Size: Bundling all locales can significantly increase application file size
  • Memory Overhead: Unused locales consume memory without user benefit

Lazy Loading

Lazy loading fetches locale-specific strings over HTTPS at runtime based on app settings or browser locale.

Advantages

  • Smaller Payload: Only the necessary strings are loaded
  • Flexibility: New translations can be added without rebuilding the application

Disadvantages

  • HTTP Latency: Network requests can introduce unpreditcable delays
  • Error Handling: Error handling is needed for failed or slow network responses
  • Cache Management: Requires proper cache invalidation to receive latest strings

Recommendation

Use the method that best suits your needs. Because Cloud Phone is rendered on powerful servers, the increased bundle size and memory footprint are imperceivable to end users. Smaller apps find bundled strings easier to implement, while large cross-platform apps may prefer to manage translations independently without rebuilding and publishing updates.

Language

Chrome Preferred Language Setting

Detecting User Language

The navigator global includes two properties to detect the user’s language: navigator.language and navigator.languages.

console.log(navigator.language); // e.g., 'en-US'
console.log(navigator.languages); // e.g., ['en-US', 'fr-FR']

Multiple Languages

43% of the global population is bilingual, speaking two languages. A further 17% are multilingual, speaking three or more languages. In recognition of multilingualism, the navigator.languages (plural) property was introduced to Chrome 37 in 2014.

The navigator.languages (plural) array is ordered by preference, with the most preferred language first, matching the value of navigator.language (singular).

Accept-Language Header

The Accept-Language header, sent with all HTTP requests, provides information about the user’s language preferences, including quality values. Servers can parse this sorted list of languages when responding to requests.

// Example of parsing Accept-Language header on the server (Node.js)
const parseAcceptLanguage = (header) => {
  // i.e. en;q=0.9 -> en
  const dropQualityValue = (lang) => lang.split(';')[0].trim();
  return header
    .split(',')
    .map(dropQualityValue);
};

const acceptLanguageHeader = 'en-US,en;q=0.9,fr;q=0.8';
console.log(parseAcceptLanguage(acceptLanguageHeader)); // ['en-US', 'en', 'fr']

By combining navigator.language and the Accept-Language header, developers can create a robust language detection mechanism that accommodates client-side and server-side preferences.

languagechange Event

The languagechange) event is fired when the user’s preferred languages are changed. Cloud Phone uses language preferences from system settings and does not provide its own setting.

The languagechange event is never triggered on Cloud Phone, because the user must exit Cloud Phone in order to access system settings.

GeoIP

Another method to approximate user language is IP address geolocation (GeoIP). Use the X-Forwarded-For header sent with each request to access the user’s IP address since traffic originates from CloudMosa data centers.

Use GeoIP for default language selection only as a fallback for locations where there is a sensible default.

Netherlands

The primary language for 97.5% in the Netherlands is Dutch.

Recommendation: Dutch is a reasonable default for the Netherlands.

India

India has 15+ languages with 1M+ speakers. Hindi is the most common language in India nationally, but its use varies between states. For example, only ~0.5% of the 72M+ people in the state of Tamil Nadu speak Hindi.

Recommendation: Use more granular state-level GeoIP for default language selection in large, linguistically-diverse countries India.

CSS :lang() pseudo-class

Adapt styles for specific languages using the :lang() pseudo-class selector.

/* Applies to elements with the matching lang attribute, and descendents */
*:lang(en-US) {
  color: deeppink;
}

/* Only applies directly to elements with the matching lang attribute */
[lang="en-US"] {
  color: blue;
}

Styles are applied when the CSS selector language code matches the corresponding HTML lang attribute.

<p lang="en-US">Hello, World</p>
<p lang="es-MX">Hola, Mundo</p>

Set language on any HTMLElement in JavaScript using the lang property.

document.body.lang = 'en-US';

The [lang] attribute selector only works if the lang attribute is explicitly set and exactly matches the HTML. On the other hand, the :lang() pseudo-class matches the inherited or implicit language, is case insensitive, and performs fuzzy matching.

  • Dynamic match: :lang() matches both explicitly set lang attributes and inherited language contexts
  • Fuzzy matching: Matches broader language codes based on the prefix. For example, :lang(en-US) matches lang="en-US" as well as lang="en", because en-US is a subtype of en.
  • Case-insensitive: :lang(en-US) matches en-US, EN-us, EN-US, etc.

Nesting

Set the lang attributes within the document for partially-translated websites, user-generated content (UGC), or third-party content. For example, PodLP displays both English and non-English podcasts like No es el fin del mundo, which sets its language to Spanish in the RSS feed using <language>es</language>.

<html lang="en-US">
  <head>
    <title>PodLP - Podcasts for the next billion</title>
  </head>
  <body>
    <header>
      <h1>Top Podcasts</h1>
    </header>
    <section lang="es" dir="ltr">
      <h3>No es el fin del mundo</h3>
      <h5>El Orden Mundial</h5>
    </section>
    <footer>
      <button>Select</button>
      <button>Subscribe</button>
    </footer>
  </body>
</html>

Set the lang attribute whenever your app displays external content.

Content Direction

The default content direction is left-to-right (LTR), used by languages like English, Spanish, and Hindi. Right-to-left (RTL) is used in languages like Arabic, Urdu, and Hebrew.

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

Use the [dir] attribute selector or :dir() pseudo-class to apply styles conditionally:

/* Applies to elements with the matching lang attribute, and descendents */
*:dir(ltr) {
  color: green;
}

*:dir(rtl) {
  color: blue;
}

[dir="rtl"], [dir="rtl"] * {
  color: blue;
}

/* Only applies directly to elements with the matching lang attribute */
[dir="ltr"] {
  color: green;
}

The [dir] attribute selector only works if the dir attribute is explicitly set in the HTML. On the other hand, the :dir() pseudo-class considers the computed text direction including inherited or programmatically determined directions.

Set the text direction in JavaScript using the dir property on any HTMLElement.

// Sets the text direction on the root <html> element
document.documentElement.dir = 'rtl';

Block and Inline Layouts

Use logical properties and values so the browser can automatically adapt layouts to different languages and text directions without restyling individual elements.

  • Use text-align: start instead of text-align: left
  • Use margin-inline-start instead of margin-left
  • Use padding-block-end instead of padding-bottom

Iconography

Mirroring for RTL Locales

Icons and UI elements should often be mirrored for RTL locales, including symbols representing direction, motion, or flow. Cloud Phone provides native CSS support for mirroring.

[dir="rtl"] .icon {
  transform: scaleX(-1);
}

Some icons should not be mirrored including checkmarks, slashes, and icons depicting time like a clock.

Intl API

Cloud Phone natively supports the Intl API without polyfills for robust internationalization.

Formatting Dates and Times

The Intl.DateTimeFormat object provides language-sensitive date and time formatting, similar to libraries like Moment.js.

const today = new Date();
const dateParams = {
  weekday: 'long', year: 'numeric', month: 'long', day: 'numeric'
};

const fmtNZ = new Intl.DateTimeFormat('en-NZ', dateParams);
const fmtUS = new Intl.DateTimeFormat('en-US', dateParams);

console.log(fmtNZ.format(today)); // Monday, 6 January 2025
console.log(fmtUS.format(today)); // Monday, January 6, 2025

Number Formatting

The Intl.NumberFormat object provides formatting utilities for numbers and numeric languages.

const fmtEur = new Intl.NumberFormat('fr-FR', {
  style: 'currency', currency: 'EUR'
});

console.log(fmtEur.format(12345.67)); // 12 345,67 €

Intl.NumberFormat supports decimal (default), currency, unit, and percent styles.

Collation for Sorting

The Intl.Collator object provides compare functions to Array.sort for language-sensitive sorting.

const items = ['z', 'a', 'Z', 'A'];
const collator = new Intl.Collator('en', {
  sensitivity: 'base'
});

console.log(items.sort(collator.compare)); // ["a", "A", "z", "Z"]

Pluralization and Message Formatting

Use libraries like Intl.MessageFormat for complex plural rules and interpolations.

Top Markets

Cloud Phone is currently available in 90+ markets around the world.

Countries

Cloud Phone has a strong and growing presence in emerging markets around the world. Top countries include:

  • India
  • Vietnam
  • Bangladesh
  • Philippines
  • Pakistan
  • South Africa
  • Thailand

Languages

Cloud Phone is used in 25+ languages, as of January 2025. The language table below is sorted from most to least common.

CodeLanguage
enEnglish
hiHindi
viVietnamese
mrMarathi
bnBengali
guGujarati
ruRussian
arArabic
taTamil
thThai
frFrench
teTelugu
knKannada
zh-TWTraditional Chinese
urUrdu
paPunjabi
heHebrew
mlMalayalam
asAssamese
tl-TLTagalog (Philippines)
faPersian (Farsi)
pt-PTPortuguese
zh-CNSimplified Chinese
msMalay
es-419Spanish (Latin America)
swSwahili
uzUzbek
ISO Codes

Cloud Phone directly returns the language reported by the underlying operating system. Language and country codes may vary between manufacturers. Country codes may be omitted, or may be inaccurate.

For example, in the table above the language code for Tagalog in the Philippines is reported as tl-TL, instead of tl-PH. tl is the ISO 639-1 language code for Tagalog and TL is the ISO 3166-2 country code for Timor-Leste, not the Philippines.

i18n Tips

  • Localize content for languages common in emerging markets
  • Always let users choose their preferred language
  • Automatically select a reasonable default language
  • Prefer the :lang() and :dir() pseudo-classes because they handle inheritance, are case insensitive, and allow fuzzy matching
  • Use logical properties and values to easily internationalize layout designs
  • Take advantage of the native Intl API for formatting dates, times, quantities, and more

Conclusion

Internationalization enhances user experience and broadens the total addressable market. With extensive native i18n support, Cloud Phone helps you reach the next billion users seamlessly, no matter where in the world they are.