Localization (i18n)
All user-facing strings flow from a single place: config.locale + config.labels. There is one unified dictionary (ChatLabels) covering the composer, reasoning block, tool-call card, message list, and date separators. Built-in dictionaries are provided for en (default) and zh / zh-CN; unknown locales fall back to English.
localealso drivesIntl-based formatting (timestamps and assistant duration viaIntl.NumberFormat/Intl.DurationFormat).labelsis a deep-partial override merged on top of the locale dictionary — supply only the strings you want to change.
const chat = document.querySelector('i-chat');
// 1) Built-in Chinese (one line):
chat.config = { locale: 'zh-CN' };
// 2) Any locale + your own translations (e.g. from vue-i18n / i18next):
chat.config = {
locale: 'fr',
labels: {
composer: { placeholder: 'Écrivez un message…', send: 'Envoyer' },
reasoning: { thinking: 'Réflexion…', reasoning: 'Raisonnement' },
toolCall: { running: 'En cours…', approve: 'Autoriser', reject: 'Refuser' },
messages: { empty: 'Aucun message. Démarrez la conversation\u202f!' },
dateSeparator: {
today: "Aujourd'hui",
yesterday: 'Hier',
daysAgo: (n) => `il y a ${n} jours`,
older: 'Plus ancien',
},
},
};
The library intentionally ships no i18n runtime — translations come from your app (vue-i18n, i18next, …); you just fill in config.labels. Helpers are exported for advanced use: resolveLabels({ locale, labels }), CHAT_LABELS_EN, CHAT_LABELS_ZH_CN (and resolveComposerLabels, COMPOSER_LABELS_* from @bndynet/ichat-input for standalone composer use).
ChatLabels sections: composer (placeholder, send/cancel/voice button labels + titles, listening overlay), reasoning (thinking, reasoning), toolCall (state labels, section headings, approve/reject), messages (empty, dismissError, scrollToLatest), and dateSeparator (today, yesterday, daysAgo(n), older).
The older
config.dateSeparatorLabelsstill works but is deprecated — preferconfig.labels.dateSeparator.
Plurals (makeDaysAgo)
dateSeparator.daysAgo(n) is a function so you control grammar. For languages with several plural forms (Russian, Arabic, Polish, …) a single template is wrong. Use makeDaysAgo(locale, forms) — it picks the correct CLDR plural category via Intl.PluralRules. Provide a template per category (one / two / few / many / other); other is the required fallback:
import { makeDaysAgo } from '@bndynet/ichat';
chat.config = {
locale: 'ru',
labels: {
dateSeparator: {
today: 'сегодня',
yesterday: 'вчера',
older: 'ранее',
daysAgo: makeDaysAgo('ru', {
one: (n) => `${n} день назад`,
few: (n) => `${n} дня назад`,
many: (n) => `${n} дней назад`,
other: (n) => `${n} дней назад`,
}),
},
},
};
Right-to-left (RTL)
All component styles use CSS logical properties (margin-inline-*, padding-inline-*, border-inline-*, inset-inline-*, logical border-*-radius, text-align: start/end), so the layout mirrors automatically for RTL languages. Just set dir="rtl" on <i-chat> (or any ancestor) — direction inherits into the shadow DOM, flipping bubble alignment, avatars, the speech-bubble "tail", quote bars, the reasoning chevron, etc.
<i-chat dir="rtl" .config=${{ locale: 'ar', labels: arabicLabels }}></i-chat>
The demo's Chat page has a language switcher (English / 简体中文 / العربية) that toggles dir so you can see RTL + makeDaysAgo live.