I18n in the Repository — sling:Message

Within Sling, translations are stored in the repository as key/value pairs. Structure:

/apps/matrix/i18n
+-- en (nt:folder, mix:language)
|    +-- jcr:language = "en"
|    +-- hello_world (sling:MessageEntry)
|    |    +-- sling:key = "hello_world"
|    |    +-- sling:message = "Hello world!"
|    +-- goodbye (sling:MessageEntry)
|         +-- sling:key = "goodbye"
|         +-- sling:message = "Goodbye!"
|
+-- fr (nt:folder, mix:language)
     +-- jcr:language = "fr"
     +-- hello_world (sling:MessageEntry)
     |    +-- sling:key = "hello_world"
     |    +-- sling:message = "Bonjour tout le monde!"
     +-- goodbye (sling:MessageEntry)
          +-- sling:key = "goodbye"
          +-- sling:message = "Au revoir!"

I18n in the Repository — JSON Files

Alternatively, translations can be stored as JSON files with a special mixin:

/apps/matrix/i18n
+-- en.json (nt:file, mix:language)
|    +-- jcr:language = "en"
|    +-- jcr:content (nt:resource)
|         +-- jcr:data (JSON file data)
|
+-- fr.json (nt:file, mix:language)
     +-- jcr:language = "fr"
     +-- jcr:content (nt:resource)
          +-- jcr:data (JSON file data)

JSON format is a flat key/value map:

{
  "matrix.appTitle": "Matrix App Title"
}

Note: Nested objects with hierarchical keys are not supported by Sling. Use flat key/value JSON files directly.

Applying i18n in HTL

<!-- Simple i18n translation -->
<h1>${'matrix.appTitle' @ i18n}</h1>

<!-- Output: <h1>Matrix App Title</h1> -->

<!-- By default, the language of the current request
     (usually matching the language of the page/site) is used.
     Optionally you can pass a locale value as parameter. -->

i18n with Placeholders

<!-- JSON definition: -->
<!-- { "matrix.appTitle": "My {0} Title" } -->

<!-- HTL with format option: -->
<h1>${'matrix.appTitle' @ i18n, format=['Shiny App']}</h1>

<!-- Output: <h1>My Shiny App Title</h1> -->