Internationalisation
Announcements default to English. Every announcement is a function, not a template string, so it can interpolate the position, pluralise properly, and phrase RTL text the way that language actually works.
Using a bundled locale
Section titled “Using a bundled locale”Other languages are opt-in files under src/locales/. Loading one — after the
library itself — registers it on Sorta11y.locales under its language code, and
from then on the name is all you need:
<script src="sorta11y.js"></script><script src="sorta11y/locales/de.js"></script><script> Sorta11y.setDefaultLabels("de"); // make German the default… const list = Sorta11y.create(el, { locale: "de" }); // …or pick per instance</script>Importing the file registers it the same way — with a bundler, in Node, as CommonJS or as ESM:
import Sorta11y from "sorta11y";import "sorta11y/locales/de"; // registers Sorta11y.locales.de
const list = Sorta11y.create(el, { locale: "de" });Each locale file also exports its labels object, so you can pass that directly instead of a name:
import de from "sorta11y/locales/de";
Sorta11y.setDefaultLabels(de);Your own wording
Section titled “Your own wording”A fully custom labels object always wins. This is the integration path for apps
that already ship their own translation files — you do not have to adopt a second
translation system for one widget:
Sorta11y.create(el, { labels: { grabbed: (c) => `Aufgenommen: ${c.itemLabel}. Position ${c.position} von ${c.total}.`, dropped: (c) => `Abgelegt an Position ${c.position} von ${c.total}.`, moved: (c) => `Position ${c.position} von ${c.total}.`, cancelled: (c) => `Abgebrochen. Zurück auf Position ${c.position}.`, instructions: "Sortierbar. Leertaste zum Aufnehmen, Pfeiltasten zum Bewegen, " + "Leertaste zum Ablegen, Escape zum Abbrechen.", applicationLabel: "Sortierbare Liste", },});Partial objects are fine — anything you leave out falls back to the locale or the built-in English.
The label set
Section titled “The label set”| Key | Type | Used for |
|---|---|---|
instructions | string | The hidden aria-describedby text on each item |
applicationLabel | string | Accessible name for the role="application" wrapper, when the list has no aria-label/aria-labelledby to mirror |
grabbed | function | Announced on pickup |
moved | function | Announced after each move while held |
dropped | function | Announced on drop |
cancelled | function | Announced on Esc or an aborted grab or drag |
Each key also takes the other type: a string for an announcement is spoken
verbatim, and a function for instructions or applicationLabel is called
with an empty context.
The context object
Section titled “The context object”Each label function receives one argument:
const context = { itemLabel, // string — the item's aria-label, data-label, or text content position, // number — 1-indexed total, // number — item count announceTotal, // boolean — the announceTotal option, for "of Y" phrasing order, // (string | null)[] — the current order of data-ids (null: no id)};itemLabel can be an empty string when an item has no accessible name, so guard
against it the way the built-in labels do:
const name = (c) => (c.itemLabel ? `${c.itemLabel}, ` : "");Precedence
Section titled “Precedence”From lowest to highest — the later one always wins:
- Built-in English
Sorta11y.setDefaultLabels(labelsOrLocale)— a global default{ locale: "de" }— per instance{ labels: {…} }— per instance, explicit
setDefaultLabels() applies to lists created after the call, so call it
before create() or autoInit(). An unknown locale name falls back to the
built-in English.
Both labels and locale can be swapped at runtime; the hidden instructions
element is re-rendered so it follows the switch:
list.option("locale", "de"); // the locale file must already be loadedThe rtl option (and data-rtl with autoInit()) is reserved and currently
has no effect. The list only moves up and down, so there is no axis to mirror;
right-to-left languages are handled by the label functions, which can phrase
each announcement however the language needs.
Contributing a locale
Section titled “Contributing a locale”Locale files are small and self-registering — copy src/locales/en.js, translate
the functions, and open a PR. Announcement wording is a genuinely hard thing to
get right in a second language, so translations from native speakers who actually
use a screen reader are especially welcome.