Skip to content

Languages and locales

Two settings are easy to mix up:

locale uiLocale
What How report content is formatted: separators, currencies, month names, digits, calendars The language of the user interface: toolbar, panels, dialogs, messages
Where The template’s locale, or the viewer’s locale prop The viewer’s and designer’s uiLocale prop
Example fa-IR fa

They are independent. A German report can be shown in an English interface, and the other way round.

English is the default. Persian (Farsi) is built in and also switches the interface to right-to-left:

<ReportViewer uiLocale="fa" template={template} data={data} />
<ReportDesigner uiLocale="fa" template={template} sampleData={data} />
designer-persian.tsx
import { useEffect, useState } from 'react';
import { createFontMeasurer, type FontRegistration, type TextMeasurer } from '@ariana-reports/core';
import { ReportDesigner } from '@ariana-reports/react';
import { persianData, persianTemplate } from './report-data';
import { loadPersianFonts } from './fonts';
// uiLocale translates the toolbar, panels and dialogs and switches them to right-to-left.
export default function DesignerPersian() {
// The preview's PDF export needs the font files (`preview.pdf.fonts`); they also add Vazirmatn to the font list.
const [fonts, setFonts] = useState<{ fonts: FontRegistration[]; measurer: TextMeasurer }>();
useEffect(() => {
loadPersianFonts().then(async (fonts) => setFonts({ fonts, measurer: await createFontMeasurer(fonts) }));
}, []);
if (!fonts) return null;
return <ReportDesigner template={persianTemplate} sampleData={persianData} uiLocale="fa" preview={{ measurer: fonts.measurer, pdf: { fonts: fonts.fonts } }} />;
}

The designer, the viewer, the text editor dialog, the section captions on the design surface and the values in drop-downs (such as portrait, bold or Persian calendar) are all translated. Arrow icons mirror in right-to-left. The report pages and the design surface keep the template’s own layout, left to right.

A language is a plain object. Register it once, then use it by code. Missing labels fall back to English:

import { registerUiLocale, type UiLocale } from '@ariana-reports/core';
const de: UiLocale = {
code: 'de',
dir: 'ltr',
labels: {
print: 'Drucken',
nextPage: 'Nächste Seite',
previousPage: 'Vorherige Seite',
// … see DEFAULT_LABELS for every key
},
values: { bold: 'fett', portrait: 'Hochformat' }, // option values shown in drop-downs
};
registerUiLocale(de);
// <ReportViewer uiLocale="de" … />

You can also pass the object itself: uiLocale={de}. Region codes such as de-CH match the registered language. DEFAULT_LABELS lists every label with its English text; {name} placeholders are filled in, as in Page {page} of {count}.

To change a few labels in one language, use labels. Overrides win over the language:

<ReportViewer uiLocale="fa" labels={{ print: 'چاپ گزارش' }} … />

Set locale in the template, or on the viewer to override it:

{ "locale": "fa-IR", … }

The locale decides digits (۱۲۳ for fa-IR, ١٢٣ for ar-EG), separators, currency symbols and month names. Dates can also use another calendar, such as the Persian one. See Formatting values.

Every text component has a direction style: auto (the default), ltr or rtl. The designer shows it as Direction in the style properties. With auto the first strong letter decides, so a text that starts with a Persian word is right-to-left. Right-to-left text is right-aligned unless you set textAlign.

The viewer, the PDF and Excel follow the same direction. In PDFs, letters are joined (shaped) by the embedded font, and each line is reordered with the Unicode bidirectional algorithm, so numbers and Latin words inside Persian text keep their order. The PDF needs a font file with Persian letters, such as Vazirmatn; see Fonts.

viewer-persian.tsx
import { useEffect, useState } from 'react';
import { createFontMeasurer, type FontRegistration, type TextMeasurer } from '@ariana-reports/core';
import { ReportViewer } from '@ariana-reports/react';
import { persianData, persianTemplate } from './report-data';
import { loadPersianFonts } from './fonts';
export default function ViewerPersian() {
// The PDF needs the font files: register them in `pdf.fonts`, and measure text with them so line breaks match.
const [fonts, setFonts] = useState<{ fonts: FontRegistration[]; measurer: TextMeasurer }>();
useEffect(() => {
loadPersianFonts().then(async (fonts) => setFonts({ fonts, measurer: await createFontMeasurer(fonts) }));
}, []);
if (!fonts) return null;
return <ReportViewer template={persianTemplate} data={persianData} zoomMode="fitWidth" uiLocale="fa" measurer={fonts.measurer} pdf={{ fonts: fonts.fonts }} />;
}