Skip to content

Localization ​

The grid contains texts in English (en, default) and German (de):

ts
const options: GridOptions = { locale: "de" };

The demo switches the language of the grid texts (filter row and filter popups, column menu, context menu, group panel, pagination, status bar). The header texts and the number and date formats are part of the column definitions, so the demo translates them itself. The checkbox adds a few overrides with localeText.

Source
vue
<template>
  <div class="demo">
    <div class="demo-toolbar">
      <select v-model="locale" aria-label="Language">
        <option value="en">English</option>
        <option value="de">Deutsch</option>
      </select>
      <label><input type="checkbox" v-model="customTexts" /> Custom texts (localeText)</label>
    </div>
    <Datagrid :columns="columns" :rows="rows" :options="options" />
  </div>
</template>

<script setup lang="ts">
import { computed, ref } from "vue";
import { Datagrid, type ColumnConfig, type GridOptions } from "@datagrid/vue-ui";
import { createEmployees, type Employee } from "./data";

type Locale = "en" | "de";

const rows = createEmployees(200);

// header texts are part of the column definitions and translated by the application
const headers = {
  en: { name: "Name", department: "Department", city: "City", startDate: "Start date", salary: "Salary", active: "Active" },
  de: { name: "Name", department: "Abteilung", city: "Stadt", startDate: "Eintritt", salary: "Gehalt", active: "Aktiv" },
};

// overrides for single texts of the built-in translations
const overrides = {
  en: {
    hint_drag_columns: "Drag the Department or City header here to group the employees",
    page_info: "Employees {from}–{to} of {total}",
    empty: "No employees found",
  },
  de: {
    hint_drag_columns: "Abteilung oder Stadt hierher ziehen, um die Mitarbeiter zu gruppieren",
    page_info: "Mitarbeiter {from}–{to} von {total}",
    empty: "Keine Mitarbeiter gefunden",
  },
};

const locale = ref<Locale>("de");
const customTexts = ref(false);

const columns = computed<Array<ColumnConfig<Employee>>>(() => {
  const text = headers[locale.value];
  // number and date formats are defined by the value formatters of the columns
  const currency = new Intl.NumberFormat(locale.value, { style: "currency", currency: "EUR", maximumFractionDigits: 0 });
  const date = new Intl.DateTimeFormat(locale.value, { dateStyle: "medium" });
  return [
    { id: "name", text: text.name, flex: 1.5, valueGetter: ({ data }) => `${data.firstName} ${data.lastName}` },
    { field: "department", text: text.department, filterType: "set", groupable: true, flex: 1.3 },
    { field: "city", text: text.city, groupable: true },
    { field: "startDate", text: text.startDate, type: "date", valueFormatter: ({ value }) => date.format(new Date(value)) },
    { field: "salary", text: text.salary, type: "number", aggFunc: "sum", valueFormatter: ({ value }) => currency.format(value) },
    { field: "active", text: text.active, type: "boolean" },
  ];
});

const options = computed<GridOptions<Employee>>(() => ({
  locale: locale.value,
  localeText: customTexts.value ? overrides[locale.value] : undefined,
  selection: "Cell",
  singleSelect: false,
  columnMenu: true,
  contextMenu: true,
  statusBar: true,
  pagination: { enabled: true, pageSize: 50, pageSizes: [50, 100] },
  defaultColumn: { flex: 1, sortable: true, filterable: true, resizeable: true },
}));
</script>
tsx
import { useMemo, useState } from "react";
import { Datagrid, type ColumnConfig, type GridOptions } from "@datagrid/react-ui";
import { createEmployees, type Employee } from "../data";

type Locale = "en" | "de";

const rows = createEmployees(200);

// header texts are part of the column definitions and translated by the application
const headers = {
  en: { name: "Name", department: "Department", city: "City", startDate: "Start date", salary: "Salary", active: "Active" },
  de: { name: "Name", department: "Abteilung", city: "Stadt", startDate: "Eintritt", salary: "Gehalt", active: "Aktiv" },
};

// overrides for single texts of the built-in translations
const overrides = {
  en: {
    hint_drag_columns: "Drag the Department or City header here to group the employees",
    page_info: "Employees {from}–{to} of {total}",
    empty: "No employees found",
  },
  de: {
    hint_drag_columns: "Abteilung oder Stadt hierher ziehen, um die Mitarbeiter zu gruppieren",
    page_info: "Mitarbeiter {from}–{to} von {total}",
    empty: "Keine Mitarbeiter gefunden",
  },
};

export default function Localization() {
  const [locale, setLocale] = useState<Locale>("de");
  const [customTexts, setCustomTexts] = useState(false);

  const columns = useMemo<Array<ColumnConfig<Employee>>>(() => {
    const text = headers[locale];
    // number and date formats are defined by the value formatters of the columns
    const currency = new Intl.NumberFormat(locale, { style: "currency", currency: "EUR", maximumFractionDigits: 0 });
    const date = new Intl.DateTimeFormat(locale, { dateStyle: "medium" });
    return [
      { id: "name", text: text.name, flex: 1.5, valueGetter: ({ data }) => `${data.firstName} ${data.lastName}` },
      { field: "department", text: text.department, filterType: "set", groupable: true, flex: 1.3 },
      { field: "city", text: text.city, groupable: true },
      { field: "startDate", text: text.startDate, type: "date", valueFormatter: ({ value }) => date.format(new Date(value)) },
      { field: "salary", text: text.salary, type: "number", aggFunc: "sum", valueFormatter: ({ value }) => currency.format(value) },
      { field: "active", text: text.active, type: "boolean" },
    ];
  }, [locale]);

  const options = useMemo<GridOptions<Employee>>(
    () => ({
      locale,
      localeText: customTexts ? overrides[locale] : undefined,
      selection: "Cell",
      singleSelect: false,
      columnMenu: true,
      contextMenu: true,
      statusBar: true,
      pagination: { enabled: true, pageSize: 50, pageSizes: [50, 100] },
      defaultColumn: { flex: 1, sortable: true, filterable: true, resizeable: true },
    }),
    [locale, customTexts]
  );

  return (
    <div className="demo">
      <div className="demo-toolbar">
        <select value={locale} onChange={(e) => setLocale(e.target.value as Locale)} aria-label="Language">
          <option value="en">English</option>
          <option value="de">Deutsch</option>
        </select>
        <label>
          <input type="checkbox" checked={customTexts} onChange={(e) => setCustomTexts(e.target.checked)} /> Custom
          texts (localeText)
        </label>
      </div>
      <Datagrid columns={columns} rows={rows} options={options} />
    </div>
  );
}

Overriding texts ​

Single texts are overridden with localeText:

ts
const options: GridOptions = {
  locale: "de",
  localeText: {
    empty: "Keine Mitarbeiter gefunden",
    hint_drag_columns: "Spalte hierher ziehen",
  },
};

Adding languages ​

Register a new language once with registerLocale. Missing keys fall back to English.

ts
import { registerLocale } from "@datagrid/vue-ui";

registerLocale("fr", {
  empty: "Aucune ligne",
  loading: "Chargement…",
  filter_placeholder: "Filtrer…",
  // ...
});

Alternatively provide a translation function with localize: (key) => i18n.t(\grid.${key}`)`.

Keys ​

All keys can be found in the English translation (packages/core/src/i18n/en.ts). Some texts contain placeholders, e.g. page_info: "{from}–{to} of {total}".

GroupKeys
generalempty, loading, hint_drag_columns, total, true, false, select_all, select_row, expand, collapse, search
filterfilter, filter_placeholder, filter_clear, filter_apply, filter_select_all, filter_blank, filter_search, filter_and, filter_or, filter_to, filter_true, filter_false, filter_all
operatorsop_contains, op_notContains, op_equals, op_notEqual, op_startsWith, op_endsWith, op_blank, op_notBlank, op_lessThan, op_lessThanOrEqual, op_greaterThan, op_greaterThanOrEqual, op_inRange
column menumenu_sort_asc, menu_sort_desc, menu_sort_clear, menu_pin_left, menu_pin_right, menu_unpin, menu_autosize, menu_autosize_all, menu_group, menu_ungroup, menu_hide, menu_columns, menu_reset_columns
paginationpage_first, page_previous, page_next, page_last, page_size, page_info, page_of

Number and date formats are controlled by the formatters of the columns, see formatting.

Released under the ISC License.