Mobile App Localisation and Internationalisation

NOVASOLUTIONS.TECHNOLOGY is engaged in the development, support and maintenance of iOS, Android, PWA mobile applications. We have extensive experience and expertise in publishing mobile applications in popular markets like Google Play, App Store, Amazon, AppGallery and others.
Development and support of all types of mobile applications:
Information and entertainment mobile applications
News apps, games, reference guides, online catalogs, weather apps, fitness and health apps, travel apps, educational apps, social networks and messengers, quizzes, blogs and podcasts, forums, aggregators
E-commerce mobile applications
Online stores, B2B apps, marketplaces, online exchanges, cashback services, exchanges, dropshipping platforms, loyalty programs, food and goods delivery, payment systems.
Business process management mobile applications
CRM systems, ERP systems, project management, sales team tools, financial management, production management, logistics and delivery management, HR management, data monitoring systems
Electronic services mobile applications
Classified ads platforms, online schools, online cinemas, electronic service platforms, cashback platforms, video hosting, thematic portals, online booking and scheduling platforms, online trading platforms

These are just some of the types of mobile applications we work with, and each of them may have its own specific features and functionality, tailored to the specific needs and goals of the client.

Showing 12 of 12 servicesAll 1735 services
Simple
from 1 business day to 3 business days
Simple
from 1 business day to 3 business days
Simple
from 1 business day to 3 business days
Medium
from 1 business day to 3 business days
Medium
from 1 business day to 3 business days
Simple
from 1 business day to 3 business days
Medium
from 1 business day to 3 business days
Simple
from 4 hours to 2 business days
Medium
from 1 week to 3 months
FAQ
Our competencies:
Development stages
Latest works
  • image_mobile-applications_feedme_467_0.webp
    Development of a mobile application for FEEDME
    756
  • image_mobile-applications_xoomer_471_0.webp
    Development of a mobile application for XOOMER
    624
  • image_mobile-applications_rhl_428_0.webp
    Development of a mobile application for RHL
    1054
  • image_mobile-applications_zippy_411_0.webp
    Development of a mobile application for ZIPPY
    947
  • image_mobile-applications_affhome_429_0.webp
    Development of a mobile application for Affhome
    862
  • image_mobile-applications_flavors_409_0.webp
    Development of a mobile application for the FLAVORS company
    445

Mobile App Localization: i18n, RTL, Dynamic Language Switching

Localization is not just translating strings. The date "04/05/2024" in the US means April 5, in Europe—May 4. The sum "1,000.50" in most countries is one thousand and a half, in Germany—one and fifty cents. The number of words for "1 file," "3 files," "5 files" in Russian is three different forms; Arabic has six plural forms. If app architecture doesn't account for this from the start, localization becomes a series of patches.

Basic Infrastructure: Strings, Formats, Pluralization

iOS: Localizable.strings and String Catalogs

Historically, iOS strings were stored in Localizable.strings—a simple key=value format. With Xcode 15, String Catalogs (.xcstrings) appeared—a JSON-based format that stores all locales in one file, displays translation status (translated/outdated/missing) and is integrated with Xcode UI.

String(localized: "welcome_title") in Swift 5.7+ instead of NSLocalizedString("welcome_title", comment: ""). Shorter, more type-safe. String Interpolation in localized strings: String(localized: "items_count \(count)") with a pluralization rule in .xcstrings—the system automatically selects the right form for the language.

Pluralization via .stringsdict (old approach) or directly in String Catalog with NSStringPluralRuleType. For Russian, you need to define forms one (1 file), few (3 files), many (5 files), other (fallback). Skip few for Russian—you get "5 files" where it should be "3 files."

Android: XML Resources and String Formats

res/values/strings.xml for the base locale (en), res/values-ru/strings.xml for Russian. Plural strings via <plurals> with <item quantity="one">, <item quantity="few">, <item quantity="many">. resources.getQuantityString(R.plurals.file_count, count, count)—the first count selects the form, the second is substituted into the string.

In Compose: stringResource(R.string.key) and pluralStringResource(R.plurals.file_count, count, count). Type-safe alternative—Lyricist library, which generates typed strings from annotations.

Android App Bundle with android:splitByLocale="true" in bundle.gradle—resources are delivered only for device languages. APK shrinks, needed locale resources are loaded via Play Asset Delivery. Important: on Android 8+ Configuration.locales is a list, not a single language.

Flutter: intl and Abstraction Layers

Flutter intl package—standard. AppLocalizations.of(context).welcomeTitle is generated from ARB files (app_en.arb, app_ru.arb). flutter gen-l10n generates typed code. Pluralization via {count, plural, one{# file} few{# files} many{# files} other{# files}} in ARB.

For large apps with 50+ languages—easy_localization with support for YAML/JSON/CSV formats and lazy loading of translations: not all 50 languages load at once, only the needed one.

RTL: Right-to-Left Writing

Arabic, Hebrew, Persian, Urdu—RTL (Right-to-Left) languages. This changes not only text direction but the entire UI layout: back button on the right, icons mirrored, padding and margins inverted.

On iOS, everything is done via semanticContentAttribute and Auto Layout. Layout constraints with leading/trailing (not left/right) automatically invert on RTL. UIView.semanticContentAttribute = .forceRightToLeft for a specific component. System components (UINavigationController, UITableView, UIStackView) switch automatically on RTL locale. Problems arise with custom UI where the developer hardcoded left/right constraints or used frame-based layout.

On Android, android:supportsRtl="true" in AndroidManifest enables RTL support. start/end instead of left/right in XML attributes: paddingStart, layout_marginEnd, textAlignment="viewStart". LayoutInflater with android:layoutDirection="rtl" for preview. Icons with direction (arrows, chevrons) must be mirrored—android:autoMirrored="true" in drawable for automatic inversion on RTL.

On Flutter, Directionality widget with TextDirection.rtl manages direction for the subtree. Padding(EdgeInsetsDirectional.fromSTEB(...)) instead of EdgeInsets.only(left:...). Row automatically accounts for TextDirection from Directionality. Most Material widgets are RTL-ready, but custom CustomPainter—no: you need to get TextDirection from context and account for it manually.

RTL testing: on iOS Settings → General → Language & Region → Region: Saudi Arabia switches to RTL mode without changing system language. On Android adb shell setprop debug.force.rtl 1 forces RTL for debugging.

Dynamic Language Switching

Switching language without restarting the app is a non-trivial task, especially if the system is built on system locale.

iOS doesn't natively support app language change without restart. The cleanest approach—store the selected language in UserDefaults, on startup create a Bundle with the needed localization, use a custom NSLocalizedString through this Bundle. Bundle.setLanguage("ru") via swizzling Bundle.localizedString(forKey:value:table:)—works, but this is runtime swizzling, which is not ideal. Alternative: your own string system on top of NSBundle, which rereads files on language change. On switch—recreate the root ViewController.

Android API 33: LocaleManager.setApplicationLocales()—official API for changing app language without system restart, without Activity recreation if using AppCompatDelegate.setApplicationLocales(). Before API 33—Configuration.setLocale() + recreate() for Activity. On language change, notify all open Activities via broadcast or ViewModel.

Flutter—simplest of the three. LocalizationsDelegate reloads when locale changes in MaterialApp. Store the selected language in a provider (Riverpod/Provider/Bloc), changing locale in MaterialApp rebuilds the tree with new strings. Practically no boilerplate when using easy_localization.

Formatting Dates, Numbers, Currencies

DateFormatter (iOS) and DateFormat (Android, intl)—always with an explicit locale, never without it. DateFormatter().dateStyle = .medium with locale = Locale(identifier: "ru_RU") gives "May 4, 2024" (in Russian format), with Locale(identifier: "en_US")—"May 4, 2024".

NumberFormatter / NumberFormat.currency() for currencies. Currency symbol, thousand and decimal separators—all locale-specific. Hardcoding "₽" or "." as a separator is an error. Locale(identifier: "ru_RU") + NumberFormatter.numberStyle = .currency with currencyCode = "RUB" gives correct formatting automatically.

Relative time ("2 hours ago," "yesterday"): RelativeDateTimeFormatter (iOS 13+) and RelativeTimeFormatter via intl package on Flutter/Android—don't reinvent the wheel with manual formatting.

Common Localization Mistakes

String concatenation instead of formatting: "Hello, " + name + "!" works for SVO-languages, but in Japanese, the name comes before the greeting. String(format: "greeting %@", name) with greeting = "%@ さん、こんにちは" in the Japanese file—correct.

Fixed UI size for text. German is on average 30% longer than English. AutoLayout with proper constraints, adjustsFontSizeToFitWidth where allowed, dynamic row height changes via UITableView.automaticDimension.

Images with embedded text—require localized versions or replacement with text overlay.

Timeframe

Adding one new language to an already localized app (strings only, no RTL)—2–3 days of technical work + translation time. Initial localization infrastructure setup from scratch, including RTL support and dynamic language switching—2–4 weeks.