One of the most common (and costly) mistakes in multilingual React Native apps is bundling all localization files directly into the JavaScript bundle.
If your app supports several languages (for example: English, Spanish, French, etc.) and youβre still bundling them into JS, youβre doing it the wrong way.
But donβt worry β 99% of us have done this.
πͺ€ The Problem
Hereβs what happens when all locale files are bundled in JS:
- π Increased app size
- π’ Slower app startup
- π§ Higher memory usage (even for unused languages)
This might be fine in development, but it's a performance killer in production.
β The Right Way (Android)
Letβs fix it using two native Android features:
- Per-app language preferences
- Alternative resources based on device locale
Step 1: Move Locale Files to Native Resources
Instead of bundling JSON locale files in JS, place them in Android's raw resource folders:
android/
βββ app/
βββ src/
βββ main/
βββ res/
βββ raw/ # default (e.g. English)
β βββ localizable.json
βββ raw-es/ # Spanish
β βββ localizable.json
βββ raw-fr/ # French
β βββ localizable.json
βββ raw-it/ # Italian
β βββ localizable.json
βββ raw-pt-rBR/ # Portuguese (Brazil)
β βββ localizable.json
Now, Android will include only the necessary languages based on the user's device settings.
Step 2: Enable Per-App Language Preferences
Let Android handle locale selection automatically.
2.1 Create locales_config.xml
<?xml version="1.0" encoding="utf-8"?>
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
<locale android:name="en"/>
<locale android:name="es"/>
<locale android:name="fr"/>
<locale android:name="it"/>
<locale android:name="pt-br"/>
</locale-config>
Save this file to:
android/app/src/main/res/xml/locales_config.xml
2.2 Register in AndroidManifest.xml
<application
android:name=".MainApplication"
android:label="@string/app_name"
+ android:localeConfig="@xml/locales_config"
2.3 Configure resConfigs
in build.gradle
In android/app/build.gradle
, declare the supported locales:
android {
defaultConfig {
...
resConfigs "en", "es", "fr", "it", "pt-rBR"
}
}
π Bonus: Read Locales from Native Side
Now that your locales live natively, itβs time to read them.
In production, use the native resource. In development, load the file directly for faster iteration:
import { Fbtee } from 'react-native-fbtee';
function getLocale() {
if (__DEV__) {
return require('../android/app/src/main/res/raw/localizable.json');
}
return JSON.parse(Fbtee.readLocalizationFile('localizable'));
}
π¦
react-native-fbtee
enables fast, synchronous file access from native resources.
π§© Putting It All Together
Here's what happens in practice:
- π² User installs your app.
- π₯ Only the locale matching their device is downloaded.
- π If they change the app language (via system settings), Android dynamically downloads the new locale in the background.
- π¦ Your app reads the updated locale JSON β no JS bundle changes needed.
Often, this triggers a push notification like:
Once the download completes, translations are updated β you can read updated values.
π Verify It: Check Your App Size
Tools like Ruler by Spotify can show the difference in download size per locale. Youβll be shocked at how much space you save (π see a demo video from MichaΕ PierzchaΕa)..
TL;DR
β Donβt do this... | β Do this instead |
---|---|
Bundle all locales in JS | Use native raw resources |
Load all languages in memory | Let Android handle locale |
Rebuild for every change | Load dynamically from native (dev. mode only) |
Top comments (1)
@retyui Nice article, what about iOS?