# Locale

The viewer's language, and your translations. The SDK ships English only: the string table is the contract, and you supply the languages. A translation is a `Partial<UIStrings>` (`UIStringKey = keyof typeof EN_STRINGS`): the keys are typed, so a misspelt key is a compile error and your editor completes them. The full list, with the English text, is in the exported `EN_STRINGS`; the groups are summarized in the table below.

- Interface: `LocaleConfig`
- Config path: `config.locale`

## Example

```ts
import type { UIStrings } from '@kernstra/pdf-web-sdk';

const german: Partial<UIStrings> = {
  'cluster.highlight': 'Markieren', // the toolbar button
  'tool.sign': 'Unterschreiben',
  'common.download': 'Herunterladen', // the toolbar button; 'download.title' is the dialog's title
  'common.pageCount': '{n, plural, one {# Seite} other {# Seiten}}',
};

new PDFViewer(container, doc, {
  locale: {
    lang: user.language, // 'de-AT'
    translations: {
      de: german,
      fr: { 'cluster.highlight': 'Surligner', 'tool.sign': 'Signer' },
    },
  },
});
```

## Options (3)

### `lang`

- Type: `string`
- Default: `'en'`
- Page: https://kernstra.com/docs/web-sdk/config/locale/lang

A BCP-47 tag, e.g. `'de-AT'`. It picks a table from `translations` and drives numbers and dates through `Intl`: zoom percentages, file sizes (the number; the unit is the `common.bytes.*` key, so French can say `Mo`), page counts, and dates in the signatures panel. Dates use the language's medium style ("Oct 7, 2026", "07.10.2026"); a signing time in the signatures panel shows the time the file records, not converted to the reader's time zone. Lists such as the Image tool's accepted types are joined the language's way ("PNG, JPEG, or GIF"). The viewer sets `lang` on its own element from this value, so screen readers pronounce the labels in that language; dialogs that open outside the viewer carry it too.

An invalid `lang` formats numbers and dates in English (a translation stored under exactly that string is still used). `lang` and the keys of `translations` are read in their canonical form (`de-at` becomes `de-AT`).

### `strings`

- Type: `Partial<UIStrings>`
- Page: https://kernstra.com/docs/web-sdk/config/locale/strings

Overrides for this viewer, whatever the language. `strings` wins over `translations`. Some tools have a short label for the toolbar and a full one for tooltips: `tool.editText.short`, `tool.addText.short` and `tool.managePages.short`. Translate both.

```ts
new PDFViewer(container, doc, {
  locale: { strings: { 'common.download': 'Save a copy', 'tool.sign': 'Sign here' } },
});
```

### `translations`

- Type: `Record<string, Partial<UIStrings>>`
- Page: https://kernstra.com/docs/web-sdk/config/locale/translations

Several languages; `lang` picks one. Type a complete table as `UIStrings` (`satisfies UIStrings`) and the compiler lists every key you have not translated. Load it however you like (a dynamic `import()` per language works), but have it in hand before you build the viewer: translations are read once, when the viewer is built. A key the SDK does not have is ignored without a warning, so after upgrading, compare your table with `EN_STRINGS`.

```ts
import { EN_STRINGS } from '@kernstra/pdf-web-sdk';
const missing = Object.keys(EN_STRINGS).filter((key) => !(key in german));
```

## The key groups of EN_STRINGS (725 keys)

| Group | Keys | What it covers |
| --- | --- | --- |
| `common.*` | 26 | Shared button labels (Cancel, Close, Done, Save, Delete, Download, Print …), size units (`common.bytes.*`), page labels and the page-count plural. |
| `tool.*`, `group.*`, `cluster.*`, `key.*` | 45 | Tool names (with the `.short` toolbar labels), toolbar group and cluster labels, key names. |
| `viewer.*`, `download.*`, `print.*`, `pageScope.*` | 35 | The viewer's own labels and loading/error messages, the Download and Print dialogs, the page-scope choices (all, current, range). |
| `fields.*`, `thumbs.*`, `search.*`, `nav.*`, `toolbar.*`, `permission.*`, `certified.*`, `sidebar.*`, `outline.*`, `attachments.*`, `signatures.*`, `textLayer.*`, `phone.*`, `links.*` | 135 | Form fields and the stepper, thumbnails, the search bar, the navigation bar, the toolbar, document permissions and certification notices, the sidebar and its Outline, Attachments and Signatures tabs, the text layer, the phone shell, and link pills. |
| `states.*`, `dropZone.*`, `progress.*`, `colorPicker.*`, `color.*`, `weight.*` | 54 | The document states (error, password, offline), the drop zone, progress cards, the color picker, the built-in color names and line weights. |
| `confirm.*` | 22 | The confirmation questions, their messages and the Discard / Replace buttons (see [Confirmations](https://kernstra.com/docs/web-sdk/config/confirmations)). |
| `pages.*` | 21 | The Manage Pages dialog. |
| `security.*` | 69 | The Security tool: passwords and permissions. |
| `object.*`, `subject.*`, `erase.*`, `highlight.*`, `image.*`, `link.*`, `note.*`, `ink.*`, `select.*`, `sign.*`, `stamp.*`, `marks.*` | 177 | Selected objects and their action bar, annotation subjects, and the Erase, Highlight, Image, Link, Note, Select, Sign, Stamp and Marks tools, including the built-in ink names and the standard stamp wordings. |
| `comments.*` | 36 | The Comments panel: replies and review statuses. |
| `signature.*` | 33 | The signature dialog and its fonts; `signature.alt` is what a screen reader reads for a placed signature. |
| `text.*`, `addText.*`, `freeText.*`, `editText.*` | 33 | The Add Text, Text box and Edit Text tools and their options bars. |
| `drawing.*`, `shape.*`, `style.*`, `ending.*` | 39 | The drawing tools and shapes, the border Style picker and the Line and Arrow Ends picker. |

## Notes

**How a key resolves.** `strings`, then `translations[lang]`, then the base language (`de-AT` → `de`), then English. A partial translation shows English where it has gaps, not a key. An empty string is a value: `''` shows nothing. The fallback goes straight from the full tag to its first part: `zh-Hant-TW` falls back to `zh`, never to `zh-Hant`.

**Placeholders and plurals.** Some values carry `{name}` placeholders — keep them; a number put into one is formatted for `lang` (1234 → "1,234" in English, "1.234" in German), and a placeholder you misspell prints as written. Counts use a plural, `{n, plural, one {# page} other {# pages}}`: `#` is the number, and the branches are the language's own plural categories (`zero`, `one`, `two`, `few`, `many`, `other`) or an exact value such as `=0` or `=2`, chosen with `Intl.PluralRules` for `lang` (an exact value wins; `other` is the fallback). For example `pl: { 'common.pageCount': '{n, plural, one {# strona} few {# strony} many {# stron} other {# strony}}' }`.

**The syntax has `{name}` and `plural` only.** `select`, `selectordinal`, `offset:` and apostrophe quoting are not supported, and there is no escape character: a `select` prints as written, and so does a `{` that is never closed. Inside a plural branch every `#` is the number. A branch missing for a count falls back to `other`, or to the first branch when there is no `other`.

**What goes into the PDF.** The standard stamps' words (a tick, a cross and a dot have none) and the date a dated stamp burns in are written with the viewer's language at the moment the stamp is placed — they are content, and stay as written if the document is later opened in another language. A form field that uses Acrobat's number, date or time formats shows and stores its value in the field's own format, as Acrobat does, whatever `lang` is.

**What stays English.** Error messages (`SDKError.message`, the `error` event's) are for your logs; show your own copy for the error `code` (see [Errors](https://kernstra.com/docs/web-sdk/api/errors)). What the SDK shows or tells a screen reader about an error is from the table (`viewer.error.*`, `states.error.*`). The watermark is not translatable; the "License required" popup is outside the viewer and its table, and takes your own words through [`Kernstra.init({ licensePopup })`](https://kernstra.com/docs/web-sdk/config/init/licensepopup) — see [Licensing](https://kernstra.com/docs/web-sdk/guides/licensing).

**Right-to-left languages.** You can translate the table into Arabic, Hebrew or Persian, but the viewer's layout stays left-to-right: toolbars, panels and dialogs are not mirrored. Document text in those scripts renders and searches normally. Edit Text and Add Text handle text that is entirely right-to-left; a line that mixes right-to-left and left-to-right text is not yet laid out in mixed directions.

**Changing language** means building a new viewer: the chrome is built once. The same is true of `theme`, `toolbar` (including `icons` and `actions`), the picker lists and `layout`: a viewer reads its configuration once. To switch, call [`viewer.destroy()`](https://kernstra.com/docs/web-sdk/api/pdfviewer/destroy) and build a new viewer on the same `doc`. The document and the edits made to it are kept, but not what was typed or signed into form fields, which lives in the viewer until export: read [`doc.forms.getValues()`](https://kernstra.com/docs/web-sdk/api/doc-forms/getvalues) first and give it back to [`doc.forms.setValues()`](https://kernstra.com/docs/web-sdk/api/doc-forms/setvalues) once the new viewer is open. Undo history and the current page start fresh (call [`goToPage`](https://kernstra.com/docs/web-sdk/api/pdfviewer/gotopage) to restore the page).

Outside a viewer, [`createDropZone`](https://kernstra.com/docs/web-sdk/api/helpers/createdropzone), [`createPasswordPrompt`](https://kernstra.com/docs/web-sdk/api/helpers/createpasswordprompt) and [`createLoadError`](https://kernstra.com/docs/web-sdk/api/helpers/createloaderror) take the same object as `options.locale`, as does [`PDFViewer.showLoadingIndicator(container, { loader, locale })`](https://kernstra.com/docs/web-sdk/api/pdfviewer/showloadingindicator).


Web page: https://kernstra.com/docs/web-sdk/config/locale
