Translations
The viewer speaks the user’s language: it picks the best match from the browser’s languages. To
choose one yourself, set locale:
{ locale: 'de' }locale follows its prop, so a language switch in your app switches the viewer too. Without it,
or with 'auto', the viewer follows the browser.
The languages it speaks#
English, German, French, Spanish, Italian, Dutch, Portuguese, Polish, Swedish, Japanese, Chinese
(Simplified and Traditional), Korean, Arabic and Hebrew. Each one loads only when it’s needed. For
Arabic and Hebrew, the viewer is right-to-left: the bars mirror, and start and end swap sides.
A language matches in its own script: readers in Taiwan and Hong Kong (zh-TW, zh-HK) see
Traditional Chinese, and readers in China and Singapore (zh-CN, zh-SG) Simplified.
Change a word#
A built-in button’s label has the command’s id as its key. Give a new one, per language:
{
strings: {
en: { 'document:download': 'Save a copy' },
de: { 'document:download': 'Kopie speichern' },
},
}A panel’s button and the title in its header are one word, under the button’s command id:
'panel:comments' renames both. See Panels.
A mode tab is a button too, with the command mode:annotate for Annotate. Here a picker in your
app sets locale, and strings gives two labels your own words in each language it offers:
Loading live preview…
<link rel="stylesheet" href="./languages.css" />
<div class="app">
<header class="bar">
<select id="language" aria-label="Language">
<option value="en">English</option>
<option value="de">Deutsch</option>
<option value="fr">Français</option>
<option value="nl">Nederlands</option>
<option value="ar">العربية</option>
</select>
</header>
<embedpdf-viewer id="viewer" class="viewer"></embedpdf-viewer>
</div>
<script type="module">
import 'https://cdn.jsdelivr.net/npm/@embedpdf/viewer@3/dist/embedpdf.js';
const welcome = '/pdfs/welcome.pdf';
const viewer = document.getElementById('viewer');
const language = document.getElementById('language');
viewer.config = {
src: welcome,
locale: language.value,
// Your own words for two of the viewer's labels, in each language.
strings: {
en: { 'mode:annotate': 'Review', 'document:download': 'Save a copy' },
de: { 'mode:annotate': 'Prüfen', 'document:download': 'Kopie speichern' },
fr: { 'mode:annotate': 'Relire', 'document:download': 'Enregistrer une copie' },
nl: { 'mode:annotate': 'Nakijken', 'document:download': 'Kopie opslaan' },
ar: { 'mode:annotate': 'مراجعة', 'document:download': 'حفظ نسخة' },
},
};
language.addEventListener('change', () => (viewer.locale = language.value));
</script>Try it: the second tab reads Review instead of Annotate, and the menu at the top left has Save a copy. Pick Deutsch above the viewer: every word changes, yours too. Pick العربية and the bars mirror.
Translate your own buttons#
Give a command a labelKey instead of a label, and its words per language:
{
commands: [{ id: 'acme:send', labelKey: 'acme.send', icon: 'signature', run: send }],
strings: {
en: { 'acme.send': 'Send for signature' },
nl: { 'acme.send': 'Verstuur ter ondertekening' },
},
}Panels and mode bars take a titleKey the same way, for their title. A panel’s title is its
button’s label too.
The style panel’s words have keys too: each property and option by what it says
(annotation.style.stroke, annotation.style.opacity, annotation.lineEndings.openArrow), and a
form field’s settings by theirs (form.settings.tooltip). Change one like any other word:
{ strings: { en: { 'annotation.style.stroke': 'Line' } } }So do the page number’s words, under pageNumber., and the comments panel’s, under comments..
The ones you’re most likely to change:
| Key | What it says |
|---|---|
pageNumber.page | {current} / {total} |
pageNumber.pages | {first}–{last} / {total}, while a spread fits across the view (spread) |
pageNumber.goToPage | The tooltip of the page number, and the label of the field it turns into |
comments.empty, comments.emptyReadOnly | What the panel says while the document has no comments, when the user can add some and when not |
comments.addPlaceholder, comments.replyPlaceholder, comments.reply | The field for a new comment, and for a reply |
comments.statusAccepted, comments.statusRejected, comments.statusCancelled, comments.statusCompleted, comments.statusNone | A thread’s status |
A word in braces is filled in as the viewer writes it: keep it in your words. The number that turns
into a field to type a page is {current}, or {first}:
{ strings: { en: { 'pageNumber.page': 'Page {current} of {total}', 'comments.empty': 'No notes yet.' } } }A language of your own#
Give strings for a language the viewer doesn’t have, and it becomes one of its languages. Anything
you don’t translate shows in English:
{
locale: 'da',
strings: { da: { 'document:download': 'Hent', 'zoom:in': 'Zoom ind' } },
}It reads right to left when its code says so: a right-to-left language such as fa or ur, or a
right-to-left script such as ku-Arab.
Good to know#
Change the language from code#
viewer.get('i18n').setLocale('fr') does the same as the locale prop, and returns a promise that
resolves once the language has loaded.
Add words while the app runs#
viewer.get('i18n').addTranslations('nl', { … }) adds or replaces words in a language without
starting over, for words that arrive from your own translation service.
Labels in the toolbar#
The toolbar measures the words it shows, so a longer translation moves fewer or more buttons into the “More” menu by itself.
Your feedback goes directly to the documentation team.