Socket
Book a DemoInstallSign in
Socket

@dialpad/i18n

Package Overview
Dependencies
Maintainers
3
Versions
2
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@dialpad/i18n

Dialpad's internationalization library

1.19.0
latest
Source
npmnpm
Version published
Weekly downloads
77
71.11%
Maintainers
3
Weekly downloads
 
Created
Source

i18n (Vue 3 compatible)

Introduction

This package contains all the logic needed to take care the i18n of a Dialpad application extending from the common logic existing in the base locale manager that you can find about on the i18n-services documentation, based on different bundle sources.

How it works?

There are essentially two main concepts behind the scenes:

LocaleManager

The LocaleManager extends the BaseLocaleManager to oversee the internationalization (i18n) in a Vue3.js application using the Fluent localization framework. Its responsibilities include:

  • Loading and caching translation bundles: Manages the .ftl data, which maps keys to text for each locale.
  • Switching the current locale: Provides methods to change the active language dynamically.
  • Handling bundle namespaces: Manages potential duplicate bundle requests from multiple sources, though this feature is still being refined.
  • Initializing the Vue plugin: Exposes translation methods ($t, $ta) to Vue templates, enabling localized content within the application.

BundleSource

The second key concept is the BundleSource interface, which abstracts the loading and management of localization resources. This interface has two primary implementations: RawBundleSource and HTTPBundleSource, each designed for different use cases.

  • RawBundleSource: This implementation handles localization resources defined within the application. It organizes these resources defined directly in the application, and imported directly at runtime (for example, using import(./[locale].ftl). This approach is ideal for applications with mostly static content.

  • HTTPBundleSource: This implementation fetches localization resources dynamically from a server. It caches these resources locally, allowing for efficient access while still being flexible enough to load translations on demand.

Disclaimer: Both implementations are provisional and may change as we better understand our needs. Currently, RawBundleSource is the preferred option for most applications.

Synchronous Resource Loading with builtResources

While the dynamicResources method is used for asynchronously loading resources, the RawBundleSource class also provides a builtResources method for synchronous resource loading. This is useful when you have the localization resources available at compile time and prefer to import them directly without dealing with promises.

How to use builtResources

Instead of dynamically importing .ftl files, you can import them directly and use the builtResources method to process the resources. Here's an example:

import { RawBundleSource } from '@dialpad/i18n-services';
// Import your .ftl files directly
import enUSResource from './locales/en-US.ftl';
import esResource from './locales/es.ftl';

// Create an array of BuiltResource objects
const builtResourcesArray: BuiltResource[] = [
  ['en-US', 'namespace', enUSResource],
  ['es', 'namespace', esResource],
  // ... add other locales and namespaces as needed
];

// Convert BuiltResource objects to Resource objects using builtResources
const resources: Resource[] =
  RawBundleSource.builtResources(builtResourcesArray);

// Now, resources can be used to instantiate RawBundleSource or for any other purpose
const bundleSource = new RawBundleSource({ resources });

Setup

Installation

pnpm add @dialpad/i18n

Configuration - Static resources

Integrating LocaleManager with Vue using the install Method

When using LocaleManager within a Vue application, (especially in the context of a library, you should be aware that install needs to receive a non-default namespace value) it's important to properly integrate it using the install method. This method registers LocaleManager with the Vue instance, allowing for global access to localization functionalities across the application.

Usage of install

After creating an instance of LocaleManager, you must call the install method. This method accepts an optional namespace parameter, which is particularly useful when you are developing a library and need to avoid conflicts with other potential instances of LocaleManager in the consumer's environment.

By using different namespaces, you can have multiple instances of LocaleManager available globally in Vue. This is ideal for libraries that may be used in conjunction with other Vue plugins or in larger applications where scoped localization management is required.

Parameters
  • namespace: (Optional) The namespace under which the LocaleManager will be registered. Defaults to 'default' if no namespace is provided.
Example
import Vue from 'vue';
import { LocaleManager } from '@dialpad/i18n-vue2';

// Create a LocaleManager instance with your configuration options
const localeManager = new LocaleManager({
  // ... configuration options, see on Dynamic resources configuration section
});

// Install the LocaleManager with a specific namespace to avoid conflicts
localeManager.install('my-namespace');

// Your library's users can now access the LocaleManager instance globally in Vue
new Vue({
  // ... other options
}).$mount('#app');

Configuration - Dynamic resources

We recommend you to include this in your own composable that handle every locale and i18n set up logic, i.e.:

//src/localization/i18n.ts
import type { App } from 'vue';
import { LocaleManager, RawBundleSource } from '@dialpad/i18n';

export async function hostI18NManager({
  vueApp,
}: {
  vueApp: App;
}): Promise<void> {
  const bundleSource = new RawBundleSource({
    resources: await RawBundleSource.dynamicResources([
      ['en-US', 'your-app', import('./en-US.ftl?raw')],
    ]),
  });

  const manager = new LocaleManager({
    bundleSource,
    preferredLocale: 'en-US', // optional
    allowedLocales: ['en-US'], // optional
    fallbackLocale: 'en-US',
    namespaces: ['your-app'],
  });

  await manager.ready;

  vueApp.use(manager);
}

Important note: let's say that you have more than one allowedLocales, or that your fallbackLocale/preferredLocale is different from what you're specifying on the allowedLocales prop to the LocaleManager instance. In those cases you need to verify that you have specified a Bundle resource for each locale, in order to have them working properly, i.e.:

//src/localization/i18n.ts
import type { App } from 'vue';
import { LocaleManager, RawBundleSource } from '@dialpad/i18n';

export async function hostI18NManager({
  vueApp,
}: {
  vueApp: App;
}): Promise<void> {
  const bundleSource = new RawBundleSource({
    resources: await RawBundleSource.dynamicResources([
      // You must **always** have one resource per locale.
      ['dp-DP', 'your-app', import('./dp-DP.ftl?raw')],
      // This one is for the `fallbackLocale`
      ['en-US', 'your-app', import('./en-US.ftl?raw')],
    ]),
  });

  const manager = new LocaleManager({
    bundleSource,
    // I'm using Dialpadistan as my locale
    preferredLocale: 'dp-DP',
    // But my fallback is en-US (if it was part of the locales this is the same concept, **you need to add one resource per locale**)
    fallbackLocale: 'en-US',
    namespaces: ['your-app'],
  });

  await manager.ready;

  vueApp.use(manager);
}

After this, you should plug this into your main.ts. You will call it like:

// src/main.ts

import { createHost } from '@dialpad/host-entry';
import { hostI18NManager } from './localization/i18n';
import { hostEnv } from './constants';

await createHost(hostEnv)
  // ... all your config
  .vueCreated(hostI18NManager)
  // ... some other config
  .start();

Usage

User's locale selection criteria

You will find that this API is (and should always be) the same as the i18n-vue2 tool.

When instantiating the LocaleManager (or when calling setI18N), the preferredLocale and allowedLocales parameters are optional. BUT this is the following criteria to select it.

If preferredLocale param is provided, use that. If allowedLocales param is provided, use the first one. If localStorage contains the previously-used value, use that. If navigator.language is available, use that. Use the fallbackLocale.

First of all you need to understand he difference between $t and $ta, which mainly lies in their outputs:

useI18N() hook API

There are three main functions exported: $t, $ta, and setI18N(), and two exported values: currentLocale and allowedLocales.

(Keep in mind that you should have a fluent file (en-US.ftl in this case) following the Fluent rules.)

$t

Returns a translated string based on a key and optional variables. It’s used for simple text translations.

# src/localization/en-US.ftl
PARAGRAPH_KEY = Amazing paragraph, { $name }
// Component file
const greeting = $t('PARAGRAPH_KEY', { name: 'John' });
// Output: "Amazing paragraph, John"

$ta

Returns an object containing translated attributes to pass directly as props to components, it can contain aria-label, title, etc, rather than just a plain text. It’s useful for handling element attributes in the UI.

# src/localization/en-US.ftl
BUTTON_NAME =
  .aria-label = { $title } now
  .title = { $title }
// Component file
const buttonAttrs = $ta('BUTTON_NAME', { title: 'Submit' });

// Output: { ariaLabel: "Submit now", title: "Submit" }

// Usage:
<template>
  <DtButton v-bind="$ta('BUTTON_NAME', { title: 'Submit' });" />
</template>;

In both cases, any valid fluent syntax is allowed, so the usage of it might include functions or any other feature provided by the framework. (You can find real world examples on this file)

Vue component example - $t, $ta

Here's an example of how to use the LocaleManager in a Vue component.

<script>
/* `useI18N` exposes the `$t` and `$ta` localization methods, **for use in the setup method**, and these are both available by default in templates with no extra calls needed. */

import { useI18N } from '@dialpad/i18n';

const { $t, $ta } = useI18N();
</script>

<template>
  <div>
    <p>{{ $t('PARAGRAPH_KEY') }}</p>
    <button
      v-bind="
        $ta('BUTTON_NAME', {
          name,
        })
      "
    />
  </div>
</template>

using the following Fluent file as example:

# src/localization/en-US.ftl
PARAGRAPH_KEY = Amazing paragraph, { $name }
BUTTON_NAME =
  .aria-label = { $title } now
  .title = { $title }

setI18N

This function receives a Partial<SetLocaleParams>. This allows you to change any of the set up parameters after the initialization of the LocaleManager, but the main use case is to change locales dynamically.

You probably want to use this in addition to:

  • currentLocale, determined by the criteria defined in the usage section.
  • allowedLocales, are all the allowed locale codes, sorted alphabetically, defined during initialization of the LocaleManager.
Vue component example - setI18N, allowedLocales, currentLocales
<script setup lang="ts">
// your imports ...
const { setI18N, allowedLocales, currentLocale } = useI18N();
</script>

<template>
  <DtDropdown placement="bottom-end">
    <template #anchor="{ attrs }">
      <DtButton v-bind="attrs" size="md" importance="clear">
        {{ currentLocale }}
      </DtButton>
    </template>
    <template #list="{ close }">
      <template v-for="locale in allowedLocales" :key="locale">
        <DtListItem
          navigation-type="tab"
          @click="
            setI18N({ locales: locale });
            close();
          "
        >
          {{ locale }}
        </DtListItem>
      </template>
    </template>
  </DtDropdown>
</template>

Dynamically Changing Locales with changeLocale Method

The changeLocale method provides the functionality to dynamically change the current locale of your application. This method can target a specific LocaleManager by namespace or all LocaleManager instances globally.

changeLocale()

To change the locale settings, call the changeLocale method on your LocaleManager instance. You can pass optional parameters to update the locale settings and optionally specify a namespace to target a specific LocaleManager. If no namespace is provided, the locale settings will be updated for all LocaleManager instances.

Parameters
  • args: (Optional) A Partial<SetLocaleParams> object containing the new locale settings to be applied.
  • namespace: (Optional) The namespace of the LocaleManager instance whose locale settings you want to change. If not provided, all instances will be updated.
Behavior
  • Retrieves the map of LocaleManager instances from the Vue prototype.
  • If a namespace is specified, it targets the corresponding LocaleManager and throws an error if it does not exist.
  • If no namespace is specified, it targets all registered LocaleManager instances.
  • Updates the locale settings for the targeted LocaleManager(s) using the provided arguments.
Example
// Assuming you have a LocaleManager instance
const manager = new LocaleManager(...);

// To change the locale settings for a specific namespace
manager.changeLocale({ preferredLocale: 'fr-FR' }, 'myNamespace');

// To change the locale settings for all LocaleManager instances
manager.changeLocale({ preferredLocale: 'fr-FR' });

### Adding Resources at Runtime with `addSources`

#### API Method: `addSources`

The `addSources` method allows you to add multiple translation resources to the `LocaleManager` at runtime. Once all resources are loaded, it triggers the `ready` promise indicating that the locale manager is fully initialized and ready to handle localization requests.

Adding Resources at Runtime with addSources

API Method: addSources

The addSources method allows you to add multiple translation resources to the LocaleManager at runtime. Once all resources are loaded, it triggers the ready promise indicating that the locale manager is fully initialized and ready to handle localization requests.

Parameters
  • sources: An array of BuiltResource items where each item contains:
    • locale: The locale code for the translation resource.
    • namespace: The namespace associated with the resource.
    • source: The actual source string or a promise that resolves to the source string.
Example
// Assuming you have a LocaleManager instance
const manager = new LocaleManager(...);

// Define your resources
const resourcesToAdd: BuiltResource[] = [
  // Array of [locale, namespace, source] tuples
  ['en-US', 'namespace1', sourceStringOrPromise],
  ['es-ES', 'namespace1', anotherSourceStringOrPromise],
  // Add more resources as needed
];

// Add the resources to the LocaleManager
manager.addSources(resourcesToAdd);

Context screenshots

Context screenshots are, as their name suggest, screenshots that provide context to recognize where each translation is used in each app.

Each screenshot should contain visual information of where the translation can be found in the app with enough context to be easily located. If other dev looks at the screenshot they should be able to locate it fairly easily in your app.

There should be one screenshot per each translation key on each .ftl file. You can reuse the same screenshot for multiple keys, but each file will correspond to one key, so you must make one copy for each translation key. The screenshot filename will be {translationKeyHere}.png. We only support .png images for now.

There is a PR check which will fail if any translation key is missing its corresponding screenshot. There is an exception list for paths that should be ignored by this check. Avoid using it unless it's completely necessary. If you strictly need to use it, remember to mention in your commit message why you are using it.

These screenshots will be located in a directory called context-screenshots sibling to each .ftl file in your project. If you have an .ftl file, it should have a sibling screenshots directory. Each screenshot has a file size limit of 20MB.

The screenshots are uploaded to smartling along with the CSV/FTL files through a github action when a PR to main is merged.

Resources

FAQs

Package last updated on 25 Aug 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

About

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.

  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc

U.S. Patent No. 12,346,443 & 12,314,394. Other pending.