> For the complete documentation index, see [llms.txt](https://docs.openiam.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.openiam.com/administration-guide/platform/localization.md).

# Languages and localization

Understand the two translation surfaces, add a LANGUAGE\_MAPPING row for a menu, and verify it against a real locale.

## What this is, and when you need it

Localization in OpenIAM is two unrelated mechanisms that share one language table, and almost every "I translated it and nothing changed" report is a case of editing the wrong one. This page settles which surface a given piece of text belongs to, then translates an object name and proves it under a real locale. The 23 language rows, their IDs, codes and active flags are in [Languages and localization reference](/administration-guide/reference/languages.md).

## At a glance

|                          |                                                                                                                                                        |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **You will end up with** | A menu, role, resource or metadata type whose name appears in the reader's own language, proved under a real locale rather than by clicking the picker |
| **Where**                | **Administration → Languages** (`/webconsole/languages`) for the language row; the object's own screen, or a `LANGUAGE_MAPPING` row, for the name      |
| **You need first**       | The numeric `LANGUAGE.ID` of each language; the object's real primary key; and, for a menu, database write access — no screen edits menu translations  |
| **Takes**                | 10 minutes for the first object, plus up to five minutes for the language cache to turn over                                                           |
| **Reversible**           | Yes. Delete the mapping row and the object falls back to its base value. Deactivating **every** language is the one change that is not safe            |

## Before you begin

**Settle which of two mechanisms you are dealing with, first.** Almost every "I translated it and nothing changed" report is a case of editing the wrong one:

* A **system message, button, error or hint** in the shipped language comes from a resource bundle. No screen in OpenIAM edits it, and overriding it needs a file on disk and a service restart. Stop here and read [The bundles, and what you can and cannot change](#the-bundles-and-what-you-can-and-cannot-change).
* **The name of an object** — a menu, role, group, resource, metadata type, security question or the name of a language itself — is a `LANGUAGE_MAPPING` row, editable at runtime. That is what the procedure below does.

You also need:

* **The numeric `LANGUAGE.ID`** for every language you have activated, from [Languages and localization reference](/administration-guide/reference/languages.md). The match is made on that number, never on the locale string.
* **The object's real primary key** — for a menu, its `RES.RESOURCE_ID`, not its label.
* **A record of every activated language**, because there is no cross-language fallback: a missing row leaves the base value, and for a menu the base value is a database identifier.

## Translate an object name into another language

The worked values below translate one menu into Dutch. Dutch is `LANGUAGE.ID` `17`, code `nl`, locale `nl_NL`, and it ships active. The menu is the sequence-generator menu, resource id `COUNTE_ADM_M`, whose English name has shipped as `Counters` since 4.2.1.1.

{% stepper %}
{% step %}

### Confirm the language is active and named

**Administration → Languages**, open Dutch. Confirm **Is Active** is ticked, **Code** is `nl`, and one **Locale** row reads `nl_NL`. Do not change **Is Default**.
{% endstep %}

{% step %}

### Find the object's real primary key

You need `RES.RESOURCE_ID`, not the label. Open **Access Control → Menus** and read it from the menu's own record. For this example it is `COUNTE_ADM_M`, and its `RES.NAME` is `COUNTERS` — which is exactly what an untranslated Dutch console will show in place of a label.
{% endstep %}

{% step %}

### Insert the mapping row

{% hint style="warning" %}
**Break-glass: this is a direct write to the `openiam` schema, outside the supported change path.** No screen in OpenIAM edits arbitrary `LANGUAGE_MAPPING` rows, so for a menu there is no supported alternative; where the screen that owns an object does offer a translated name, use that screen instead and skip this step. The cost of doing it here: the insert is not audited, so nothing in the audit log will ever show who translated this menu; nothing validates `REFERENCE_TYPE`, `REFERENCE_ID` or `LANGUAGE_ID`, so a wrong value saves cleanly and simply never matches; and the menu tree and language caches are not invalidated, so the row does not appear until the next sweep. Read the current rows before you write, and insert one row at a time.
{% endhint %}

Read first, so you know whether you are inserting or duplicating:

{% code overflow="wrap" %}

```sql
SELECT LANGUAGE_ID, TEXT_VALUE FROM LANGUAGE_MAPPING
 WHERE REFERENCE_ID = 'COUNTE_ADM_M'
   AND REFERENCE_TYPE = 'ResourceEntity.displayNameMap';
```

{% endcode %}

Then insert, against the **`openiam`** schema:

{% code overflow="wrap" %}

```sql
INSERT INTO LANGUAGE_MAPPING (ID, LANGUAGE_ID, REFERENCE_ID, REFERENCE_TYPE, TEXT_VALUE)
VALUES (REPLACE(UUID(), '-', ''), '17', 'COUNTE_ADM_M',
        'ResourceEntity.displayNameMap', 'Sequentiegeneratoren');
```

{% endcode %}

`REPLACE(UUID(),'-','')` is the id form the shipped translations use, and it fits the 32-character `ID` column. Re-run the `SELECT` above to confirm exactly one row now exists for `LANGUAGE_ID` `17`.
{% endstep %}

{% step %}

### Repeat for every activated language, English included

There is no cross-language fallback. Run the same insert with `LANGUAGE_ID` `1` and the English text if the object has no English row; otherwise English users see `COUNTERS`.
{% endstep %}

{% step %}

### Sign in with the locale actually set, not by clicking the picker

Open a private browser session and go to `https://<OPENIAM_HOST>/webconsole/?lang=nl_NL`. OpenIAM writes the `OPENIAM_LOCALE` cookie and redirects to the same URI without the parameter; confirm the cookie exists in devtools before judging the result. Sign in as `<TEST_USER>` and read the menu.

Clicking the drop-down does the same thing, but only if Dutch is in the picker — which requires the `LanguageEntity.displayNameMap` row described above. Setting `?lang=` works regardless, which is why it is the reliable test.
{% endstep %}

{% step %}

### If nothing changed, wait or restart

The menu tree and the language list are both cached. `org.openiam.language.provider.threadsweep` is `300000` ms. Wait five minutes before assuming the row is wrong.
{% endstep %}
{% endstepper %}

## Verification

| Evidence                                                                   | Meaning                                                                                                                               |
| -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| The `OPENIAM_LOCALE` cookie holds `nl_NL`                                  | The locale resolver accepted your request; anything still English is a mapping or bundle problem, not a locale problem                |
| The menu shows `COUNTERS`                                                  | No `LANGUAGE_MAPPING` row matched — check `REFERENCE_TYPE` and `LANGUAGE_ID` before anything else                                     |
| The menu shows `Counters` under a Dutch console                            | The English row (`LANGUAGE_ID = '1'`) matched, so `languageId` is resolving to English. Check the cookie and `LANGUAGE.LANGUAGE_CODE` |
| A "Save language" audit event                                              | The `LANGUAGE` row itself was changed. `LANGUAGE_MAPPING` rows inserted by SQL leave no audit trail                                   |
| ESB log: *"There are no languages with the 'used' flag marked as 'true'."* | Every language was deactivated. Re-activate one immediately                                                                           |

## When it goes wrong

| Symptom                                                       | Inspect                                                                                                                       | Fix                                                                                                                                                                                                                                                    |
| ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Menu shows a database identifier such as `OTP_PROVIDERS`      | `LANGUAGE_MAPPING` for that `REFERENCE_ID` with `REFERENCE_TYPE='ResourceEntity.displayNameMap'`                              | Menus have no base display name. Insert one row per active language                                                                                                                                                                                    |
| Row inserted, still English                                   | `REFERENCE_TYPE` spelling, and `LANGUAGE_ID` against [the language table](/administration-guide/reference/languages.md)       | Copy one of the [four recognised values](#the-runtime-surface-language_mapping) exactly — it is `ResourceEntity.displayNameMap`, never `Resource.displayName`. A wrong value saves without complaint                                                   |
| Some objects translate, others do not, in the same screen     | Which object types the four `REFERENCE_TYPE` values cover                                                                     | Only those object types carry translated names; everything else renders its `NAME` column and cannot be translated at all                                                                                                                              |
| A system message or button is English in a translated console | The text against the bundle, not against `LANGUAGE_MAPPING`                                                                   | That is a bundle key. No screen edits it; overriding it is a deployment change needing a restart — [Installation Guide](/installation/installation.md) — or raise it for the release                                                                   |
| A bundle override was placed on disk, no effect               | Whether the UI services were restarted after the file appeared, and whether they read that directory at all                   | Bundles are cached for the life of the process. Both questions are for whoever owns the deployment — [Installation Guide](/installation/installation.md)                                                                                               |
| Language does not appear in the picker                        | `LANGUAGE.IS_USED`, then `LANGUAGE_MAPPING` with `REFERENCE_TYPE='LanguageEntity.displayNameMap'` for the *viewer's* language | The list includes only languages named in the current language; and the control is hidden entirely when only one qualifies                                                                                                                             |
| Save rejected: *"No default language has been defined"*       | `LANGUAGE.IS_DEFAULT` across all rows                                                                                         | You cleared the flag on the only default. Set it on another row instead — that clears the old one                                                                                                                                                      |
| Save rejected: *"Locale ''nl\_NL'' already exists"*           | `LANGUAGE_LOCALE.LOCALE`                                                                                                      | The column is unique across all languages. Move the existing row rather than adding a duplicate                                                                                                                                                        |
| New locale added but labels stay English                      | The bundle file name against the locale string                                                                                | The locale must match a `messages_*.properties` name, and a locale matching none shows English without saying so. Read the **Locale** from **Administration → Languages** rather than deriving it — Danish and Norwegian both changed code in 2026.8.1 |
| Translate button does nothing, no error                       | `org.openiam.ui.api.google.apikey` on **Administration → System Configuration → System**                                      | It ships empty, and the failure is returned as an empty result rather than an error. Set the key                                                                                                                                                       |
| Deleted an object, its translations linger                    | `LANGUAGE_MAPPING` for that `REFERENCE_ID`                                                                                    | Deleting the object through its own screen removes its mapping rows too; deleting it with SQL does not, and leaves rows nothing will ever read                                                                                                         |

## The two translation surfaces

|                           | Shipped resource bundles                                                                                               | `LANGUAGE_MAPPING` rows                                                                                                                       |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| What it covers            | Every fixed label, button, error and hint in the UI                                                                    | The *name* of an object: menus, roles, groups, resources, metadata types, security questions, page-template labels, language names themselves |
| Where it lives            | `messages_<locale>.properties` shipped inside each UI service, plus an optional override the deployment places on disk | Rows in the `openiam` schema, one per object per language                                                                                     |
| Editable at runtime       | Only through the on-disk override, and only with a service restart                                                     | Yes — SQL, or whatever screen owns the object                                                                                                 |
| Needs a release           | For the shipped copy, yes                                                                                              | No                                                                                                                                            |
| Keyed by                  | A message key such as `openiam.ui.common.is.active`                                                                    | `REFERENCE_TYPE` + `REFERENCE_ID` + `LANGUAGE_ID`                                                                                             |
| Missing translation shows | The value from the next basename in the chain, ultimately `messages_en.properties`                                     | The object's own base value — for a menu, the raw `RES.NAME`                                                                                  |

So: a *system message* in English inside an otherwise Dutch console is a bundle problem. A *menu item* or *role name* in English is a missing `LANGUAGE_MAPPING` row. They are fixed in different places by different people.

## The bundles, and what you can and cannot change

Fixed UI text — every label, button, error and hint that is not the name of an object — comes from a resource bundle named `messages_<locale>.properties` shipped inside each UI service. `messages_en.properties` is the base, and carries around ten thousand keys.

**Every other bundle is generated from the English one.** Each opens with a header saying so, mirrors English key for key in the same order, and is rewritten whenever the English file changes. That is the thing to carry away from this section: a translation you disagree with is not a deployment setting you can put right. Correcting it inside a bundle does not survive, because the next generation overwrites the file — the correction belongs with OpenIAM, against the English string.

A deployment can override or extend a bundle by putting its own `messages_<locale>.properties` on disk where the UI services look before the shipped copy: a key present in the override wins, and keys you omit fall through to the shipped bundle. No such file ships, so on a fresh install nothing overrides anything.

{% hint style="warning" %}
**Not an administration task, and not a live change.** Placing that file needs filesystem access to the `webconsole`, `selfservice` and `idp` containers, and each service caches its bundles for the life of the process, so the change takes effect only when those services restart. Both facts put the procedure outside this guide — see the [Installation Guide](/installation/installation.md). What you can recognise from your own seat is the symptom: a label that stays in the shipped language no matter how many `LANGUAGE_MAPPING` rows you add is a bundle key, not a mapping, and no screen in OpenIAM edits it.
{% endhint %}

Around eighteen locales ship and the set grows, so **Administration → Languages** is the list for your own release rather than anything written here.

Two are worth knowing as shapes rather than as entries. `messages_ar.properties` is language-only, with no country, so a locale of `ar_SA` resolves to it by Java's normal bundle fallback. And `messages_en_GB.properties` is a full mirror of English rather than a thin overlay of British spellings — it holds every key, so nothing in it falls through to `messages_en`.

The locale string has to match a bundle file name, and OpenIAM's own codes have moved more than once. Danish and Norwegian shipped for a time as `dk_DK` and `no_NO`, which are not the ISO codes; **2026.8.1 corrects them to `da_DK` and `nb_NO`**, renaming the rows in place rather than adding new ones. Bundle files exist under both spellings, so a deployment that has not yet run that migration keeps working. Swedish is still `se_SE`, which is also not the ISO code and has not been changed.

The rule survives the churn: read the value from **Administration → Languages** on your own deployment rather than deriving it from the language. Open the language and read **Locale**, not **Code** — they are separate fields and they differ, Danish being `da` and `da_DK`. **Locale** is what the bundle lookup uses, and a locale matching no bundle silently shows English.

There is also a Groovy hook keyed on language, and it is one you write. OpenIAM looks for a script named `LanguageSupport<XX>`, where `XX` is the uppercased two-letter language code of the resolved locale, below the Groovy Manager path held in `org.openiam.language.support.script.base.name`. `addArticle` is the only method that will ever be dispatched to it, so a script exposing anything else is never reached. `LanguageSupportEN` and `LanguageSupportRU` ship as examples — see [Create a Groovy script](/administration-guide/automation/manage-groovy-scripts.md).

{% hint style="warning" %}
**Nothing in the shipped screens asks for it.** The hook is available to a customised page, and no Webconsole or SelfService screen in this release calls it — so a `LanguageSupport<XX>` script you write is inert until something asks, and there is no screen that exercises it to prove it works. Confirm on your own release before building a language on it, and treat "my script never runs" as expected rather than as a fault.
{% endhint %}

## The runtime surface: `LANGUAGE_MAPPING`

Four columns matter.

| Column           | Meaning                                                                                                                                                                                                       |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `LANGUAGE_ID`    | The numeric `LANGUAGE.ID` — `1` English, `2` German, `3` French, `4` Spanish, `8` Russian, `9` Japanese, `10` Chinese, `11` Portuguese, `12` Norwegian, `14` Danish, `15` Malaysian, `17` Dutch, `18` Swedish |
| `REFERENCE_ID`   | The primary key of the object being named                                                                                                                                                                     |
| `REFERENCE_TYPE` | `<EntitySimpleName>.<fieldName>` — see below                                                                                                                                                                  |
| `TEXT_VALUE`     | The translated name                                                                                                                                                                                           |

`REFERENCE_TYPE` is not a free-form label. OpenIAM composes it internally from the object type and the name of that type's translated-names field, joined by a dot, and matches your row against the composed string exactly. No screen shows you the spelling, and a wrong one is ignored rather than rejected, so copy a value rather than deriving it. These four are the whole set an administrator ever writes, and all four appear in shipped translations:

| `REFERENCE_TYPE`                        | Names                                                   |
| --------------------------------------- | ------------------------------------------------------- |
| `ResourceEntity.displayNameMap`         | Menus, resources and applications (`RES.RESOURCE_ID`)   |
| `MetadataTypeEntity.displayNameMap`     | Metadata types                                          |
| `IdentityQuestionEntity.displayNameMap` | Security questions                                      |
| `LanguageEntity.displayNameMap`         | The name of a language as shown in every other language |

A wrong `REFERENCE_TYPE` is the most common failed translation: the row saves, no query matches it, and nothing on screen changes.

### How a mapping row reaches the screen

Two hops, and both are conditional.

**Loading.** When OpenIAM reads an object that can carry translated names, it also reads every `LANGUAGE_MAPPING` row matching that object's `REFERENCE_ID` and `REFERENCE_TYPE`, and holds them in memory keyed by `LANGUAGE_ID`. Object types that carry no translated names are never read this way, which is why some objects on a screen translate and others beside them do not.

**Applying.** The label is then substituted **only when the rows just loaded contain the exact language id of the request**. There is no attempt at a parent language, no attempt at the default language, no warning and no error: an unmatched language id leaves the object's base value in place, and a request carrying no language id at all skips the substitution entirely.

{% hint style="info" %}
Neither hop writes an audit record or a log line you can read, so the console cannot tell you whether a row was found. Diagnose it from the data instead: if a `LANGUAGE_MAPPING` row exists for the object with the right `REFERENCE_TYPE` and the right `LANGUAGE_ID` and the screen still shows the base value, the request is resolving to a different language — check the cookie, per [Which locale is actually in force](#which-locale-is-actually-in-force).
{% endhint %}

### The fallback, stated exactly

**A missing mapping row leaves the base value in place.** For most objects that base value is the object's `NAME` column, which is usually a human-readable name — so a missing German row for a role called `Finance Approver` shows `Finance Approver`, which is tolerable.

For menus it is worse, because a menu has no base display name at all. A menu entry gets a label only from a `LANGUAGE_MAPPING` row for the language of the request; with no such row there is nothing to display, so the tree falls back to the menu resource's `RES.NAME`, and where even that is empty to the word **Unnamed**.

{% hint style="danger" %}
That is why an untranslated menu shows a database identifier such as `OTP_PROVIDERS` or `COUNTE_ADM_M` rather than a label. It is not a broken bundle and reindexing will not help — the menu needs a `LANGUAGE_MAPPING` row for **every** language you have activated, including English.
{% endhint %}

Consent text has no fallback at all, not even a base value. OpenIAM returns only the text of the policy version that matches the user's current language, and returns nothing when none matches — so the user gets a blank agreement page rather than an error, and can neither accept nor proceed. See [Consent and IT policy](/administration-guide/consent/consent-and-it-policy.md).

## The `LANGUAGE` table and the "Is Active" checkbox

**Administration → Languages** at `/webconsole/languages` lists the languages, and one row is edited at `/webconsole/languageEdit?id=<LANGUAGE_ID>`. Saving is audited with description *"Save language"*.

| Column                   | Screen label  | Notes                                                                                                                                                                                                          |
| ------------------------ | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ID`                     | —             | The numeric key you put in `LANGUAGE_MAPPING.LANGUAGE_ID`                                                                                                                                                      |
| `LANGUAGE`               | Name          | Required on add (`NAME_MISSING` → *"A name for the current language is required"*)                                                                                                                             |
| `LANGUAGE_CODE`          | Code          | `varchar(2)`, maxlength 2 on the form. Required (`LANGUAGE_CODE_MISSING` → *"Language code is required"*). This is what matches a browser locale to a language row                                             |
| `IS_USED`                | **Is Active** | The checkbox writes `IS_USED`. Its label comes from the message key `openiam.ui.common.is.active`, and nothing on screen names the column — which is why the two are rarely connected                          |
| `IS_DEFAULT`             | Is Default    | Exactly one row must have it. Clearing it on the only default row fails with `NO_DEFAULT_LANGUAGE` → *"No default language has been defined"*; setting it on another row clears the previous one automatically |
| `LANGUAGE_LOCALE.LOCALE` | Locale        | One or more per language, unique across the table. A duplicate fails with `LOCALE_ALREADY_EXISTS` → *"Locale ''{0}'' already exists"*                                                                          |

{% hint style="danger" %}
**Do not deactivate every language.** Every UI service re-reads the list of active languages on a timer, and an empty list is a hard failure rather than a cosmetic one: the service log fills with *"There are no languages with the 'used' flag marked as 'true'."* and repeats it on every sweep and every start. Before you untick **Is Active** anywhere, confirm on **Administration → Languages** that another row still has it ticked.
{% endhint %}

Activation is not immediate. OpenIAM re-reads the language list on the interval in `org.openiam.language.provider.threadsweep`, shipped **`300000`** ms — five minutes. Allow that long before concluding a change did not take.

The language picker is also conditional, in two ways that compound. The drop-down is hidden entirely unless more than one language qualifies for it, and a language qualifies only when it has a `LanguageEntity.displayNameMap` row **in the language the viewer is currently using** — so a language you activated but did not name in every other language is invisible to users of those languages, and if it is the only extra language they see no picker at all. Arabic, added in 2026.7.1.0, is the pattern to copy: it ships one `LanguageEntity.displayNameMap` row per already-present language, naming Arabic in each of them. Verify by signing in under each activated language in turn and confirming the new language appears in the drop-down.

## Which locale is actually in force

There is **no per-user preferred-language column** in OpenIAM: nothing on a user's record sets their language, and there is no screen on which you can set one for them. The locale for a request is resolved fresh each time, in this order:

1. If `org.openiam.locale.i18n.enabled` is `false`, the default locale, always. It ships **`true`**.
2. The `OPENIAM_LOCALE` cookie. It is `HttpOnly`, path `/`, and `Secure` when the request arrived over `https`.
3. The browser's `Accept-Language`, matched to a language row by its two-letter `LANGUAGE_CODE` (case-insensitively) and then to that row's first locale.
4. `org.openiam.default.locale`, shipped **`en_US`**, falling back to US English if that value names no locale that exists.

The cookie is written from the request parameter named in `org.openiam.locale.request.param.name`, shipped **`lang`**: a request carrying `?lang=<locale>` gets the cookie set and is redirected to the same URI without it. That is all the language drop-down does — it rewrites the query string, it does not call an API — which is why appending `?lang=` by hand is an equally valid way to switch language, and the only way when the picker is hidden.

None of `org.openiam.locale.i18n.enabled`, `org.openiam.default.locale`, `org.openiam.locale.request.param.name` or `org.openiam.language.provider.threadsweep` is a `PROPERTY_FILE_VALUES` row, so none of them appears on **Administration → System Configuration**. They come from `openiam.ui.properties` in each UI artifact and are changed with an `OPENIAM_PROP_*` container override — see [Where settings live](/administration-guide/start/where-settings-live.md#the-container-override-convention).

The resolved language's numeric id is what gets compared against `LANGUAGE_MAPPING.LANGUAGE_ID`. **Nothing on any screen tells you which language a given screen resolved.** The observable substitute is the outcome: change the browser locale one language at a time and watch which localized values appear and which fall back to the raw identifier.

## Google Translation, and its shipped default

The Webconsole can machine-translate a value for you while you are editing it.

| Property                                | Ships as           | Category                 | Screen label               |
| --------------------------------------- | ------------------ | ------------------------ | -------------------------- |
| `org.openiam.ui.api.google.apikey`      | **empty** (`NULL`) | `System`                 | Google Translation API Key |
| `org.openiam.ui.api.translate.provider` | `Google`           | — (properties file only) | —                          |
| `org.openiam.ui.api.google.baseurl`     | `https://`         | — (properties file only) | —                          |
| `org.openiam.ui.api.google.contentType` | `Json`             | — (properties file only) | —                          |

The API key is the only one of the four exposed on **Administration → System Configuration → System**; the other three exist only in each UI artifact's `openiam.ui.properties` and are changed with an `OPENIAM_PROP_*` container override. Until you set the key, the request returns an empty result rather than an error, so the symptom is a translate button that appears to do nothing at all. Confirm the key is present on that screen before investigating anything else.

{% hint style="warning" %}
Machine translation sends the text you are editing to Google. Do not use it on anything derived from personal data, and treat the API key as a secret even though the property row stores it in clear text.
{% endhint %}

## Related

* [Languages and localization reference](/administration-guide/reference/languages.md) — the 23 shipped languages, their IDs and codes
* [Consent and IT policy](/administration-guide/consent/consent-and-it-policy.md) — consent text is localized per version and has no fallback
* [Mail and notifications](/administration-guide/platform/mail-and-notifications.md) — mail templates are localized by template row, not by `LANGUAGE_MAPPING`
* [System configuration](/administration-guide/platform/system-configuration.md) — where `org.openiam.ui.api.google.apikey` lives

*Applies to OpenIAM 2026.8.1. Last reviewed 7 August 2026.*


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.openiam.com/administration-guide/platform/localization.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
