Internationalization
Translating built-in labels, right-to-left (RTL) support, and locale-aware formatting across bpdm/ui form components — React (@bpdm/ui) and Angular (@bpdm/ng).
bpdm/ui form components adapt to internationalized apps three ways: their built-in screen-reader strings are translatable, their layout is right-to-left safe, and value formatting is locale-aware where it applies.
Translating labels
A few components render their own screen-reader text (button labels, live announcements).
These default to English but are fully overridable — pass your translated strings and nothing
else changes. In React it's a messages object (merged over the defaults); in Angular it's a
messages input, except the OTP per-cell label which is a function.
| Component | Prop | Default strings |
|---|---|---|
| Number Input | messages={{ increase, decrease }} | Increase · Decrease |
| Password Input | messages={{ show, hide }} (strength via labels) | Show password · Hide password |
| Secure Field | messages={{ reveal, hide, copy, copied }} | Reveal · Hide · Copy · Copied to clipboard |
| OTP Input | aria-label (group) + cellLabel={(i, n) => …} (per cell) | One-time code · Character N of M |
import { SecureField } from '@bpdm/ui/secure-field';
import { InputOtp } from '@bpdm/ui/input-otp';
export function FrenchSecrets() {
return (
<>
<SecureField
copyable
messages={{ reveal: 'Révéler', hide: 'Masquer', copy: 'Copier', copied: 'Copié' }}
/>
<InputOtp
length={6}
integerOnly
aria-label="Code de vérification"
cellLabel={(i, n) => `Chiffre ${i + 1} sur ${n}`}
/>
</>
);
}import { Component } from '@angular/core';
import { BpdmSecureField, BpdmInputOtp } from '@bpdm/ng';
@Component({
selector: 'app-french-secrets',
standalone: true,
imports: [BpdmSecureField, BpdmInputOtp],
template: `
<bpdm-secure-field copyable [messages]="secretMessages" />
<bpdm-input-otp
[length]="6"
integerOnly
aria-label="Code de vérification"
[cellLabel]="cellLabel" />
`,
})
export class FrenchSecretsComponent {
readonly secretMessages = { reveal: 'Révéler', hide: 'Masquer', copy: 'Copier', copied: 'Copié' };
readonly cellLabel = (i: number, n: number) => `Chiffre ${i + 1} sur ${n}`;
}Wire these to your i18n library (react-i18next, @angular/localize, etc.) by passing the
translated values through — the components hold no message catalogue of their own.
Right-to-left (RTL)
Every form component is built with CSS logical properties (padding-inline, text-start,
inset-inline, logical border-radius) rather than physical left/right. So they mirror
automatically inside a right-to-left context — set dir="rtl" on an ancestor and icons, affixes,
alignment, and the connected OTP rounding all flip correctly. No component prop is required.
import { Input } from '@bpdm/ui/input';
import { MoneyInput } from '@bpdm/ui/money-input';
export function ArabicForm() {
return (
<div dir="rtl">
<Input startIcon={<SearchIcon />} placeholder="بحث" />
<MoneyInput currency="AED" locale="ar-AE" defaultValue="2500" />
</div>
);
}<div dir="rtl">
<input bpdmInput placeholder="بحث" />
<bpdm-money-input currency="AED" locale="ar-AE" defaultValue="2500" />
</div>The OTP Input's ←/→ arrow keys follow the visual cell order too: inside dir="rtl",
ArrowLeft advances to the next cell and ArrowRight steps back, matching the mirrored layout.
Locale-aware formatting
The Money Input formats through the platform Intl.NumberFormat, so a
single stored amount renders with the right grouping, symbol, and decimal count per currency +
locale — en-IN groups as 1,00,000, de-DE as 100.000,00 €, JPY shows no decimals. The
value you read back stays a precise numeric string.
import { MoneyInput } from '@bpdm/ui/money-input';
export function Amounts() {
return (
<>
<MoneyInput currency="INR" locale="en-IN" defaultValue="100000" /> {/* ₹1,00,000.00 */}
<MoneyInput currency="EUR" locale="de-DE" defaultValue="100000" /> {/* 100.000,00 € */}
<MoneyInput currency="JPY" locale="ja-JP" defaultValue="100000" /> {/* ¥100,000 */}
</>
);
}<bpdm-money-input currency="INR" locale="en-IN" defaultValue="100000" />
<bpdm-money-input currency="EUR" locale="de-DE" defaultValue="100000" />
<bpdm-money-input currency="JPY" locale="ja-JP" defaultValue="100000" />