Home/Appearance & Platform/Localisation
Appearance & Platform

Localisation

Every word the grid puts on screen — overlays, pager labels, editor placeholders and the screen-reader announcements nobody sees — comes from one object. Pass a translation, get a translated grid, with no template forks and no partial-translation penalty.

Français — extending a bundled set

A thirteen-string bundled set with two of its strings replaced. Filter Prénom for a name nobody has: the overlay, the pager and the retry button are French, and everything the set does not carry is still English.

#
Prénom
Nom
Service
Statut
1
Nadia
Smith
Engineering
Inactive
2
Ben
Haddad
Marketing
Active
3
Yara
Novak
Support
Active
4
Karim
Okafor
Legal
Inactive
5
Elena
Smith
Operations
Active
6
Walid
Haddad
Engineering
Active
7
Alice
Novak
Marketing
Inactive
8
Petra
Okafor
Support
Active
Lignes par page:
1–8 sur 24

GRID_MESSAGES['fr'] carries thirteen strings — the overlays, the pager and the retry button. Spread it and change the two this screen words differently:

messages: {
  ...GRID_MESSAGES['fr'],
  empty:     'Aucun employé ne correspond',
  gridLabel: 'Répertoire du personnel',
}

Filter Prénom for a name nobody has and the overlay reads Aucun employé ne correspond. The pager under the grid says Lignes par page and sur, and neither string was written here — both came with the bundled set.

What a partial set does with the rest

The other sixty-nine keys are not in fr, so they fall back to English key by key — never to blank. Tab to the header checkbox in this grid and a screen reader still announces Select all rows. That is the honest state of a thirteen-string language file, and it is why a set with six strings in it is a working set rather than a broken one. The Arabic grid below is the other end of the same rule.

العربية — messages and direction together

A complete set, so even the strings only a screen reader hears are translated. dir: 'rtl' flips this grid alone — the two grids around it, and the page itself, stay left to right.

#
الاسم الأول
اسم العائلة
القسم
الحالة
1
Nadia
Smith
Engineering
Inactive
2
Ben
Haddad
Marketing
Active
3
Yara
Novak
Support
Active
4
Karim
Okafor
Legal
Inactive
5
Elena
Smith
Operations
Active
6
Walid
Haddad
Engineering
Active
7
Alice
Novak
Marketing
Inactive
8
Petra
Okafor
Support
Active
صفوف في الصفحة:
1–8 من 24

ar is one of the two complete sets, so nothing here falls back: the pager, the overlays and the strings only a screen reader hears are all Arabic. The same header checkbox that announced Select all rows in French announces تحديد كل الصفوف here.

Direction is set separately, and only for this grid

dir: 'rtl' is a second option, next to messages. It moves the layout — the columns run right to left, and so does the pager — while the two grids above and below stay left to right. The page around them never changes direction:

config = {
  dir:      'rtl',
  messages: { ...GRID_MESSAGES['ar'], gridLabel: 'دليل الموظفين' },
};

RTL_LOCALES ships beside the messages and holds ar, fa and ur, so a language switch can decide direction without keeping its own list.

English — what you still override

No translation needed, which leaves the two things a language file cannot supply: the grid's accessible name, and the column headers that were always yours.

#
First Name
Last Name
Department
Status
1
Nadia
Smith
Engineering
Inactive
2
Ben
Haddad
Marketing
Active
3
Yara
Novak
Support
Active
4
Karim
Okafor
Legal
Inactive
5
Elena
Smith
Operations
Active
6
Walid
Haddad
Engineering
Active
7
Alice
Novak
Marketing
Inactive
8
Petra
Okafor
Support
Active
Rows per page:
1–8 of 24

English needs no translation — every string is already its own default. That makes this the example that shows what is left to do once the language is handled, because the two things below are not translations and no language file can supply them.

  • gridLabel — the name a screen reader announces on entering the grid. Employee directory says what this grid holds; the default, Data Grid, says only that it is one.
  • The column names — First Name, Department and the rest are declared on the columns, so they are yours to translate, in all three grids on this page.
messages: { gridLabel: 'Employee directory' }

Twelve languages ship with the library

GRID_MESSAGES is exported alongside the grid and carries en, ar, fr, de, es, pt, fa, ur, tr, zh, ja and ru. Localising is an import, not a translation project:

import { GRID_MESSAGES, RTL_LOCALES, GridDirectionService } from '@gridcraft/angular';

const locale = inject(GridDirectionService);

locale.setMessages(GRID_MESSAGES[lang] ?? GRID_MESSAGES['en']);
locale.setDir(RTL_LOCALES.has(lang) ? 'rtl' : 'ltr');

en and ar are complete, at eighty-three strings each. The other ten carry thirteen — the overlays, the pager, the retry button — and anything they omit falls back to English key by key, so a partial set is a working set rather than a half-broken one. The first two examples above are those two cases side by side.

Overriding a shipped set

Spread it, then change what your product words differently. What you do not mention keeps the shipped translation:

const FR = {
  ...GRID_MESSAGES['fr'],
  empty:     'Aucun employé ne correspond',
  gridLabel: 'Répertoire du personnel',
};

gridLabel is the reason to do this per screen rather than per language: it is the grid's own accessible name, so it should say what this grid holds, not what every grid in the app holds. The French example sets exactly those two on top of the bundled set.

Column names are yours, not the grid's

messages covers the strings the grid produces. The column headers are strings you wrote, declared on the columns, so they go through whatever i18n your app already uses — $localize, a JSON bundle, or your translation service. Each grid above declares its own; a real language switch has to move both halves at once.

The strings nobody sees

A translated grid that still announces "sorted ascending" in English is only half translated, and it is the half that fails the readers who depend on it most. These keys never appear on screen, so they are the ones that get forgotten:

  • gridLabel — the grid's own accessible name, announced on entering it.
  • selectAllRows, selectRow — the checkbox labels.
  • filterFor, editorFor, rowDetailsToggle — the labels on the filter inputs, the inline editors and the row-detail toggle.
  • announceSortAsc, announceSortDesc, announceSortCleared, announceResults, announceLoaded — what is read out after an action.

See Accessibility for what each announcement is used for.

Placeholders

A few strings are templates rather than fixed text. Keep the placeholder in your translation and the grid fills it in. Drop one and the value it carried is simply gone from the sentence:

  • {col} — a column's name. filterFor, editorFor, announceSortAsc, announceSortDesc, announceEditDone, validationRequired.
  • {n} — a count. announceResults, announceLoaded, announceSelectedAll, quickFilterResults.
  • {page} and {pages} — the current page and the total, in announcePage.
  • {total} — a second count beside {n}, in announceLoadedMore.
  • {min} and {max} — the bound that was broken, in validationMin and validationMax.

They can sit anywhere in the string, which is what makes a language with a different word order translatable rather than merely re-worded. Every other message is plain text — pageOf included: the pager prints the two numbers around it, so a translation is the word alone.

Three places to set them

The same object is accepted at three levels, and they combine key by key — a grid that overrides one string keeps every other one from the level above.

  • App-wide, once — provideGridDefaults({ messages }) in your application config. Every grid inherits it, including grids you add later.
  • At runtime — GridDirectionService.setMessages(). Call it when the reader changes language and every grid on screen updates; nothing is re-created. patchMessages() merges a few keys instead of replacing the set.
  • Per grid — config.messages, which wins over both. Use it for the strings that belong to one screen, such as gridLabel. Each grid on this page uses it, which is why three languages sit on one screen at once.

Direction is a separate switch

Translating the strings does not move the layout, and moving the layout does not translate the strings — deliberately independent, because plenty of apps need one without the other. config.dir is per grid, so the Arabic example above reads right to left while the rest of this page, and the two grids around it, stay left to right. See RTL Support for what direction changes on its own.

Messages are plain strings, not a message format, so they compose with whatever you already use to produce them — pull them from $localize, a JSON bundle or your translation service and hand the resulting object over.

Localisation options

PropertyTypeDefaultDescription
GRID_MESSAGESRecord<string, Partial<GridMessages>>—Bundled translations: en, ar, fr, de, es, pt, fa, ur, tr, zh, ja, ru. Spread one to extend it; anything a set omits falls back to English key by key.
RTL_LOCALESSet<string>{ 'ar', 'fa', 'ur' }The bundled languages that read right to left — pair it with config.dir.
config.messagesPartial<GridMessages>English defaultsEvery string the grid renders. Any key you omit keeps its default, so a partial translation is valid.
messages.gridLabelstring'Data Grid'The grid's own accessible name — what a screen reader announces on entering it. Worth setting per screen.
messages.empty / error / retrystringEnglish defaultsThe overlay text and the retry button. See Loading & Empty States.
messages.rowsPerPage / pageOfstring'Rows per page' / 'of'The pager labels under a paged grid. pageOf is the word between the two numbers, not a template.
messages.firstPage / prevPage / nextPage / lastPagestringEnglish defaultsAccessible labels on the four page buttons.
messages.records / allLoadedstring'records' / 'All records loaded'The count line and end-of-list note under a grid that scrolls rather than pages.
messages.filterFor / editorForstring'Filter {col}' / 'Edit {col}'Labels on the filter inputs and inline editors. {col} becomes the column name.
messages.announceSortAsc / …Desc / …ClearedstringEnglish defaultsAnnounced after a sort changes. {col} becomes the column name.
messages.search / noResults / pickDate / clearDatestringEnglish defaultsStrings inside the select and date editors.
config.dir'ltr' | 'rtl''ltr'Layout direction — independent of the messages, and set per grid. See RTL Support.
GridDirectionService.setMessages()(m: Partial<GridMessages>) => void—Sets the app-wide messages at runtime; every grid on screen follows. A per-grid config.messages still wins.
GridDirectionService.patchMessages()(m: Partial<GridMessages>) => void—Merges a few keys into the current app-wide messages instead of replacing them.
provideGridDefaults({ messages })Partial<GridConfig>—The app-wide baseline, merged key by key with each grid's own messages.