Skip to content

Localization and currencies

Two distinct concerns:

  • Localization — the language of human-readable strings (message fields in errors, “Please enter your PIN” in the SDK widget).
  • Currency — the unit the customer is charged in. Sometimes different from the unit the merchant priced in.

Six built-in locales:

CodeLanguage
enEnglish
frFrench (default)
esSpanish
ruRussian
zhChinese (Mandarin)
lnLingala

Both SDKs default to French (fr). Override per checkout via acceptLanguage (config) or the language widget input.

Send Accept-Language: <code> on every request. The gateway translates the message field on error responses and any human-readable string in the response body.

error_code values are never localised — they are stable identifiers, not display text.

Terminal window
curl https://app.api.gtwy.pdirect.com/api/v1/payments/health \
-H "Accept-Language: en"
Terminal window
curl https://app.api.gtwy.pdirect.com/api/v1/payments/health \
-H "Accept-Language: fr"
// Flutter — process-wide default
PdirectPay.init(const PdirectPayConfig(
environment: PdirectPayEnvironment.production,
defaultLocale: 'en',
));
// Per-checkout override
PdirectPayCheckout(
configs: PdirectPayConfigs(
sessionToken: token,
acceptLanguage: 'fr', // overrides defaultLocale for this checkout
),
language: PdirectPayLanguage.french, // also overrides UI strings
// ...
);
// Angular — process-wide default
{
provide: PDIRECT_PAY_CONFIG,
useValue: { acceptLanguage: "en", isProduction: true },
}
// Per-checkout override
configs: PdirectPayConfig = {
token: "merchant-app-key",
acceptLanguage: "fr",
};

The Angular SDK exposes PdirectLocalizationService if you need to swap the entire UI language at runtime:

import { PdirectLocalizationService, PdirectPayLanguage } from "@mms/pdirect-pay";
constructor(private i18n: PdirectLocalizationService) {}
ngOnInit() {
this.i18n.setLanguage(PdirectPayLanguage.French);
// ...
this.i18n.translations$.subscribe(t => {
// t is the active translation table
});
}

PdirectLocalizationService.addTranslations(language, partial) lets you extend or override the built-in tables for a language. The Flutter SDK uses Flutter’s intl package and accepts custom delegates.

For full UX customisation (different copy than what the SDK ships), override the relevant Starlight content rather than adding translations to the SDK — the SDK’s surface is intentionally narrow.

Three currencies in v1:

CodeCurrency
usdUS Dollar
cdfCongolese Franc
xofWest African CFA Franc

Lowercase ISO 4217. The gateway rejects uppercase or alternative forms (USD, dollar) with error_code: "1102".

More currencies are on the roadmap; track the changelog.

Pricing currency vs transactional currency

Section titled “Pricing currency vs transactional currency”

The currency field on /payments/collect is the pricing currency — what your books say the customer owes. The transactional_currency field is the transactional currency — what the customer actually gets debited in.

Most of the time these are the same:

{ "amount": "12.50", "currency": "usd" }

But you can override:

{
"amount": "12.50",
"currency": "usd",
"transactional_currency": "cdf"
}

Effect: the gateway displays a CDF-equivalent amount to the customer (at the FX rate active at session-mint time), debits in CDF, and settles to your account in USD.

When to use this:

  • The customer’s wallet is denominated in cdf but you price in usd. The customer sees a familiar local-currency total while your accounting stays in dollars.
  • You’re running a cross-border B2C payout and the beneficiary receives in their local currency.

When not to use it:

  • For card payments where Mastercard handles FX server-side. Set currency only.

The rate locks at session-mint time. The customer sees the rate at session-mint; if FX moves between session-mint and /submit, you do not get re-quoted.

This means a stale session (a customer who walks away and returns 20 minutes later) may now have an out-of-date rate. The session TTL of 30 minutes (configurable up to 60) is your guard against this.

amount is a positive decimal string ("12.50", not 12.50 or 1250). Decimal places match the currency’s standard:

CurrencyDecimals
usd2 ("12.50")
cdf2
xof0 ("5000" — no decimals)

The gateway accepts "5000.00" for XOF too, but settlement is in whole units.

For display, use the customer’s locale’s formatting (1,000.50 vs 1.000,50). For storage and gateway calls, use the canonical unformatted string.