Skip to main content

Internationalization (i18n)

Customize all UI strings in DialStack components for localization or branding.

Quick Start​

TypeScript
import { en } from '@dialstack/sdk-js';

// Create French locale
const fr = {
...en,
common: {
...en.common,
loading: 'Chargement...',
error: 'Erreur',
noResults: 'Aucun résultat',
},
callLogs: {
...en.callLogs,
title: 'Journal des appels',
empty: 'Aucun appel trouvé',
},
};

<CallLogs locale={fr} />;

Locale Structure​

Locale is the type of the built-in English locale, en. It has one section of shared strings and one per component:

SectionUsed by
commonEvery component (loading, errors, pagination, playback)
callLogsCall logs
callHistoryCall history
voicemailsVoicemails
phoneNumbersPhone numbers
phoneNumberOrderingPhoneNumberOrdering
aiAgentAIAgent
softphoneSoftphone
dialPlanDial plan
accountOnboardingOnboarding portal steps
onboardingPortalOnboarding portal shell

Sections nest further (for example callLogs.columns, callLogs.statuses). For every key and its English text, see Locale in the SDK reference or print en from @dialstack/sdk-js.

Common Strings​

Shared across all components:

TypeScript
{
loading: 'Loading...',
error: 'Error',
noResults: 'No results',
delete: 'Delete',
call: 'Call',
cancel: 'Cancel',
confirm: 'Confirm',
previous: 'Previous',
next: 'Next',
perPage: 'Per page',
showing: 'Showing {start}-{end} of {total}',
play: 'Play',
pause: 'Pause',
}

Built-in Locales​

Currently, English is the only built-in locale:

TypeScript
import { en } from '@dialstack/sdk-js';

Creating Custom Locales​

Translating a Locale​

A Locale must define every section, so start from en and replace the strings you translate. Strings you do not replace keep their English text:

TypeScript
import { en, type Locale } from '@dialstack/sdk-js';

const de: Locale = {
...en,
common: {
...en.common,
loading: 'Laden...',
error: 'Fehler',
noResults: 'Keine Ergebnisse',
delete: 'Löschen',
call: 'Anrufen',
cancel: 'Abbrechen',
confirm: 'Bestätigen',
previous: 'Zurück',
next: 'Weiter',
perPage: 'Pro Seite',
showing: 'Zeige {start}-{end} von {total}',
play: 'Abspielen',
pause: 'Pause',
},
callLogs: {
...en.callLogs,
title: 'Anrufliste',
loading: 'Anrufliste wird geladen...',
empty: 'Keine Anrufe gefunden',
columns: {
...en.callLogs.columns,
date: 'Datum',
direction: 'Richtung',
from: 'Von',
to: 'An',
duration: 'Dauer',
},
},
};

Extending English Locale​

Override only specific strings:

TypeScript
import { en } from '@dialstack/sdk-js';

const customEn = {
...en,
common: {
...en.common,
noResults: 'Nothing to show',
},
callLogs: {
...en.callLogs,
title: 'Call History',
empty: 'No calls yet',
},
};

Partial Override​

Override only the section you need:

TypeScript
import { en } from '@dialstack/sdk-js';

const brandedLocale = {
...en,
voicemails: {
...en.voicemails,
title: 'Messages',
empty: 'Your inbox is empty',
},
};

Using Locales​

Per-Component​

TypeScript
<CallLogs locale={customLocale} />
<Voicemails userId={userId} locale={customLocale} />

With Web Components​

JavaScript
const callLogs = document.querySelector('dialstack-call-logs');
callLogs.setLocale(customLocale);

Dynamic Locale Switching​

Change locale at runtime:

TypeScript
function Dashboard() {
const [locale, setLocale] = useState(en);

return (
<div>
<select onChange={(e) => setLocale(locales[e.target.value])}>
<option value="en">English</option>
<option value="fr">Français</option>
<option value="de">Deutsch</option>
</select>

<CallLogs locale={locale} />
<Voicemails userId={userId} locale={locale} />
</div>
);
}

Interpolation​

Some strings support placeholders:

TypeScript
// 'showing' uses {start}, {end}, {total}
showing: 'Showing {start}-{end} of {total}';

// Result: "Showing 1-20 of 150"

Complete Example​

TypeScript
import { useState } from 'react';
import { loadDialstackAndInitialize, en, type Locale } from '@dialstack/sdk-js';
import { DialstackComponentsProvider } from '@dialstack/sdk-react';
import { CallLogs } from '@dialstack/sdk-react/call-logs';
import { Voicemails } from '@dialstack/sdk-react/voicemails';

const es: Locale = {
...en,
common: {
...en.common,
loading: 'Cargando...',
noResults: 'Sin resultados',
delete: 'Eliminar',
call: 'Llamar',
cancel: 'Cancelar',
confirm: 'Confirmar',
previous: 'Anterior',
next: 'Siguiente',
perPage: 'Por página',
showing: 'Mostrando {start}-{end} de {total}',
play: 'Reproducir',
pause: 'Pausar',
},
voicemails: {
...en.voicemails,
title: 'Buzón de voz',
loading: 'Cargando mensajes...',
empty: 'No hay mensajes de voz',
},
callLogs: {
...en.callLogs,
title: 'Registro de llamadas',
loading: 'Cargando llamadas...',
empty: 'No hay llamadas',
},
};

const locales: Record<string, Locale> = { en, es };

const dialstack = await loadDialstackAndInitialize({
publishableKey: 'pk_live_YOUR_KEY',
fetchClientSecret: async () => {
const res = await fetch('/api/dialstack/session', { method: 'POST' });
const { client_secret } = await res.json();
return client_secret;
},
});

function App({ userId }: { userId: string }) {
const [currentLocale, setCurrentLocale] = useState<string>('en');

return (
<DialstackComponentsProvider dialstack={dialstack}>
<div className="p-6">
<div className="flex justify-between items-center mb-6">
<h1 className="text-2xl font-bold">{locales[currentLocale].callLogs.title}</h1>

<select
value={currentLocale}
onChange={(e) => setCurrentLocale(e.target.value)}
className="border rounded px-3 py-2"
>
<option value="en">English</option>
<option value="es">Español</option>
</select>
</div>

<CallLogs locale={locales[currentLocale]} />

<h2 className="text-xl font-bold mt-8 mb-4">{locales[currentLocale].voicemails.title}</h2>

<Voicemails userId={userId} locale={locales[currentLocale]} />
</div>
</DialstackComponentsProvider>
);
}

TypeScript​

Import the Locale type for type safety:

TypeScript
import { en, type Locale } from '@dialstack/sdk-js';

// TypeScript checks that every section and key is present
const myLocale: Locale = { ...en, common: { ...en.common, loading: 'Please wait…' } };

Next Steps​