DocsVuePluginsInternationalization

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-i18n

Registration

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 found

Live 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:

OptionTypeDescription
defaultLocaleLocaleCode(Required) The locale code to use by default (e.g., 'en', 'es').
localesLocale[](Required) An array of locale objects containing translations.
fallbackLocaleLocaleCode(Optional) A locale to use as fallback when a translation is missing in the current locale.
paramResolversParamResolvers(Optional) An object mapping translation keys to parameter resolver functions.

Locale Object

PropertyTypeDescription
codestringThe locale code (e.g., 'en', 'es', 'de').
namestringThe display name of the locale (e.g., 'English', 'Español').
translationsTranslationDictionaryA 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

ParameterTypeDescription
documentId() => string | undefined(Optional) A getter function returning the document ID for document-scoped translations.

Returns

PropertyTypeDescription
translate(key: string, options?: TranslateOptions) => stringFunction to translate a key.
localestringThe current locale code.

TranslateOptions

PropertyTypeDescription
paramsRecord<string, string | number>Parameters to interpolate into the translation (e.g., { level: 150 }).
fallbackstringFallback 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

PropertyTypeDescription
providesRef<I18nCapability | null>A ref object with methods to manage i18n, or null if the plugin is not ready.

I18nCapability Methods

MethodDescription
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

PropTypeDescription
kstring(Required) The translation key.
paramsRecord<string, string | number>(Optional) Parameters to interpolate.
fallbackstring(Optional) Fallback text if translation not found.
documentIdstring(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:

EventTypeDescription
onLocaleChangeEventHook<LocaleChangeEvent>Emitted when the locale changes.
onParamsChangedEventHook<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.

Last updated on December 5, 2025

Need Help?

Join our community for support, discussions, and to contribute to EmbedPDF's development.