Localization
Every user-facing string — empty states, aria labels, validation errors, tooltips — lives in a typed message catalog. Nothing is hardcoded: provide a catalog once for the whole application, or override single strings per component instance.
How it works
Each package exports a messages interface (for example OgeGridMessages, OgeInputsMessages). Catalogs are partial — you only supply the strings you change, the rest keep their English defaults. Patterns support {placeholder} interpolation for dynamic values.
The catalogs themselves are shared. Message names, defaults and placeholder syntax live in the framework-free packages, so a translation written once is correct in both render layers. Only the delivery differs: Angular takes a provideOge…Config() provider, React an <Oge…ConfigProvider> — the same object, handed over the way each framework expects.
Global configuration
import { provideOgeGridConfig } from '@oge-ui/grid';
import { provideOgeInputsConfig } from '@oge-ui/inputs';
import { provideOgeButtonsConfig } from '@oge-ui/buttons';
// app.config.ts — a Turkish application
providers: [
provideOgeGridConfig({
messages: {
noData: 'Kayıt bulunamadı',
search: 'Ara…',
rowsSuffix: 'satır',
summaryLabels: { sum: 'Toplam', avg: 'Ort', min: 'Min', max: 'Maks', count: 'Adet' },
},
}),
provideOgeInputsConfig({
messages: {
requiredError: 'Bu alan zorunludur',
clearButton: 'Temizle',
counterAria: '{max} karakterden {count} tanesi kullanıldı',
},
}),
provideOgeButtonsConfig({
messages: { loading: 'Yükleniyor', holdToConfirm: 'Onaylamak için basılı tutun' },
}),
]Switching language at runtime
Every provideOge…Config() also accepts a function. The config then follows the signals that function reads: flip your language signal and every OGE component re-renders its strings — and, with locale, its number and date formats — without reloading the page or fetching the catalog before bootstrap. A component-level [messages] input still wins over it. In React, pass a new config to the <Oge…ConfigProvider>; context already re-renders.
import { signal } from '@angular/core';
import { provideOgeGridConfig } from '@oge-ui/grid';
import { provideOgeInputsConfig } from '@oge-ui/inputs';
import { GRID_TR, INPUTS_TR } from './i18n/tr';
/** The app's own language state — a cookie, a store, a user setting… */
export const uiLanguage = signal<'en' | 'tr'>('en');
// Pass a function instead of an object: the config becomes live. Every OGE
// component re-renders its strings when a signal the function reads changes —
// no reload, no re-bootstrap. English is the built-in default, so '{}' is enough.
export const appConfig = {
providers: [
provideOgeGridConfig(() => ({
messages: uiLanguage() === 'tr' ? GRID_TR : {},
})),
provideOgeInputsConfig(() => ({
messages: uiLanguage() === 'tr' ? INPUTS_TR : {},
locale: uiLanguage() === 'tr' ? 'tr-TR' : 'en-US', // Intl formats follow too
})),
],
};
// anywhere: uiLanguage.set('tr');Per-component overrides
Components accept the same catalog through a [messages] input. Instance values win over the global provider, which wins over the built-in defaults:
<!-- the [messages] input overrides the global catalog for one instance -->
<oge-grid [data]="rows" [messages]="{ noData: 'No matching orders' }" />
<oge-text-box
label="Coupon code"
[messages]="{ requiredError: 'Enter a coupon to continue' }"
/>Validation messages
Input editors resolve validation errors from the catalog — the same strings serve standalone validation, reactive forms and Signal Forms, so translating them once covers all three binding modes:
// Message patterns interpolate the constraint that failed:
provideOgeInputsConfig({
messages: {
minError: 'Value must be at least {min}',
maxLengthError: 'Enter no more than {requiredLength} characters',
},
})
// Priority when an editor resolves its error text:
// 1. errorText input (always wins when set)
// 2. parse errors (e.g. invalid number)
// 3. form errors (Signal Forms / reactive), mapped through the catalogNumber & date locales
Formatting is separate from message catalogs: number editors format and parse through Intl.NumberFormat, honoring an explicit locale input or Angular's LOCALE_ID. Grouped input like 1.234,56 parses correctly in every locale:
<!-- Intl-powered: grouping, decimal separator and currency follow the locale -->
<oge-number-box
label="Price"
locale="de-DE"
[format]="{ style: 'currency', currency: 'EUR' }"
/>
<!-- without an explicit locale, editors use Angular's LOCALE_ID -->Behavior defaults
The config providers also centralize timing and interaction defaults, so product-wide tuning does not require touching templates:
// The same providers also carry non-text defaults:
provideOgeButtonsConfig({
clickGuardMs: 300, // default clickGuard window
holdToConfirmMs: 1000, // default hold duration
}),
provideOgeInputsConfig({
spinRepeatDelayMs: 300, // number-box spin: delay before repeating
spinRepeatIntervalMs: 60,
copiedResetMs: 1500, // "copied" indicator duration
})