Source: https://wealthfolio.app/docs/addons/localization/

# Addon Localization

Format values and translate addon interfaces using the user's Wealthfolio locale.

* * *

Last updated September 10, 2026

# Addon Localization

Wealthfolio addons run inside a sandboxed iframe that follows the host application’s language and regional formatting settings. Formatting controls numbers, currencies, and dates; translation controls the strings owned by your addon. Both update when the user changes their settings.

The sandbox localization runtime ships with Wealthfolio 3.8. Addons using these APIs must set both `sdkVersion` and `minWealthfolioVersion` to `3.8.0` or newer.

## Format numbers, currencies, and dates

The UI language and formatting region are separate settings. A user may read Wealthfolio in French while formatting amounts as `en-US`. Do not hardcode locales or date patterns. Use the formatting hooks provided by `@wealthfolio/ui`:

```tsx
import {
  useAmountFormatting,
  useDateFormatting,
  useLocalizationSettings,
  useNumberFormatting,
} from '@wealthfolio/ui';

function HoldingRow({ value, currency, asOf }: Props) {
  const { formatAmount } = useAmountFormatting();
  const { formatDate } = useDateFormatting();
  const { formatPercent } = useNumberFormatting();

  return (
    <div>
      {formatAmount(value, currency)} — {formatDate(asOf)} — {formatPercent(0.042)}
    </div>
  );
}
```

Available hooks include:

-   `useAmountFormatting()` — `formatAmount`, `formatPrice`, `formatCompactAmount`, `formatRoundedAmount`, `formatCurrencySymbol`, and `currencyFractionDigits`.
-   `useNumberFormatting()` — `formatPercent`, `formatQuantity`, `formatDecimal`, locale-aware `parseNumber`, and decimal/group separators.
-   `useDateFormatting()` — `formatDate`, `formatDateTime`, `formatTime`, date-range helpers, and locale-aware `parseDate`.
-   `useLocalizationSettings()` — the raw `{ locale, uiLocale, timezone }` settings.

## Translate addon-owned strings

Register translations once in `enable()` before the first render, then use the translation hook in React components:

```tsx
import {
  registerTranslations,
  useAddonTranslation,
  type AddonContext,
} from '@wealthfolio/addon-sdk';

export default function enable(ctx: AddonContext) {
  registerTranslations({
    en: {
      title: 'Dividend Forecast',
      greeting: 'Hello {{name}}',
      holdings_one: '{{count}} holding',
      holdings_other: '{{count}} holdings',
    },
    fr: {
      title: 'Prévision de dividendes',
      greeting: 'Bonjour {{name}}',
    },
  });

  // Register routes and sidebar items.
}

function Title() {
  const { t, language } = useAddonTranslation();
  return <h1 lang={language}>{t('title')}</h1>;
}
```

### Behavior and fallback rules

-   Translation resources are private to the current addon. They cannot read or overwrite the host’s strings, and other addons cannot see them.
-   The language always follows Wealthfolio. Addons cannot change it.
-   Missing strings fall back to the addon’s `en` bundle and then to the translation key. Always ship a complete English bundle.
-   Interpolation uses `{{name}}`; plurals use `_one` and `_other` suffixes with `t('holdings', { count })`.
-   Components re-render on language changes and late `registerTranslations()` calls.
-   Namespace and language overrides passed to `t()` are ignored, and `$t()` nesting inside resource values is disabled.

### Supported language keys

The host currently resolves `en`, `fr`, `de`, `es`, `pt`, `zh`, `zh-Hant`, `ja`, `ko`, and `it`. Regional aliases normalize to their supported language: for example, `fr-CA` becomes `fr` and Traditional Chinese aliases such as `zh-TW`, `zh-HK`, and `zh-MO` become `zh-Hant`.

Register `zh-Hant` separately from `zh`. A missing Traditional Chinese string falls back to English, not Simplified Chinese.

Valid language bundles outside the host’s supported set may be registered, but they are never selected. Invalid language keys are ignored with a warning.

## Using another localization library

The host does not provide `react-i18next` or `i18next` as external dependencies. If your addon needs ICU messages, its own language switcher, or another language, bundle your own localization library. The addon sandbox blocks direct network access, so bundle translation resources instead of loading them from a remote backend.

* * *
