# react-native-localize: device locale data for React Native apps

> react-native-localize reads the user's locale, currency, calendar and time zone settings from the device instead of guessing from the JS runtime. It is a data source, not a translation framework, and the distinction matters when you pick it.

**zoontek/react-native-localize** — 🌍 A toolbox for your React Native app localization

- Repository: https://github.com/zoontek/react-native-localize
- Stars: 2,439 · Forks: 225
- Language: TypeScript
- License: MIT
- Published: 2026-09-28 · Updated: 2026-09-28 · Language: en
- Canonical page: https://hysenlabs.com/projects/zoontek-react-native-localize

## What react-native-localize actually returns

The package is a read-only accessor over platform locale APIs. Its exported functions each answer one question about the device: getLocales() returns the user's preferred locales in order, getCurrencies() returns preferred currency codes in order, getCountry() returns a country code, getTimeZone() returns a zone identifier, getCalendar() returns a calendar system, and getNumberFormatSettings() returns a decimal and grouping separator pair. Small predicates cover the rest: uses24HourClock(), usesMetricSystem(), getTemperatureUnit(), and on Android only, usesAutoDateAndTime().

The audience is a React Native developer who needs to branch on device settings rather than on a hardcoded default. Formatting a price with the wrong decimal separator, or rendering a date in the wrong calendar, is the class of bug this library exists to prevent. It is not a translation layer. Nothing in the README mentions message catalogues, plural rules or string lookup, so teams expecting a drop-in i18n runtime will be looking in the wrong place.

## How the data reaches JavaScript

The repository layout shows the split plainly: src/ holds the TypeScript surface, android/ and ios/ hold the native implementations, and RNLocalize.podspec wires the iOS side into CocoaPods. The published package exposes three entry points through package.json exports: the root module, ./expo for the config plugin, and ./mock plus ./mock/jest for test doubles.

That native boundary is the whole design. Calls cross into platform APIs and come back as plain JavaScript values, which is why getCountry() and getTimeZone() are documented as based on device settings rather than on position. A phone set to France but physically in Japan reports FR and Europe/Paris. If your feature needs where the user is, this library will give you a confidently wrong answer, and the README is explicit that this is intentional.

The dual build matters for bundlers. package.json declares separate commonjs and module outputs with matching type declarations, so both require and import resolve to typed code. The ./mock and ./mock/jest entries exist because native modules are not present in a Jest environment; without them, any test that imports the library would fail on a missing native binding.

## Installing react-native-localize and reading the device locale

Install from npm or Yarn, then run pod install for the iOS side. The README lists both package managers as equivalent.

```bash
npm install --save react-native-localize
# --- or ---
yarn add react-native-localize
```

After installation, the README says not to forget pod install, which links the native module into the iOS project. Skipping it leaves the JavaScript imports resolving but the native calls unavailable at runtime.

The first useful call is getLocales(). It returns an ordered array, and each entry carries languageCode, an optional scriptCode, countryCode, languageTag and an isRTL boolean.

```ts
import { getCurrencies, getLocales } from "react-native-localize";

console.log(getLocales());
console.log(getCurrencies());
```

The README's own example output shows three entries for a device preferring British English, then US English, then French, each with isRTL false. The order is the preference order, so the first element is the one to use for a default. getCurrencies() returns a plain string array such as ["EUR", "GBP", "USD"], again ordered.

Declaring supported locales is a separate step on each platform. On iOS the README instructs you to list them under CFBundleLocalizations in ios/YourApp/Info.plist:

```xml
<key>CFBundleLocalizations</key>
<array>
  <string>en</string>
  <string>fr</string>
</array>
```

On Android, set android:localeConfig on the application element in android/app/src/main/AndroidManifest.xml, then list the same locales in android/app/src/main/res/xml/locale_config.xml. If you ship with Expo, the config plugin takes a locales array in app.json or app.config.js, and the README shows that array accepting either a flat list or an object splitting android and ios.

## Where the abstraction leaks

getCountry() has a documented edge case: devices using Latin American regional settings return "UN" rather than "419", because 419 is not a standard country code. Code that validates the return value against a two-letter ISO list will pass UN through happily and then fail somewhere downstream. Any country-based routing, pricing or content rule needs to handle that value explicitly.

usesAutoDateAndTime() is Android only, and its return type is boolean or undefined, not boolean. On iOS you get undefined. A caller that treats the result as a truthy check will silently read undefined as false and conclude that automatic date and time is disabled when the platform simply does not answer the question. The signature is honest about this, but it is easy to miss.

The deeper limitation is that this library reports settings, it does not react to them. The related searches include a query about addEventListener, and the README's API listing is a set of plain getters with no subscription mechanism. If a user changes their language while your app is in the foreground, you have to re-read the values yourself at the points where it matters. Treating these functions as a live observable source will produce stale UI.

Finally, the library is the wrong tool if you need translations. It tells you the user prefers French. It does not give you the French string.

## react-native-localize compared with expo-localization

The related searches pair react-native-localize against expo-localization, and the difference is architectural rather than a matter of feature lists. expo-localization belongs to the Expo SDK and is consumed through Expo's module system. react-native-localize is a standalone native module with a CocoaPods spec and an Android package, usable in a bare React Native project without the Expo runtime.

That said, the repository ships app.plugin.js and an ./expo export, so Expo users are not excluded: the config plugin writes the supported locale declarations for you instead of leaving you to edit Info.plist and locale_config.xml by hand. The trade-off is that the plugin adds a build-time configuration step, and dynamic configs need the require form in app.config.js rather than an import, as the README notes.

If your project is already fully inside the Expo managed workflow and you have no bare-native requirements, expo-localization avoids adding a second localization dependency. If you are on bare React Native, or you want the same module across iOS, Android, macOS and web with one API, react-native-localize is the more direct fit. Note the platform badge list: web is supported, which the native-only alternative does not cover in the same way.

## Maintenance, licence and upgrade cost

The last push to the default branch was on 2026-09-15, and version 3.7.2 was released the same day, following 3.7.1 on 2026-09-14 and 3.7.0 on 2026-02-22. The repository is not archived. The README states the support policy directly: the library follows the React Native releases support policy and supports the latest version plus the two previous minor series.

That policy is the real upgrade cost. It is not a library that stays compatible with old React Native versions indefinitely. If your app is pinned to a React Native release outside that window, you are outside the stated support boundary, and the README offers no backport commitment. Budget for React Native upgrades as a prerequisite for staying current here.

The licence is MIT, declared in package.json and in the LICENSE file at the repository root. MIT permits commercial and closed-source use with attribution and no copyleft obligation. This is a factual description of the licence text, not legal advice; your own counsel should confirm how it interacts with your distribution model, particularly if you ship native binaries.

The third piece of upgrade cost is the native configuration. Every platform you support needs its locale list declared in its own file, and the Expo plugin only covers the Expo path. Adding a locale means editing iOS and Android configuration and shipping a new binary, not just adding a JSON file.

## Conclusion

Adopt react-native-localize when you need the device's actual locale list, currency codes, calendar or time zone and you are already running a React Native or Expo build. Do not adopt it expecting translated strings: the README describes a data toolbox, and the package.json ships no translation catalogues. Before committing, verify that your supported locale list is declared in CFBundleLocalizations on iOS and in android/app/src/main/res/xml/locale_config.xml on Android, because the library reads what the platform reports, and an empty declaration means an empty answer.

## FAQ

### How do I install react-native-localize?

Install it with npm install --save react-native-localize or yarn add react-native-localize, then run pod install for the iOS side. After that, declare your supported locales in Info.plist on iOS and in android/app/src/main/res/xml/locale_config.xml on Android.

### What does react-native-localize getLocales() return?

It returns the user's preferred locales in order, and each entry contains languageCode, an optional scriptCode, countryCode, languageTag and an isRTL boolean. The README's example shows a three-entry array for a device preferring en-GB, then en-US, then fr-FR.

### How do I use react-native-localize with Expo?

Specify the supported locales through the config plugin in app.json or app.config.js. The README shows the locales array accepting either a flat list such as ["en", "fr"] or an object splitting android and ios, and notes that app.config.js must use require rather than import.

### Does react-native-localize translate strings for me?

No. The README describes it as a toolbox for localization and the API is a set of getters for locale, currency, calendar, time zone and number format settings. It reports device preferences; it does not ship message catalogues or resolve translated text.

### How do I mock react-native-localize in Jest?

The package.json exposes ./mock and ./mock/jest entry points with matching type declarations, which exist so tests can substitute the native module that is not available in a Jest environment. The README does not document the mock API's individual functions.

## Sources

- [Issues](https://github.com/zoontek/react-native-localize/issues)
- [License: MIT](https://github.com/zoontek/react-native-localize/blob/master/LICENSE)
- [README](https://github.com/zoontek/react-native-localize/blob/master/README.md)
- [Releases](https://github.com/zoontek/react-native-localize/releases)
- [zoontek/react-native-localize on GitHub](https://github.com/zoontek/react-native-localize)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/zoontek-react-native-localize
