i18n Module

About

The localisation module allows you to translate content on client side. This is especially useful if the used (CMS) system is not able to translate the content server side or if no hard reload should happen if the language was changed.

Install

npm install --save @ribajs/i18n

Register

Import i18nModule and a LocalesService implementation (for example LocalesStaticService), then register the module:

import { coreModule, Riba } from "@ribajs/core";
import { ready } from "@ribajs/utils/src/dom.js";
import { i18nModule, LocalesStaticService } from "@ribajs/i18n";

const locales = {
  en: {
    examples: {
      newsletter: { title: "Hello" },
    },
  },
};

const riba = new Riba();
const localesService = new LocalesStaticService(locales);
const model = {};

riba.module.register(coreModule.init());
riba.module.register(i18nModule.init({ localesService }));

ready(() => {
  riba.bind(document.body, model);
});

The root keys of the locales object must be language codes (en, de, …). See LocalesStaticService.

A default export exists only in the browser bundle (browser.ts); from the main package entry use named imports: import { i18nModule } from '@ribajs/i18n'.

Templates

The module reads the default language from the lang attribute on <html>. Set it to one of your locale keys (e.g. en or de):

<!doctype html>
<html lang="en">
  <head>
    ...
  </head>
  <body>
    ...
  </body>
</html>

Events

Events are emitted on the LocalesService instance you pass to i18nModule.init({ localesService }), via localesService.event (an EventDispatcher with namespace 'i18n'). You can subscribe with the same namespace:

import { EventDispatcher } from "@ribajs/events";

const event = new EventDispatcher("i18n");
event.on("changed", (langcode: string, initial: boolean) => {
  console.debug("The language was changed", langcode, initial);
});
event.on("ready", (currentLangcode: string, translationNeeded: boolean) => {
  console.debug(
    "Locales are initialized; module is ready",
    currentLangcode,
    translationNeeded,
  );
});

Alternatively, use localesService.event.on(...) on your registered service (same dispatcher instance as new EventDispatcher('i18n')).

Name Arguments Description
changed langcode, initial The active language was changed.
ready currentLangcode, translationNeeded Locales finished loading and initialization; safe to translate.

Services

LocalesService

The abstract class LocalesService (packages/i18n/src/types/locales-service.ts) is the base for all locale backends. Implementations included in @ribajs/i18n:

Class Purpose
LocalesStaticService In-memory object (de / en / … as keys)
LocalesRestService Load JSON from a URL via HttpService

To implement your own backend, extend LocalesService and implement protected async getAll(): Promise<any> so it returns the same shape as the static service (top-level keys = language codes). Call super(doNotRetranslateDefaultLanguage, showMissingTranslation, autoDetectLangcode) with the three boolean flags expected by the base constructor, then invoke the initialization flow (see LocalesStaticService / LocalesRestService in the source tree for full patterns).

The former name ALocalesService is outdated; the exported abstract type is LocalesService.

LocalesStaticService

The LocalesStaticService can be used to integrate and define the translations directly in the source code:

The root object must use language codes (de, en, …) as keys. Do not wrap translations in an extra property such as locales; otherwise lookups like examples.newsletter.title resolve to en.locales.examples… and fail.

import { LocalesStaticService } from '@ribajs/i18n';

// Your static locales — top-level keys are language codes
const locales = {
  de: {
    examples: {
      newsletter: {
        description_html: 'Abonnieren Sie unseren Newsletter und erhalten Sie <strong>10% Rabatt</strong> auf Ihren nächsten Einkauf.',
        input_value: 'Unbekannt',
        placeholder_last_name: 'Nachname',
        title: 'Melde dich für den Newsletter an',
      },
    },
  },
  en: {
    examples: {
      newsletter: {
        description_html: 'Subscribe to our newsletter and get <strong>10% off</strong> your next purchase.',
        input_value: 'Unknown',
        placeholder_last_name: 'Surname',
        title: 'Sign up for the newsletter',
      },
    },
  },
};

const localesService = new LocalesStaticService(locales);

LocalesRestService

The LocalesRestService loads the translation tree from a URL (JSON). The response should use language codes as top-level keys, same as LocalesStaticService.

import { LocalesRestService } from '@ribajs/i18n';

const url = 'https://example.com/api/locales.json';

const localesService = new LocalesRestService(url);

Constructor signature:

new LocalesRestService(
  url: string,
  doNotRetranslateDefaultLanguage?: boolean,
  showMissingTranslation?: boolean,
  autoDetectLangcode?: boolean,
)

If the page runs in a Shopify theme context, the service may append ?shop=… to the request (see implementation).

Binders

i18n-[type]

Gets the (current selected) translation of a keypath string from your locales object (over the TranslationService). The translation is set as html, text or value depending on the passed type, available types are html, text and value. If the type is not known, the translation is instead set as an attribute with the given name, a useful example for this could be the placeholder attribute.

i18n-text

i18n-html

i18n-value

i18n-[attributeName]

Formatters

t

This formatter resolves a translation key path and now re-renders when the active language changes. For element content/attributes, the i18n-* binders (rv-i18n-text, rv-i18n-html, …) are still recommended because they are more explicit and support rich translation templates directly.

In mustache text nodes, Riba’s default delimiters are a single { and } (see configuration: templateDelimiters). That differs from Liquid/Shopify, which use {{ and }} — do not copy that syntax here.

{ 'examples.newsletter.title' | t }

Components

i18n-switcher

Use this component to switch to another available language. It does not ship with a template: add your own markup as children (e.g. buttons bound to langcodes).

Types

export interface Langcode {
  code: string;
  active: boolean;
}

Template methods

Name Arguments Description
switch langcode: Langcode Activates the given language (Langcode.code) if it is not already active
toggle Switches to the other language (only useful when exactly two languages exist)

Template properties

Name Type Description
langcodes Langcode[] Language codes from your locales object (with active set for the current one)
ready boolean Is true if the locales are initialized
Riba.js © 2026 ·GitHub · Version 2.0.0-rc.23