AppMatic Tech builds multi-language, multi-currency travel apps for international markets, with externalised strings, right-to-left layouts, server-side exchange rates, integer price storage, and a payment abstraction over Stripe, Razorpay, PayU, and Checkout.com, in Swift, Kotlin, and React. AppMatic Tech is based in Ahmedabad, India, with 330+ products shipped since 2017.
Why is internationalisation an architecture decision for a travel app?
Adding multi-language support to a travel app after the codebase is established is significantly more expensive than building with internationalisation from the start. The same principle applies to multi-currency support, right-to-left layout handling, and payment gateway abstraction. Each of these dimensions touches the data model, the UI layer, the API response format, and the payment flow.
AppMatic Tech has built travel and location-based applications for international markets, including TLV Places, a city discovery app for the Tel Aviv market built with full Hebrew right-to-left layout on iOS. This article documents the architecture decisions that allow a travel app to scale across languages, currencies, and payment methods without a layer-by-layer rewrite for each new market.
How should a travel app support multiple languages?
String Externalisation
The fundamental requirement for multi-language support is that no user-visible string is hardcoded in the application code. Every string, including labels, button text, error messages, empty state copy, and confirmation dialogs, must be externalised into a translation resource file keyed by identifier.
On iOS (SwiftUI), the LocalizedStringKey type and the Localizable.strings and Localizable.stringsdict files are the standard mechanism. Xcode's string catalogues (introduced in Xcode 15) provide a unified interface for managing translations across plural forms and device-specific variants.
On Android (Kotlin), string resources live in res/values/strings.xml, with language-specific overrides in res/values-[language-code]/strings.xml. The Android resource qualifier system handles locale selection automatically.
For React/Next.js web travel apps, i18next with react-i18next is the standard library. Translations are loaded as JSON namespaces, and the useTranslation hook provides string access in components. Dynamic string interpolation (e.g., "You have {count} trips booked") is handled via i18next's interpolation syntax.
Locale Detection and Language Switching
The app should detect the device locale on first launch and apply the closest supported language. If the device locale is Hebrew, the app should load Hebrew strings and apply RTL layout. Language switching within the app (allowing users to override the device locale) requires the app to reload translations and, in a native app, trigger a layout refresh that reapplies directionality.
On iOS, Locale.current.languageCode provides the device locale. On Android, Locale.getDefault().language provides the equivalent. React apps read navigator.language or use the Accept-Language header from the server for initial locale selection.
How do you build right-to-left (RTL) layouts for Arabic and Hebrew?
RTL languages, including Arabic, Hebrew, Farsi (Persian), and Urdu, require mirrored application layouts where the reading direction is reversed. A travel app's search form, booking flow, navigation tabs, and content cards must all reorient for RTL users.
AppMatic Tech built TLV Places with full Hebrew RTL on iOS, which required:
Layout mirroring: SwiftUI's layoutDirection environment value switches the entire view hierarchy to RTL when the locale is Hebrew. Leading and trailing anchors (rather than left and right) are used for all layout constraints, so SwiftUI automatically swaps them under RTL. Stacks reverse order. Navigation back buttons appear on the right.
Bidirectional text: Strings that mix RTL and LTR characters (Hebrew text with an English brand name, or Arabic text with a URL) require explicit bidirectional text handling. Both iOS and Android implement Unicode's bidirectional algorithm, but the display behaviour must be tested with real content, not placeholder text.
Map overlays: MapKit (used in TLV Places) supports RTL localisation for map labels and navigation overlays. Map controls (zoom buttons, compass) mirror to the RTL position. Custom map annotations and callout views require RTL-aware layout explicitly.
Iconography: Directional icons, including back arrows, forward chevrons, and swipe indicators, must be mirrored for RTL. iOS applies automatic mirroring for system SF Symbols that are marked as directional. Custom icons require RTL-specific asset variants.
For web travel apps built with React, CSS dir="rtl" on the root element and logical CSS properties (margin-inline-start, padding-inline-end) enable layout mirroring. Tailwind CSS supports RTL variants with the rtl: prefix on utility classes.
How should a travel app handle multiple currencies?
Exchange Rate Management
A travel app that displays prices in the user's local currency must source exchange rate data and update it on a defined schedule. Exchange rate APIs suitable for production use:
- Open Exchange Rates: REST API with daily and hourly update tiers and rates derived from mid-market data; hourly updates require a paid plan.
- Fixer.io: Similar data quality, REST API, European-market-focused rates.
- ECB (European Central Bank) API: Free, updated daily at 16:00 CET, covers the euro against about 30 other currencies. Suitable when the update frequency is acceptable.
Exchange rates should be stored server-side and refreshed on schedule. The mobile client should not call an exchange rate API directly; this exposes the API key and creates inconsistent rate data if different clients refresh at different times.
Rounding and Currency Formatting
Currency formatting rules vary by locale and must not be hardcoded:
- Decimal separator: Period (USD, GBP) vs comma (EUR in most European markets, BRL)
- Grouping separator: Comma (USD) vs period (EUR) vs space (CHF)
- Symbol position: Before amount (USD, GBP) vs after (SEK, NOK) vs ISO code display
- Decimal places: Two places standard for most currencies; zero for JPY, KRW, VND; three for KWD, BHD
iOS NumberFormatter with .currencyStyle and the correct locale handles all of these rules automatically. Android's NumberFormat.getCurrencyInstance(Locale) provides the equivalent. For web, the JavaScript Intl.NumberFormat API is the standard approach.
Storing and Transmitting Price Data
Prices should be stored in the database in the base currency (typically USD or EUR) and converted to the display currency at query time using the current stored exchange rate. This prevents inconsistency when rates change between a price being stored and displayed.
Do not store prices as floating-point numbers. Use integer storage in the currency's smallest unit (cents for USD and EUR, pence for GBP) to eliminate floating-point arithmetic errors in price calculations. Convert to decimal only for display.
Which payment gateways does an international travel app need?
A travel app serving international markets needs a payment gateway abstraction layer that allows different payment providers to be used in different geographies without rebuilding the payment flow.
Payment Provider Selection by Geography
- Stripe: Global coverage, strong developer tooling, excellent iOS and Android SDKs, supports 3D Secure 2 (required for EU SCA compliance). The default choice for US and European markets.
- Razorpay: Dominant in India. Supports UPI (Unified Payments Interface, India's real-time bank transfer system), credit/debit cards, net banking, and EMI options. Required for Indian consumer travel apps.
- PayU: Strong in Eastern Europe (Poland, Czech Republic, Romania) and Latin America (Brazil, Colombia, Mexico). Multi-currency support with local payment method coverage.
- Checkout.com: Strong in the Middle East (UAE, Saudi Arabia, Egypt) with local payment method support and Arab-market currency handling.
- HyperPay: Covers MENA markets with strong Saudi Arabia and UAE payment method support (MADA, Apple Pay in Arabic, stc pay).
Abstraction Layer Design
The payment abstraction layer isolates the payment provider selection from the rest of the booking flow:
Booking service → Payment interface → [Stripe | Razorpay | PayU | Checkout.com]
The payment interface defines: initiate payment, confirm payment, cancel payment, refund, and query status. Each provider implements the interface. The booking service selects the provider based on the user's billing country or a platform configuration rule, and calls the interface without knowing which provider is active.
This design allows new payment providers to be added for new markets without modifying the booking service.
How should a travel app store and display times across timezones?
Travel bookings span timezones. A flight departing Delhi at 23:50 and arriving in London at 06:15 the next day crosses multiple timezone boundaries. Storing and displaying these times correctly requires discipline across the full data stack.
Storage rule: All times are stored in UTC in the database. Never store times in local time without the timezone offset.
Display rule: Convert UTC times to the local timezone of the relevant event for display. Flight departure time is shown in the departure airport's local time. Arrival time is shown in the arrival airport's local time. The user's device time is irrelevant to flight schedule display.
IANA timezone database: Use IANA timezone identifiers (e.g., Asia/Kolkata, Europe/London) for timezone storage and conversion, not fixed UTC offsets. Fixed offsets break for countries that observe Daylight Saving Time.
iOS TimeZone(identifier:) and Calendar handle IANA-based conversion. Android's ZoneId and ZonedDateTime (from java.time) provide the equivalent. JavaScript's Intl.DateTimeFormat with timeZone option handles timezone-aware date display on the web.
How does AppMatic Tech build international travel apps?
AppMatic Tech builds travel applications and booking platforms with multi-language, multi-currency, and multi-market support from the first architecture review. For an international product example, see how AppMatic Tech engineered the Hungry Hub dining reservation app for the Thai market. For related travel engineering, read GDS API integration for travel tech and native vs cross-platform mobile development. Contact the team at contact@appmatictech.com to discuss the internationalisation requirements of a travel technology project.
Related travel guides from AppMatic Tech: travel booking engine development and AI trip planner app development.
Frequently Asked Questions
- Should a travel app store prices as floating-point numbers?
- No. AppMatic Tech stores prices as integers in the currency's smallest unit, such as cents or pence, to eliminate floating-point rounding errors, and keeps them in a single base currency such as USD or EUR. Prices are converted to the user's display currency at query time using the current server-side exchange rate, and formatted with the platform's locale-aware currency formatter.
- Which payment gateway should a travel app use in India or the Middle East?
- AppMatic Tech uses Razorpay in India for UPI, cards, net banking, and EMI, Checkout.com or HyperPay in the Middle East for local methods such as MADA and stc pay, and Stripe for US and European markets with 3D Secure 2 for EU Strong Customer Authentication. A payment abstraction layer lets the booking service switch provider by billing country without changing the booking flow.
- What is the minimum set of languages for an Asia-Pacific travel app?
- For a consumer travel app in Asia-Pacific, English plus the primary language of the target country, such as Mandarin, Japanese, Korean, Thai, or Bahasa Indonesia, is the minimum viable starting point. AppMatic Tech recommends planning Arabic from the start if the app will reach the Middle East, because right-to-left support is far cheaper to build in than to retrofit.
- How does Razorpay UPI work in a mobile app?
- Razorpay's iOS and Android SDKs handle the UPI flow natively: the SDK launches a UPI intent that opens the user's UPI app, such as PhonePe, Google Pay, Paytm, or a bank app, captures the payment, and returns a success or failure callback. The app receives a payment ID that AppMatic Tech verifies server-side before confirming the booking.
- Can currency conversion be done entirely on the client side?
- Client-side conversion with locally stored exchange rates produces inconsistent prices across sessions and devices. AppMatic Tech stores exchange rates server-side and serves converted prices through the API, so every client sees the same rate at the same moment and the exchange rate API key never ships inside the app.

