# Localization Service

<figure><img src="/files/vvVduW5CK6XvPsNnSQuR" alt=""><figcaption></figcaption></figure>

**Audience:** IT admins. This page describes how the **localization service** works: how the **locale** is set, how it can be **overridden**, and how to **modify** UI text via localization configuration.

***

### Overview

Keeper Privilege Manager supports **multiple languages** for UI components (tray app, MFA/approval/justification dialogs, messages, etc.). The system:

* **Resolves the user’s locale** (system detection or an explicit override).
* **Stores the chosen locale** per user (via registration with the local service).
* **Serves localized strings** to each component by **culture** (e.g. `en_US`, `fr_FR`).
* **Allows customization** of text by editing **localization JSON files** or, where supported, via the **localization API**.

Locale is **per user** (or per session that registers). Each UI component requests strings for the **registered** culture so menus, dialogs, and notifications appear in the correct language.

***

### How the Locale is Set

#### Default Behavior (no override)

1. When the **KeeperClient** (tray) application starts, it determines the locale to use:
   * If no override is configured, it uses **system locale detection** (Windows display language, Linux `LANG`/locale, macOS preferences).
   * The result is normalized to a **culture code** such as `en_US`, `fr_FR`, `es_ES` (language\_REGION).
2. The client **registers** this locale with Keeper Privilege Manager by calling **`POST /api/Locale/Register`** with a JSON body such as `{ "Locale": "en_US" }`.
3. The service stores the **locale for that user** (or session). Other UI apps (KeeperMFA, KeeperApproval, KeeperJustification, KeeperMessage, etc.) that run in the same context use the **same registered locale** when they request localization data.
4. When a component needs strings (e.g. menu labels, dialog text), it calls **`GET /api/localization/{component}/{culture}`** (e.g. `GET /api/localization/KeeperClientLocales/en_US`). The **culture** comes from the registered locale, so all components stay in sync.

So by default: **system locale → register with KPM → all UIs use that culture** for localization.

#### Fallback

* If system detection fails, the client falls back to **en\_US**.
* If a requested culture is missing for a string, the service typically falls back to **en\_US** for that key, or the UI may show a fallback message (e.g. the `message` field in a toast).

***

### How the Locale Can Be Overwritten

You can **override** the system-detected locale so that the UI always uses a specific language, regardless of the OS display language.

#### Option 1: KeeperClient Plugin Setting (recommended)

The **KeeperClient** plugin supports a **LanguageOverride** setting in its **metadata**:

| Setting                       | Type   | Default     | Effect                                                    |
| ----------------------------- | ------ | ----------- | --------------------------------------------------------- |
| **metadata.LanguageOverride** | string | `"DEFAULT"` | Override UI language for the tray and related components. |

**Values:**

* **`"DEFAULT"`** (or empty/not set) — Use **system-detected** locale (behavior above).
* **A valid culture code** — Force that language, e.g. `"en_US"`, `"fr_FR"`, `"es_ES"`, `"de_DE"`, `"ja_JP"`, `"zh_CN"`.

**How to set it:**

1. **From the dashboard** — If your deployment supports configuration policy or plugin settings push, set **LanguageOverride** for the KeeperClient plugin to the desired culture code.
2. **On the endpoint** — Edit the KeeperClient plugin JSON (e.g. `Plugins/KeeperClient.json` or the path used in your install). Under `metadata`, add or change:

   ```
   "metadata": {
     "LanguageOverride": "fr_FR"
   }
   ```

   Then **restart the KeeperClient plugin** (or the agent) so it reloads settings. On next start, KeeperClient will read `LanguageOverride`, use `fr_FR` instead of system detection, and register that with `POST /api/Locale/Register`.

**Note:** If the value is not a valid culture code, the client logs a warning and falls back to system detection.

#### Option 2: Register Locale via API

An admin or a custom script can call **`POST /api/Locale/Register`** with a body like `{ "Locale": "fr_FR" }` (with appropriate auth and, typically, in the context of the target user/session). That **overwrites** the stored locale for that user so subsequent UI components will request strings for the new culture. This is advanced; usually you use the plugin setting or command-line override instead.

#### Summary

<table data-header-hidden="false" data-header-sticky><thead><tr><th>Method</th><th>Scope</th><th>Persistence</th></tr></thead><tbody><tr><td><strong>metadata.LanguageOverride</strong> (KeeperClient)</td><td>All users on endpoints where this config is applied</td><td>Until config is changed and plugin restarted</td></tr><tr><td><strong>--language-override</strong> (launch arg)</td><td>Single process run</td><td>That run only</td></tr><tr><td><strong>POST /api/Locale/Register</strong></td><td>One user/session</td><td>Until next register</td></tr></tbody></table>

***

### How to Modify Text (localization configuration)

You can **change the text** that appears in the UI by editing **localization data**. The product uses **locale files** (JSON) that map **string keys** to **per-culture text**. You can edit these files directly or, where the product supports it, use the **localization API**.

#### Where Localization Data Lives

* **On the service (agent):** Localization JSON files are typically under the **Localization** directory of the Keeper Privilege Manager installation (exact path depends on deployment; e.g. `KeeperPrivilegeManager/Localization/`).
* **Component-specific files** — Each UI component has its own locale file (or shares one). Examples:
  * **LocaleValues.json** — Core/system strings.
  * **SharedLocales.json** — Shared strings (buttons, common labels, etc.).
  * **KeeperClientLocales.json** — Tray app (KeeperClient).
  * **KeeperMfaLocales.json** — MFA dialog.
  * **KeeperApprovalLocales.json** — Approval dialog.
  * **KeeperJustificationLocales.json** — Justification dialog.
  * **KeeperMessageLocales.json** — KeeperMessage dialogs.
  * **KeeperTrayLocales.json** — System tray.
  * **KeeperControlsLocales.json** — Controls UI.
  * **SudoWrapperLocales.json**, **DiagnosticToolLocales.json** — CLI/tool strings.

The **component name** in the API (`GET /api/localization/{component}/{culture}`) corresponds to these files (e.g. `KeeperClientLocales`, `SharedLocales`).

<mark style="color:$danger;">**WARNING:**</mark> localization files may be overwritten during upgrades.

#### JSON Structure of a Localization File

Each file is a JSON object where:

* **Key** = string id used in code or jobs (e.g. `kepm_kc_menu_settings`, `kepm_shared_button_ok`).
* **Value** = object mapping **culture code** to **display text**.

**Example:**

```
{
  "kepm_shared_button_ok": {
    "en_US": "OK",
    "fr_FR": "OK",
    "es_ES": "Aceptar",
    "de_DE": "OK"
  },
  "kepm_approval_title": {
    "en_US": "Approval Required",
    "fr_FR": "Approbation requise",
    "es_ES": "Aprobación requerida"
  }
}
```

* **Parameterized strings** use placeholders `{0}`, `{1}`, etc. Example: `"en_US": "Approval required for {0}"`. The application substitutes values at runtime.

**Culture codes** are in the form **language\_REGION** (e.g. `en_US`, `fr_FR`, `zh_CN`). The product supports many locales (e.g. en\_US, en\_GB, es\_ES, fr\_FR, de\_DE, it\_IT, pt\_BR, ja\_JP, ko\_KR, zh\_CN, zh\_TW, ru\_RU, and others). Add or edit the culture key that matches the locale you care about.

#### Modifying Text by Editing a Localization File

1. **Locate the correct file** — For tray/menu text, use **KeeperClientLocales.json** or **SharedLocales.json**. For MFA/approval/justification/message dialogs, use the corresponding component file (e.g. **KeeperMfaLocales.json**, **KeeperApprovalLocales.json**).
2. **Find the key** — Keys follow patterns like `kepm_kc_*` (KeeperClient), `kepm_shared_*` (shared), `kepm_kmfa_*` (MFA), `kepm_kapproval_*` (approval). Search the file for the key that corresponds to the text you want to change (or add a new key if you are extending; use the same structure as existing entries).
3. **Edit the value for the culture** — Change the string for the desired culture (e.g. `"en_US": "Your new text"`). You can add a new culture block if the file does not yet have that locale.
4. **Save the file** and **reload** so the service picks up changes:
   * **Restart the affected plugin** (e.g. KeeperClient) or **restart the agent**, and/or
   * If your deployment uses a **locale cache**, run the **locale-cache-cleanup** job (or equivalent) so the next request gets fresh data.

**Important:** Keep valid JSON (commas, quotes). Back up the file before editing. Avoid removing keys that are still referenced by the app, or the UI may show a missing-key placeholder.

#### Modifying Text via the Localization API (Admin)

The product exposes **Admin** endpoints to create, update, or delete localization strings:

<table data-header-hidden="false" data-header-sticky><thead><tr><th width="107.6666259765625">Method</th><th>Path</th><th>Description</th></tr></thead><tbody><tr><td><strong>POST</strong></td><td><code>/api/localization/strings</code></td><td>Create a localization string (body: key and per-culture values).</td></tr><tr><td><strong>PUT</strong></td><td><code>/api/localization/strings/{key}</code></td><td>Update an existing string.</td></tr><tr><td><strong>DELETE</strong></td><td><code>/api/localization/strings/{key}</code></td><td>Delete a string.</td></tr></tbody></table>

These typically operate on the **same data** that the service uses to answer `GET /api/localization/{component}/{culture}`. Whether they apply to file-based locale files or to a separate store depends on implementation; see product documentation or API docs. After changes, **restart the relevant UI** or **clear locale cache** so clients see updated text.

**Example (conceptual):** To change the English text for key `kepm_shared_button_ok`, you might send a PUT with a body that includes the updated `en_US` value. Exact request/response format follows the product’s API specification.

#### Adding a New Key or New Culture

* **New key:** In the appropriate JSON file, add a new top-level key with the same structure: key name → object with culture codes and strings. Use a consistent naming convention (e.g. `kepm_<component>_<description>`). If the UI or a job references this key (e.g. by `messageKey` in a toast), it will then show your text.
* **New culture:** Add a new property to existing (or new) key objects, e.g. `"pt_PT": "Texto em português"`. Ensure the locale is one the product supports (or document any custom codes your deployment uses).

#### Naming and Best Practices

* **Key naming** — Many keys use a prefix such as `kepm_shared_*`, `kepm_kc_*`, `kepm_kmfa_*`, etc. Keeping a similar style makes it easier to find and maintain entries.
* **Fallback** — Always provide at least **en\_US** so there is a default if a culture is missing.
* **Parameterized strings** — Use `{0}`, `{1}` for dynamic parts (e.g. file name, count); the app will substitute them in order.
* **Testing** — After changing a file or API, set the user’s locale (e.g. via **LanguageOverride**) to that culture and restart the UI to verify the new text.

***

### Locale Registration and Localization API Summary

<table data-header-hidden="false" data-header-sticky><thead><tr><th width="180">Item</th><th>Description</th></tr></thead><tbody><tr><td><strong>Set locale</strong></td><td>System detection by default; optional override via <strong>metadata.LanguageOverride</strong> (KeeperClient) or <strong>--language-override</strong> or <strong>POST /api/Locale/Register</strong>.</td></tr><tr><td><strong>Overwrite locale</strong></td><td>Set <strong>LanguageOverride</strong> in KeeperClient plugin config to a culture code (or <code>DEFAULT</code>); restart plugin. Or use <strong>POST /api/Locale/Register</strong> for that user.</td></tr><tr><td><strong>Modify text</strong></td><td>Edit the appropriate <strong>Localization/*.json</strong> file (key → culture → text), or use <strong>POST/PUT/DELETE /api/localization/strings</strong> (Admin). Restart UI or clear locale cache after changes.</td></tr><tr><td><strong>Locale files</strong></td><td><strong>LocaleValues</strong>, <strong>SharedLocales</strong>, <strong>KeeperClientLocales</strong>, <strong>KeeperMfaLocales</strong>, <strong>KeeperApprovalLocales</strong>, <strong>KeeperJustificationLocales</strong>, <strong>KeeperMessageLocales</strong>, <strong>KeeperTrayLocales</strong>, <strong>KeeperControlsLocales</strong>, etc., under the service <strong>Localization</strong> directory.</td></tr><tr><td><strong>Structure</strong></td><td><code>"key": { "en_US": "text", "fr_FR": "text", ... }</code>; parameterized strings use <code>{0}</code>, <code>{1}</code>.</td></tr></tbody></table>


---

# Agent Instructions: Querying This Documentation

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

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.keeper.io/keeperpam/endpoint-privilege-manager/reference/localization-service.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
