I18n Plugin
The I18n Plugin provides comprehensive internationalization (i18n) support for your PDF viewer. It enables you to translate all UI text into multiple languages, handle dynamic parameters in translations, and manage locale changes across your application.
This plugin is essential for building PDF viewers that need to support users in different languages and regions.
Installation
The plugin is available as a separate NPM package.
npm install @embedpdf/plugin-i18nRegistration
Import I18nPluginPackage and add it to the plugins array. You must provide at least one locale and specify a default locale.
import { createPluginRegistration } from '@embedpdf/core'
import { EmbedPDF } from '@embedpdf/core/vue'
// ... other imports
import { I18nPluginPackage, type Locale } from '@embedpdf/plugin-i18n/vue'
const englishLocale: Locale = {
code: 'en',
name: 'English',
translations: {
zoom: {
in: 'Zoom In',
out: 'Zoom Out',
fitPage: 'Fit to Page',
},
document: {
open: 'Open',
close: 'Close',
},
},
}
const spanishLocale: Locale = {
code: 'es',
name: 'Español',
translations: {
zoom: {
in: 'Acercar',
out: 'Alejar',
fitPage: 'Ajustar a la página',
},
document: {
open: 'Abrir',
close: 'Cerrar',
},
},
}
const plugins = [
// ... other plugins
createPluginRegistration(I18nPluginPackage, {
defaultLocale: 'en',
locales: [englishLocale, spanishLocale],
// Optional: Specify a fallback locale if translation is missing
fallbackLocale: 'en',
}),
]Usage
The plugin provides composables for translating text and components for inline translations.
Using the useTranslations Composable
The useTranslations composable is the primary way to translate text in your components. It automatically updates when the locale changes or when translation parameters change.
<script setup lang="ts">
import { useTranslations } from '@embedpdf/plugin-i18n/vue'
const props = defineProps<{ documentId: string }>();
const { translate, locale } = useTranslations(() => props.documentId);
</script>
<template>
<div>
<button>{{ translate('zoom.in') }}</button>
<button>{{ translate('zoom.out') }}</button>
<button>{{ translate('zoom.fitPage') }}</button>
<span>Current locale: {{ locale }}</span>
</div>
</template>Using the <Translate /> Component
For simple inline translations, you can use the <Translate /> component.
<script setup lang="ts">
import { Translate } from '@embedpdf/plugin-i18n/vue'
</script>
<template>
<div>
<button>
<Translate k="zoom.in" />
</button>
<button>
<Translate k="zoom.out" />
</button>
</div>
</template>Translation with Parameters
You can include dynamic parameters in your translations using {paramName} syntax.
// In your locale definition
const locale: Locale = {
code: 'en',
name: 'English',
translations: {
zoom: {
level: 'Zoom Level ({level}%)',
},
search: {
resultsFound: '{count} results found',
},
},
}
// In your component
const { translate } = useTranslations()
translate('zoom.level', { params: { level: 150 } })
// Returns: "Zoom Level (150%)"
translate('search.resultsFound', { params: { count: 42 } })
// Returns: "42 results found"Param Resolvers
For translations that depend on plugin state (like current zoom level or search results), you can register param resolvers. These automatically resolve parameters based on the current state.
import type { ParamResolvers } from '@embedpdf/plugin-i18n/vue'
import { ZOOM_PLUGIN_ID } from '@embedpdf/plugin-zoom'
const paramResolvers: ParamResolvers = {
'zoom.level': ({ state, documentId }) => {
const zoomState = documentId
? state.plugins[ZOOM_PLUGIN_ID]?.documents[documentId]
: null
const zoomLevel = zoomState?.currentZoomLevel ?? 1
return {
level: Math.round(zoomLevel * 100),
}
},
'search.resultsFound': ({ state, documentId }) => {
const searchState = documentId
? state.plugins['search']?.documents[documentId]
: null
return {
count: searchState?.total ?? 0,
}
},
}
// Register when creating plugins
createPluginRegistration(I18nPluginPackage, {
defaultLocale: 'en',
locales: [englishLocale, spanishLocale],
paramResolvers,
})When you use a translation key with a registered param resolver, the parameters are automatically resolved:
<script setup lang="ts">
// No need to pass params - they're resolved automatically
const { translate } = useTranslations(() => props.documentId)
// In your template:
// translate('zoom.level') - Automatically uses current zoom level
// translate('search.resultsFound') - Automatically uses current search result count
</script>Changing Locale
Use the useI18nCapability composable to change the locale programmatically.
<script setup lang="ts">
import { computed } from 'vue';
import { useI18nCapability } from '@embedpdf/plugin-i18n/vue'
const { provides } = useI18nCapability();
const currentLocale = computed(() => provides.value?.getLocale() ?? 'en');
const availableLocales = computed(() => provides.value?.getAvailableLocales() ?? []);
const handleLocaleChange = (e: Event) => {
const target = e.target as HTMLSelectElement;
provides.value?.setLocale(target.value);
};
</script>
<template>
<select :value="currentLocale" @change="handleLocaleChange">
<option v-for="code in availableLocales" :key="code" :value="code">
{{ provides?.getLocaleInfo(code)?.name ?? code }}
</option>
</select>
</template>Document-Scoped Translations
When working with multiple documents, translations can be document-scoped. This is especially useful for param resolvers that depend on document-specific state.
<script setup lang="ts">
// Global translation (no document context)
const { translate: globalTranslate } = useTranslations()
globalTranslate('document.open') // "Open"
// Document-scoped translation (uses document-specific param resolvers)
const props = defineProps<{ documentId: string }>();
const { translate } = useTranslations(() => props.documentId)
translate('zoom.level') // Uses zoom level for this specific document
translate('search.resultsFound') // Uses search results for this specific document
</script>Fallback Translations
If a translation key is not found, you can provide a fallback string:
const { translate } = useTranslations()
translate('unknown.key', { fallback: 'Default Text' })
// Returns: "Default Text" if translation not foundLive Example
This example demonstrates a PDF viewer with internationalization support. You can switch between English, Spanish, and German, and see all UI text update automatically.
API Reference
Configuration (I18nPluginConfig)
You can pass these options when registering the plugin with createPluginRegistration:
| Option | Type | Description |
|---|---|---|
defaultLocale | LocaleCode | (Required) The locale code to use by default (e.g., 'en', 'es'). |
locales | Locale[] | (Required) An array of locale objects containing translations. |
fallbackLocale | LocaleCode | (Optional) A locale to use as fallback when a translation is missing in the current locale. |
paramResolvers | ParamResolvers | (Optional) An object mapping translation keys to parameter resolver functions. |
Locale Object
| Property | Type | Description |
|---|---|---|
code | string | The locale code (e.g., 'en', 'es', 'de'). |
name | string | The display name of the locale (e.g., 'English', 'Español'). |
translations | TranslationDictionary | A nested object containing all translations. Use dot notation to access (e.g., 'zoom.in'). |
Composable: useTranslations(documentId?)
The primary composable for translating text in components. Automatically updates when locale or parameters change.
Parameters
| Parameter | Type | Description |
|---|---|---|
documentId | () => string | undefined | (Optional) A getter function returning the document ID for document-scoped translations. |
Returns
| Property | Type | Description |
|---|---|---|
translate | (key: string, options?: TranslateOptions) => string | Function to translate a key. |
locale | string | The current locale code. |
TranslateOptions
| Property | Type | Description |
|---|---|---|
params | Record<string, string | number> | Parameters to interpolate into the translation (e.g., { level: 150 }). |
fallback | string | Fallback text if translation is not found. |
Composable: useTranslation(key, options?, documentId?)
A convenience composable for translating a single key. Useful for derived state or simple translations.
<script setup lang="ts">
const zoomLabel = useTranslation('zoom.in', undefined, () => props.documentId)
</script>Composable: useLocale()
Returns the current locale code. Updates automatically when locale changes.
<script setup lang="ts">
const locale = useLocale() // Ref<'en' | 'es' | 'de' | etc.>
</script>Composable: useI18nCapability()
Provides access to all i18n operations.
Returns
| Property | Type | Description |
|---|---|---|
provides | Ref<I18nCapability | null> | A ref object with methods to manage i18n, or null if the plugin is not ready. |
I18nCapability Methods
| Method | Description |
|---|---|
t(key, options?) | Translate a key. Supports documentId, params, and fallback in options. |
forDocument(documentId) | Get a document-scoped translation API. Returns an I18nScope object. |
setLocale(locale) | Change the current locale. |
getLocale() | Get the current locale code. |
getAvailableLocales() | Get an array of all available locale codes. |
getLocaleInfo(code) | Get the locale object for a specific code, or null if not found. |
registerLocale(locale) | Dynamically register a new locale. |
hasLocale(code) | Check if a locale is registered. |
registerParamResolver(key, resolver) | Register a parameter resolver for a translation key. |
unregisterParamResolver(key) | Unregister a parameter resolver. |
Component: <Translate />
A component for inline translations.
Props
| Prop | Type | Description |
|---|---|---|
k | string | (Required) The translation key. |
params | Record<string, string | number> | (Optional) Parameters to interpolate. |
fallback | string | (Optional) Fallback text if translation not found. |
documentId | string | (Optional) Document ID for document-scoped translations. |
Param Resolver
A function that resolves dynamic parameters for a translation key based on the current state.
type ParamResolver = (context: {
state: StoreState;
documentId?: string;
}) => Record<string, string | number>;Events
The plugin emits events that you can subscribe to:
| Event | Type | Description |
|---|---|---|
onLocaleChange | EventHook<LocaleChangeEvent> | Emitted when the locale changes. |
onParamsChanged | EventHook<TranslationParamsChangedEvent> | Emitted when translation parameters change for a document. |
Translation keys use dot notation to access nested translation objects. For example, 'zoom.in' accesses translations.zoom.in in your locale definition.
Need Help?
Join our community for support, discussions, and to contribute to EmbedPDF's development.