InternationaliZSation MPain Points

By Manvel Saroyan

Me + i18n

Localizsation

Date

Date: 12/11/2018


  const date = new Date(2018, 10, 12);
  console.log(new Intl.DateTimeFormat('en-GB').format(date));
  console.log(new Intl.DateTimeFormat('en-US').format(date));
  console.log(new Intl.DateTimeFormat('lt-LT').format(date));
  console.log(new Intl.DateTimeFormat('hy-AM').format(date));
  

12/11/2018
11/12/2018
2018-11-12
12.11.2018

Decimal separators

Number: 1234567.89


  const number = 1234567.89;
  console.log(new Intl.NumberFormat('en-US').format(number));
  console.log(new Intl.NumberFormat('fr-FR').format(number));
  console.log(new Intl.NumberFormat('de-CH').format(number));
  console.log(new Intl.NumberFormat('es-ES').format(number));
  

en-US: 1,234,567.89
fr-FR: 1 234 567,89
de-CH: 1’234’567.89
es-ES: 1.234.567,89

Order

  • Bob
  • Nika
  • Yves

  const items = ["Bob", "Nika", "Yves"];
  console.log(items.sort((a, b) => a.localeCompare(b)));
  console.log(items.sort((a, b) => a.localeCompare(b, 'lt')));
  

Accessibility

lang attribute

Declares default language of the document


    <html lang="de"></html>
    

hreflang


  <a href="/de/documentation" hreflang="de">Dokumentation</a>
  <a href="/en/address" hreflang="en">Address</a>
  

  a[hreflang]:after
  {
    content: "["attr(hreflang)"]"; 
    color: #999;
    vertical-align: super;
    font-size: 50%;
  }
    

Dokumentation
Address

Accept-Language header


  Accept-Language : en-US,en;q=0.9,ru-RU;q=0.8,ru;q=0.7,
                    hy-AM;q=0.6,hy;q=0.5
  

  console.log(navigator.languages); // ["en-US", "ru", "es"]
  

q - Weight of the locale

Attributes


  
  

Directions


  <html dir="rtl"></html>
  

  .vert { writing-mode: vertical-lr; }
  

Directions


    <html>
    

  .hamburger
  {
    position: absolute;
    right: 10px;
    top: 10px;
  }
  

  .hamburger
  {
    position: absolute;
    right: 10px;
    top: 10px;
  }
  [dir="rtl"] .hamburger
  {
    left: 10px;
    right: 0;
  }
  

  header
  {
    display: flex;
  }
  #menu-items
  {
    list-style: none;
    display: flex;
    flex-grow: 1;
  }
  

Layouts designed for the fixed width


  button
  {
    width: 120px;
  }
  

  button
  {
    /* width: 120px; */
    padding: 0 10px;
  }
  

  .message-next-to-button
  {
    margin-right: 100px;
  }
  

  .message-next-to-button
  {
    /* Use with precaution  */
    margin-inline-end: 100px; 
    -webkit-margin-end: 100px;
  }
  html:not([dir="rtl"]) .message-next-to-button
  {
    margin-right: 100px;
  }
  html([dir="rtl"]) .message-next-to-button
  {
    margin-left: 100px;
  }
  

Fonts

Supported by target languages

Consider fallbacks

Make use of unicode Ranges

350kb woff2
1.1mb ttf

Unicode range (5-18kb)


  @font-face {
    font-family: 'Source Sans Pro';
    font-style: normal;
    font-weight: 300;
    src: local('Source Sans Pro'), url("300/cyrillic.woff2") format('woff2');
    unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
  }
  

  # https://github.com/fonttools/fonttools
  pyftsubset DejaVuSans-ExtraLight.ttf --unicodes=U+0530-058F --flavor=woff2 --output-file=armenian.woff2
  
https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,700&subset=cyrillic,cyrillic-ext,greek,greek-ext,latin-ext,vietnamese

SEO

Translate page title and description


  <head>
    <title>Surfez sans désagrément</title>
    <meta name="description" content="Adblock Plus est le bloqueur de publicités le plus populaire">
  </head>
  

rel-alternate-hreflang


  <html lang="de">
  <head>
    <link rel="alternate" href="http://www.example.com/en" hreflang="en">
    <link rel="alternate" href="http://www.example.com/es" hreflang="es">
  ...
  <head>
  

Use canonical for duplicate content


  
  

SMM/SMO


  
  
  

  
  
  
  

Internationalization

Translation files

JSON

XML

.po, .pot

Translation strings

String ID

Description

Message/Text


  /* /en/menu/header.json */
  {
    "menu-item-about": {
      "description": "Menu item label located in the header",
      "message": "About us"
    }
  }
  

  /* /ru/menu/header.json */
  {
    "menu-item-about": {
      "description": "Menu item label located in the header",
      "message": "О нас"
    }
  }
  

Using translation strings

Reference translation file

Referrence StringID


  getText("stringId", "filePath")
  

  {stringId(filePath)}
  

  
  • {menu-item-about(menu/header)}

  
  • About us

  
  • О нас

  
  • Մեր մասին

Word order


    I love you
  

I love you [SVO ~42%]

I you love [SOV ~45%]

love I you [VSO ~9%]

love you I [VOS ~3%]

you I love [OVS ~1%]


  {
    "like-button-title": {
      "message": "je t'aime"
    }
  }
  

  {
    "like-button-title": {
      "message": "eu te amo"
    }
  }
  

  {
    "like-button-title": {
      "message": "Ես քեզ սիրում եմ"
    }
  }
  

Fixed

Fixed terms

Brand names

Usernames


    "whitelisted_notification": {
      "message": "$domain$ was whitelisted",
      "placeholders": {
        "domain": {
          "content": "$1",
          "example": "www.example.com"
        }
      }
    }
    

    getMessage("whitelisted_notification", ["www.example.com"]);
    

www.example.com was whitelisted


  {fixed-id <fix>CMintS</fix> uses <fix>fix</fix> tag}
  

  "fixed-id": {
    "message": "<fix2> тэг используется <fix1>-ом"
  }
  

  fix тэг используется CMintS-ом
  

Structure

  • Locales
  • Layouts/Themes
  • Pages/Content

  locales
  ├── de
  │   ├── about.json
  │   └── header.json
  ├── en
  │   ├── about.json
  │   └── header.json
  └── ru
      ├── about.json
      └── header.json
  

  theme
  ├── layouts
  │   ├── default.ejs
  │   └── home.ejs
  └── less/sass
      ├── _header.less
      ├── index.less
      └── main.less
  

  pages
  ├── about
  │   └── team.md
  ├── about.md
  ├── index.ejs
  └── news.md
  

Create a simple website

  • Static content generation
  • Templating engine
  • Front Matter
  • Preprocessors (LESS or SASS)
  • i18n
    • Layout
    • TMS integration
    • Markdown

Pages

Serve page per locale


  // From Hexo website
  /en/index.html
  /zh-tw/index.html

  // From Hugo website
  /content/about.md
  /content/about.fr.md
  

Markdown page


  ## Translation strings

  The translation strings can be defined in the source files by placing them
  inside of opening and closing curly braces. Translation string consist of
  stringId, optional description and source text:

  ## Heading IDs in markdown

  Markdown headers are automatically getting ID set to them, for the future
  reference and TOC generation, whenever a translation string is used as a
  markdown heading element text translation StringID is used as a header ID.
  

{StringId[Description] Message}


  ## {translation-strings[Page heading] Translation strings}

  {translation-strings-p[Paragraph in 'Translation strings' section]
  The translation strings can be defined in the source files by placing them
  inside of opening and closing curly braces. Translation string consist of
  stringId, optional description and source text:
  }

  ## {markdown-heading-id[Page heading] Heading IDs in markdown}

  {markdown-heading-id-p[Paragraph in 'Heading IDs in markdown' section]
  Markdown headers are automatically getting ID set to them, for the future
  reference and TOC generation, whenever a translation string is used as a
  markdown heading element text translation StringID is used as a header ID.
  }
  

Translation management tools

Comprehensive i18n website development tool

Lightweight and simple

Out of the box

CMintS

https://cmints.io/

Resources

Libraries/Frameworks

Resources

Follow/Contact

Thanks for attention!

Table Of Content