Skip to content

Internationalization (i18n)

Every user-facing string the picker renders comes from a single label set. Override any subset with the labels option to translate the UI, reword copy, or white-label it — there's nothing else to wire up.

The labels option

Pass a Partial<FilePickerLabels>. Anything you leave out falls back to the built-in English default, so you only supply the strings you actually want to change:

ts
new FilePicker({
  adapter,
  labels: {
    title: 'Médiathèque',
    upload: 'Téléverser',
    done: 'Terminé',
  },
})

The framework bindings spread FilePickerOptions, so labels works the same everywhere — pass it as a prop or option to <FilePicker> in React, Vue, Svelte, Solid or the Web Component.

Static vs. function labels

Most labels are plain strings. A handful are functions that receive interpolation values and return the finished string — use them to place counts, names and numbers exactly where your language needs them:

LabelSignatureDefault
selected(n) => string2 selected
results(n) => string1 result / 5 results
selectAction(n) => stringSelect 3 / Done
perPageOption(n) => string24 / page
pageStatus(page, last, total) => string2 / 5 · 108 items
uploaded(n) => stringUploaded 3 files
uploadSkipped(n) => string2 files skipped — wrong type
editMeta(type, mime, size) => stringType: image · image/jpeg · 812 KB
deleteFileConfirm(name) => stringDelete "photo.jpg"? …
deleteFolderConfirm(name) => stringDelete "Branding"? …
createFolder(name) => stringCreate folder "Press kit"
maxSelection(n) => stringYou can select up to 5 items

Because they're ordinary functions, you get full control over pluralization and word order:

ts
new FilePicker({
  adapter,
  labels: {
    selected: (n) => `${n} sélectionné${n === 1 ? '' : 's'}`,
    pageStatus: (page, last, total) =>
      total > 0
        ? `Page ${page} / ${last} · ${total} élément${total === 1 ? '' : 's'}`
        : `Page ${page} / ${last}`,
  },
})

defaultLabels

The complete English set is exported as defaultLabels, and the FilePickerLabels type describes its shape — both come from the core package:

ts
import { defaultLabels } from '@anil-labs/file-picker-core'
import type { FilePickerLabels } from '@anil-labs/file-picker-core'

Import defaultLabels when you want to see every key, reuse a default while overriding its neighbours, or build a full translation on top of it. Because labels merges over defaultLabels, a partial object is all the picker needs — but typing a complete translation as FilePickerLabels lets TypeScript flag any key you forget.

A French example

ts
import { FilePicker } from '@anil-labs/file-picker-core'
import type { FilePickerLabels } from '@anil-labs/file-picker-core'

const fr: Partial<FilePickerLabels> = {
  title: 'Médiathèque',
  filters: 'Filtres',
  upload: 'Téléverser',
  done: 'Terminé',
  searchPlaceholder: 'Rechercher des fichiers…',
  allTypes: 'Tous les types',
  clearFilters: 'Effacer les filtres',
  refresh: 'Actualiser',
  loading: 'Chargement des médias',
  emptyTitle: 'Votre médiathèque est vide',
  emptyBody: 'Téléversez votre premier fichier pour commencer.',
  emptyUpload: 'Téléverser des fichiers',
  filteredTitle: 'Aucun fichier ne correspond à vos filtres',
  filteredBody: 'Essayez une autre recherche ou effacez les filtres.',
  edit: 'Modifier',
  delete: 'Supprimer',
  cancel: 'Annuler',
  selected: (n) => `${n} sélectionné${n === 1 ? '' : 's'}`,
  results: (n) => (n === 1 ? '1 résultat' : `${n} résultats`),
  uploaded: (n) => (n === 1 ? '1 fichier téléversé' : `${n} fichiers téléversés`),
  deleteFileConfirm: (name) => `Supprimer « ${name} » ? Cette action est irréversible.`,
  pageStatus: (page, last, total) =>
    total > 0
      ? `${page} / ${last} · ${total} élément${total === 1 ? '' : 's'}`
      : `${page} / ${last}`,
}

new FilePicker({ adapter, labels: fr })

See the API reference for the labels option and the full FilePickerLabels type.

Released under the MIT License.