Localization

Overview

rs-grid ships with 15 built-in locales and supports custom translations. All user-visible strings in the grid chrome (context menu, search bar) are driven by a Locale struct that can be swapped at any time.

The grid can also auto-detect the browser language and select the matching locale automatically.

Built-in locales

CodeLanguageConstructor
enEnglishLocale::en()
frFrançaisLocale::fr()
deDeutschLocale::de()
esEspañolLocale::es()
itItalianoLocale::it()
ptPortuguêsLocale::pt()
nlNederlandsLocale::nl()
plPolskiLocale::pl()
trTürkçeLocale::tr()
ruРусскийLocale::ru()
ukУкраїнськаLocale::uk()
arالعربيةLocale::ar()
ja日本語Locale::ja()
zh中文Locale::zh()
ko한국어Locale::ko()

Browser language detection

Locale::from_browser() reads navigator.language and returns the best matching built-in locale. It matches on the primary subtag only — "fr-FR", "fr-CA", and "fr" all resolve to Locale::fr(). Unknown languages fall back to English.

// Auto-detect — the grid starts in the user's language
let locale = Locale::from_browser();

You can also match a BCP 47 tag manually:

let locale = Locale::from_language_tag("pt-BR"); // → Locale::pt()

Framework usage

Leptos
Vanilla JS
Dioxus
Yew

The <GridCanvas> component accepts an optional reactive locale prop. When the signal changes, the grid updates its UI strings in place without remounting.

use rs_grid_leptos::{GridCanvas, Locale};

// Detect browser language on startup
let locale = RwSignal::new(Locale::from_browser());

view! {
    <GridCanvas
        model=model
        locale=Signal::derive(move || locale.get())
    />
}

To switch language at runtime:

locale.set(Locale::de());

Translated strings

The Locale struct contains all UI chrome strings:

FieldEnglish defaultUsed in
cutCutContext menu
copyCopyContext menu
copy_with_headersCopy with headersContext menu
pastePasteContext menu
pin_columnPin ColumnColumn header menu
unpin_columnUnpin ColumnColumn header menu
sort_ascendingSort AscendingColumn header menu
sort_descendingSort DescendingColumn header menu
clear_sortClear SortColumn header menu
autosize_this_columnAutosize This ColumnColumn header menu
autosize_all_columnsAutosize All ColumnsColumn header menu
shortcut_cutCtrl+XContext menu hint
shortcut_copyCtrl+CContext menu hint
shortcut_pasteCtrl+VContext menu hint
search_placeholderFind…Search input
Note

Column headers are not part of the locale system. They come from ColumnDef.label and should be translated by your application code.

Custom locale

You can build a fully custom locale for any language:

let locale = Locale {
    cut: "カット".into(),
    copy: "コピー".into(),
    // ... fill all fields
    ..Locale::en() // fallback for any field you omit
};

Locale file format

Built-in locales are stored as flat TOML files in the rs-grid-web crate under src/locale/. Each file contains simple key = "value" pairs:

# French — Français
cut                = "Couper"
copy               = "Copier"
copy_with_headers  = "Copier avec en-têtes"
paste              = "Coller"
pin_column         = "Épingler la colonne"
sort_ascending     = "Tri croissant"
search_placeholder = "Rechercher…"

Files are embedded at compile time via include_str! — no runtime I/O.

Adding a new locale

  1. Copy an existing .toml file (e.g. en.tomlxx.toml)
  2. Translate all values
  3. In locale/mod.rs, add:
    • A pub fn xx() constructor calling parse_toml(include_str!("xx.toml"))
    • A "xx" branch in from_language_tag

Per-item overrides

Individual context menu labels can also be overridden per-item, independently of the locale, using ContextMenuItem::with_label():

let config = ContextMenuConfig {
    cell_items: Some(vec![
        ContextMenuItem::copy().with_label("📋 Copy"),
    ]),
    ..Default::default()
};
gc.set_context_menu(config);

These per-item overrides take precedence over the locale.