> For the complete documentation index, see [llms.txt](https://docs.rowsncolumns.app/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.rowsncolumns.app/configuration/features/localisation.md).

# Localisation

CanvasGrid renders what you pass it as a `fv` (formatted value) of the `CellData` object.

{% hint style="info" %}
RTL layout is not currently supported
{% endhint %}

## Setting the Locale

If you are using `useSpreadsheetState` for state management of Spreadsheet, you can pass in a `locale` prop to configure date and number formatting for different regions.

Locale is auto-detected from `Intl` JavaScript object if not provided.

```tsx
import { useSpreadsheetState } from "@rowsncolumns/spreadsheet-state"

const Spreadsheet = () => {
  const { } = useSpreadsheetState({
    locale: 'en-US'
  })
}

export const App = () => {
  <SpreadsheetProvider>
    <Spreadsheet />
  <SpreadsheetProvider>
}
```

## Switching Locale at Runtime

When users switch locales (e.g., from `de-DE` to `en-US`), all formatted values in the spreadsheet need to be regenerated to reflect the new locale's formatting rules.

The `onChangeLocale` function handles this automatically:

```tsx
import { useState } from "react";
import { useSpreadsheetState } from "@rowsncolumns/spreadsheet-state";

const Spreadsheet = () => {
  const [locale, setLocale] = useState("en-US");

  const { onChangeLocale } = useSpreadsheetState({
    locale,
    // ... other props
  });

  const handleLocaleChange = (newLocale: string) => {
    // Update the locale state
    setLocale(newLocale);
    // Regenerate all formatted values with the new locale
    onChangeLocale(newLocale);
  };

  return (
    <>
      <select
        value={locale}
        onChange={(e) => handleLocaleChange(e.target.value)}
      >
        <option value="en-US">English (US)</option>
        <option value="de-DE">German (Germany)</option>
        <option value="fr-FR">French (France)</option>
        <option value="es-ES">Spanish (Spain)</option>
        <option value="pt-BR">Portuguese (Brazil)</option>
      </select>
      {/* ... spreadsheet components */}
    </>
  );
};
```

### What Changes When Locale Switches

| Aspect                  | Behavior                                         |
| ----------------------- | ------------------------------------------------ |
| **Decimal separator**   | Changes (e.g., `.` in en-US, `,` in de-DE)       |
| **Thousands separator** | Changes (e.g., `,` in en-US, `.` in de-DE)       |
| **Currency symbol**     | Preserved (e.g., `$` stays `$`, `€` stays `€`)   |
| **Currency position**   | Preserved (encoded in the number format pattern) |
| **Numeric values**      | Preserved (only display formatting changes)      |
| **Date formats**        | Re-formatted according to locale conventions     |

### Example: Number Formatting Across Locales

The same numeric value `1234567.89` displays differently based on locale:

| Locale  | Formatted Value |
| ------- | --------------- |
| `en-US` | `1,234,567.89`  |
| `de-DE` | `1.234.567,89`  |
| `fr-FR` | `1 234 567,89`  |
| `es-ES` | `1.234.567,89`  |
| `pt-BR` | `1.234.567,89`  |

### Currency Formatting

When switching locales, currency symbols are preserved. Only the number formatting changes:

```
// USD currency cell with value 1234.56
en-US: $1,234.56
de-DE: $1.234,56  // Same symbol, different separators
fr-FR: $1 234,56  // Same symbol, French formatting
```

This matches the behavior of Google Sheets and Microsoft Excel.

### Supported Locales

The spreadsheet supports any valid BCP 47 locale identifier. Common examples include:

**European:**

* `de-DE` (German - Germany)
* `fr-FR` (French - France)
* `es-ES` (Spanish - Spain)
* `it-IT` (Italian - Italy)
* `nl-NL` (Dutch - Netherlands)
* `pl-PL` (Polish - Poland)
* `pt-PT` (Portuguese - Portugal)
* `sv-SE` (Swedish - Sweden)
* `da-DK` (Danish - Denmark)
* `fi-FI` (Finnish - Finland)
* `nb-NO` (Norwegian - Norway)

**Americas:**

* `en-US` (English - United States)
* `en-CA` (English - Canada)
* `fr-CA` (French - Canada)
* `es-MX` (Spanish - Mexico)
* `es-AR` (Spanish - Argentina)
* `pt-BR` (Portuguese - Brazil)

**Asia-Pacific:**

* `ja-JP` (Japanese - Japan)
* `zh-CN` (Chinese - China)
* `ko-KR` (Korean - Korea)
* `hi-IN` (Hindi - India)
* `th-TH` (Thai - Thailand)

### Undo/Redo Support

Locale changes are recorded in the undo history. Users can undo a locale change to restore the previous formatted values.

{% hint style="info" %}
Locale switching only affects the display format (`fv`). The underlying numeric values (`ev.nv`) are always preserved.
{% endhint %}

## Localising auto-generated names

Names that the spreadsheet generates on its own — new sheet titles ("Sheet1"), duplicated sheet titles ("Copy of Sheet1"), table titles ("Table 1"), pasted table titles ("Copy of Table 1") and generated table column names ("Column1") — can be localised with the `generatedNames` prop of `useSpreadsheetState`:

```tsx
import { useSpreadsheetState } from "@rowsncolumns/spreadsheet-state";

const Spreadsheet = () => {
  const {} = useSpreadsheetState({
    generatedNames: {
      sheet: (index) => `Лист${index}`,          // New sheets
      sheetCopy: (title) => `Копия ${title}`,    // Duplicated sheets
      table: (index) => `Таблица ${index}`,      // New tables
      tableCopy: (title) => `Копия ${title}`,    // Pasted tables
      tableColumn: (index) => `Столбец${index}`, // Generated table columns
    },
    // ... other props
  });
};
```

| Formatter     | Generated for                                               | Default           |
| ------------- | ----------------------------------------------------------- | ----------------- |
| `sheet`       | New sheets                                                  | `Sheet{index}`    |
| `sheetCopy`   | Duplicated sheets                                           | `Copy of {title}` |
| `table`       | New tables                                                  | `Table {index}`   |
| `tableCopy`   | Tables created by copy-paste                                | `Copy of {title}` |
| `tableColumn` | Table columns with no header value (create, insert, expand) | `Column{index}`   |

Every formatter is optional. Omitted formatters — or formatters returning `undefined` — fall back to the English defaults. Uniqueness is handled for you: if `Столбец1` already exists, the next generated column becomes `Столбец2`, and duplicated sheet titles get a numeric suffix on collision.

{% hint style="info" %}
Inline object/arrow-function literals are safe here. `useSpreadsheetState` stabilises the formatter identities internally, so passing a fresh `generatedNames` object on every render does not invalidate memoised callbacks.
{% endhint %}

## Localising the UI

All built-in UI text is localised via component overrides: copy the default component's source (or write your own), translate the strings, and pass it as a prop. `CanvasGrid` accepts overrides for its embedded UI:

| Prop                      | Default UI                                                    |
| ------------------------- | ------------------------------------------------------------- |
| `ContextMenu`             | Right-click context menu                                      |
| `CellEditor`              | Inline cell editor                                            |
| `FilterBox`               | Filter dropdown in table/filter headers                       |
| `SelectionTitleComponent` | Range title shown on named/table selections                   |
| `PasteMenu`               | "Paste formatting / Split text to columns" menu after a paste |
| `SuggestionAction`        | Agent suggestion approve/reject popover                       |
| `HiddenRowMarkers`        | "Show row" markers for hidden rows                            |
| `HiddenColumnMarkers`     | "Show column" markers for hidden columns                      |

Other components such as `SheetTabs`, `SheetSwitcher`, `Toolbar` and `FormulaBar` are standalone — replace them with your own translated copies.

```tsx
import {
  CanvasGrid,
  type PasteMenuProps,
  type HiddenRowMarkersProps,
} from "@rowsncolumns/spreadsheet";

const LocalisedPasteMenu = (props: PasteMenuProps) => {
  // Copy the default PasteMenu source and translate the strings,
  // e.g. "Split text to columns" -> "Text in Spalten aufteilen"
  return <MyTranslatedPasteMenu {...props} />;
};

const LocalisedHiddenRowMarkers = ({
  hiddenDimensions,
  expandedDimensions,
  onShowRow,
}: HiddenRowMarkersProps) => {
  // Render a marker per hidden row range with a translated label,
  // e.g. aria-label="Zeile einblenden"
  return <MyTranslatedRowMarkers />;
};

const MySpreadsheet = () => (
  <CanvasGrid
    sheetId={1}
    rowCount={100}
    columnCount={100}
    PasteMenu={LocalisedPasteMenu}
    SuggestionAction={LocalisedSuggestionAction}
    HiddenRowMarkers={LocalisedHiddenRowMarkers}
    HiddenColumnMarkers={LocalisedHiddenColumnMarkers}
  />
);
```
