> ## Documentation Index
> Fetch the complete documentation index at: https://docs.activeviam.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Internationalization

Atoti server supports internationalization (abbreviated as i18n).

Depending on internationalization settings, content can
be translated before it is sent to the UI (Atoti UI or XMLA clients, such as Excel).

## Core Features

The following content can be translated depending on the current locale:

* The captions/descriptions of all elements discoverable from Atoti by end users (levels,
  hierarchies, measures, cubes, KPIs, drillthrough columns, and so on).
* The formatted values of measures and drillthrough columns in `CellSet`s returned by data queries.
* The members in cube levels.

## Key Concepts

### Lexicons

A lexicon is a locale-specific mapping that provides the translation for each of its keys.

For instance, a localized project may have a French lexicon for measures that contains:

| key                | value                |
| ------------------ | -------------------- |
| pnl.SUM            | pnl.SOMME            |
| update.TIMESTAMP   | Dernière mise à jour |
| contributors.COUNT | Nombre de faits      |

The translated content is defined across multiple lexicons, grouped by usage, and for each
supported locale. Measure labels have their own lexicon, and so do formatters and miscellaneous
terms, for example.

### Formatter Factory

Formatter factories are the entry point for creating formatters. They are supplied by a context
value, and can as such be specific to the user role and query. The parent interface for formatter
factories is `ICubeFormatterFactory`. There needs to be one formatter factory per locale to support.

#### Base Implementations

The following base implementations are available:

* `CubeFormatterFactory`: a basic implementation that stores its translations in the resources folder or the content server
  (more details [below](#cubeformatterfactory)).
* `MdxCubeFormatterFactory`: the default formatter factory used by the MDX Engine, unless overridden
  by a context value. It reuses the formatters from the `IMdxContext` context value as formatters for
  the cube.
* `IdentityCubeFormatterFactory`: ignores all captions and formatters, used for testing and
  debugging purposes.

#### LocalI18nConfig

The `LocalI18nConfig` class provides a Spring bean to generate formatter factories from
internationalization files in the resource folder of the application.

The internationalization files should each be named after the locale they correspond to. For example,
`i18n/fr-FR` for French, `i18n/zh-CN` for simplified Chinese, `i18n/ja-JP` for Japanese...

#### Custom Formatter Factories

If `LocalI18nConfig` does not satisfy the use case of your project, a custom formatter factory class can be implemented.

Formatter factories are defined as plugin values. As such, a custom formatter factory can be incorporated in an Atoti project by:

1. Implementing an `ICubeFormatterFactory` plugin, responsible for creating an `ICubeFormatter` for
   every query and discovery.
2. Supplying the custom plugin's key to the MDX context by calling
   `.withMdxContext().withCubeFormatter(pluginKey)` on the cube builder.

The main benefit of creating a custom formatter factory is the possibility to store
the various locales elsewhere than on the resource folder or in content server, and to also
potentially use a custom format for localization files.

It is recommended to extend the `ACubeFormatterFactory` and `ACubeFormatter` classes when
implementing a new formatter factory.

## CubeFormatterFactory

`CubeFormatterFactory` is a basic implementation of formatter factories.

An instance of this class can only support one locale, so it should be extended as many times
as different locales are needed, each extension with its own plugin key. The relevant formatter
factory for each user can then be provided using context values.

The implementation stores its lexicons using a map of maps. The latter is stored in the resource folder or in
content server as a JSON file.

The keys of the top-level map correspond to the different lexicons in use and are listed in
`ACubeFormatter.Type`.

A level-specific formatter can be created using a dedicated lexicon for the level. The lexicon
can then be associated with its level in the *\_FORMATTERS\_* lexicon.

```json5 theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
{
    "_FORMATTERS_": {
        "[Bookings].[Status].[Status]": "_STATUS_"
    },

    "_STATUS_": {
        "DONE": "ACCOMPLI",
        "MATCHED": "APPARIE"
    }
}
```

When a formatter is requested for a caption:

* If no lexicon for a particular type is given, the *\_GENERAL\_* lexicon will be used.
* If captions and formatters are defined both in the resource folder (or content server) and the
  MDX context, the factory will merge them, with priority to the former.

### Example of a JSON locale file

<Accordion title="Click to expand">
  ```json5 theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
  {
      /** Measure captions lexicon */
      "_MEASURES_": {
          "pnl.SUM": "pnl.SOMME",
          "update.TIMESTAMP": "Dernière mise à jour",
          "contributors.COUNT": "Nombre de faits"
      },

      "_FORMATTERS_": {
          /** Measure formatters */
          "[Measures].[update.TIMESTAMP]": "DATE[HH:mm:ss]",
          "[Measures].[delta.SUM]": "DOUBLE[#,###.0000;-#,###.00]",
          "[Measures].[pnl.SUM]": "DOUBLE[#,###.00;-#,###.00]",

          /** Level member formatters */
          "[Time].[TimeBucket].[Value Date]": "DATE",
          "[Underlyings].[Products].[ProductType]": "_PRODUCT_TYPES_"
      },

      /**  lexicon used for Product types' members */
      "_PRODUCT_TYPES_": {
          "LISTED": "COTE",
          "OTC": "DE GRE A GRE"
      },

      "_DESCRIPTIONS_": {
          "The two elements of underlyings which have the highest value":
            "Les deux éléments sous-jacents de plus grande valeur.",
          "Dimension of underlyings": "Dimension des sous-jacents"
      },

      /**
        * The GENERAL lexicon, used for all other types
        * (dimensions, levels, drill-through...)
        */
      "_GENERAL_": {
          "Time": "Temps",
          "Measures": "Mesures",
          "Bookings": "Enregistrement",
          "Epoch": "Epoque"
      }
  }
  ```
</Accordion>

## Example: Sandbox Implementation

The Sandbox uses the `LocalI18nConfig` class mentioned [above](#locali18nconfig) to generate its formatter factories from the resource folder.

### Changing a User's Locale

If we want to change the locale to French for the admin user, we have to follow these three steps:

* Put the French locale JSON configuration file in the resource folder, with the name:
  ***/i18n/fr-FR***.

* Change the context for the role `ROLE_ADMIN`.
  ```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
  StartBuilding.entitlementsProvider()
    .withEntitlements(b ->
      b.forRole(ROLE_ADMIN)
        .withMdxContext()
          .withCubeFormatter("fr-FR"));
  ```
