MutoPay Now Speaks Six Languages
A buyer in Istanbul opens a checkout link from a shop in Madrid. The page loads in Turkish. They pay, the merchant gets the webhook, and on the merchant’s dashboard back in Madrid the payment shows up in Spanish. Nobody had to pick a language.
That is what shipped this month. The customer-facing payment page, the Pay Me link page, and the full merchant dashboard are now translated into six languages: English, Arabic, Spanish, Turkish, Armenian, and Russian. The marketing site (this blog included) is in the same six.
What is translated
Customer side:
- The hosted payment page at
/pay/:id - The Pay Me link page (
/pay/me/:slug) - All wallet flow copy: connect, sign, confirm, retry, error states
- Quote and route comparison strings
- Manual-send instructions, QR code captions, and dust-amount callouts
- KYC redirect notice and the rare “needs manual check” status
Merchant side:
- The dashboard sidebar and every page under
/dashboard/* - Settings: API keys, webhook secret, channels, master key, settlement override
- Onboarding wizard
- Payment list, filters, detail view, status badges
- Pay Me link configuration
- All form validation and error messages
The admin panel (/admin/*) stays in English for now. It is internal and not customer-facing.
How language is picked
On first visit the browser language is read from navigator.language. If it matches one of the six locales, the UI loads in that language. The choice is then saved to localStorage so the next visit skips the detection step.
A switcher sits in the footer of the payment page, the Pay Me page, and the dashboard sidebar. Picking a language overrides the auto-detected value and persists the same way.
For logged-in merchants the dashboard preference is stored against the merchant record, so switching languages on a laptop carries over to a phone.
Right-to-left for Arabic
Arabic flips the entire layout. Text aligns right, the sidebar moves to the right edge, icons and chevrons mirror, and amount fields keep numerals in their natural left-to-right reading direction. The Astro content site (blog, changelog, landing) renders the same way under /ar/*.
If you are reading this post in Arabic, the URL is /ar/blog/multilingual-checkout. The same slug exists in every locale.
A merchant in one language, a customer in another
The payment page and the dashboard are independent. A Spanish-speaking merchant can run their dashboard in Spanish while every customer sees the checkout in their own browser language. There is no per-merchant language lock on the customer side.
This matters for cross-border commerce. A Yerevan-based agency selling to clients in Turkey, Russia, and Spain does not need to maintain three checkout pages. One link, three languages, automatically.
Why these six
The selection is pragmatic, not exhaustive. We picked the languages where we already had real user demand or clear market opportunity:
- English is the default and the API documentation language
- Arabic covers the Gulf and North Africa, where stablecoin adoption is high
- Spanish is the second-most-requested checkout language we saw in early months
- Turkish matches the lira-volatility merchant base that pushed us toward USDT/TRC-20 support
- Armenian is home: MutoPay is built in Yerevan
- Russian opens the post-Soviet diaspora and the Armenian/Russian-speaking overlap in our user base
If your market is not on this list and you would use MutoPay if it were, reply to any of our posts or email the team. Adding a seventh language is a translation file plus a switcher entry, not a rewrite.
What changed under the hood
For the curious: the React app uses react-i18next with one JSON catalog per locale. The Astro content site uses Astro’s built-in i18n config with a separate ui.ts map and per-locale content collections (blog/en, blog/ar, blog/es, and so on). Matching slugs across locales generate hreflang alternates in the sitemap, so search engines know which pages are translations of each other.
Translation memory lives in content/src/i18n/ui.ts and per-page React catalogs. Adding a string anywhere requires the same key in all six files, which is enforced by a build-time check.
Try it
Open any payment link. Click the language switcher in the footer. Or change your browser’s preferred language and reload.
If you spot a translation that reads wrong (a string that is too literal, a word that does not fit the local register, an English fragment that slipped through) tell us. The catalogs are small enough that fixes ship the same week.