react-native-localization: string tables in the same file as the component
Class to localize the ReactNative interface
At a glance
- What is it?
- react-native-localization is a React Native library that keeps a language keyed string table next to the view that uses it, with a native module supplying the device interface language and a fallback to the first language when a translation is missing. Version 3 rebuilt it in TypeScript on top of react-localization, and the honest part of the design is that the strings end up duplicated across components unless you extract them yourself.
- Who is it for?
- react-native-localization fits a small React Native app whose author wanted internationalisation without adopting a translation workflow, and it fits a team that keeps its string tables close to the components. It is the wrong choice for a large multi-locale product, because the design's acknowledged weakness is duplicated strings across views, and the wrong choice for a shared React codebase, since the documentation itself points you to react-localization for that case.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 4 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The string table lives beside the component, and that is the trade
The author's stated reason for building the library is short. They needed a dead simple way to internationalise their first React Native app.
The design decision that follows from that is where the strings go. In this implementation the localized strings can be kept in the same file as the React view, in a similar way to how styles are implemented. The documentation is honest about the cost of that choice, saying it does not deny the approach could lead to some duplications in the translated strings, and suggesting the fix: create a CommonJS module to use as a common source of the strings, requiring it in the different views.
That is a complete answer to a problem that is usually answered by picking a translation file format and a loader. A mature project that ships a dozen locales and a translation team needs one of those. A first app with three languages and a dozen screens does not, and putting a table in the file next to the view means the person editing the screen can see the strings they are changing.
The reason given for not exposing the native iOS internationalisation API is also worth noting. The author considered exposing the NSLocalizedString macro to React Native, but opted for a solution that is more in the spirit of React, and hoped it would be better on performance. The result is that the strings are JavaScript data, and the native layer is only asked for one thing, which language the interface is currently set to.
The result is a library whose value is inversely proportional to the size of the product. Small app, no friction. Large product, you will outgrow it.
One native call, then a lookup with a fallback
The How it works section is short and describes the whole mechanism in two steps.
The JavaScript library uses a native module, called ReactLocalization, to get the current interface language. It then loads and displays the strings matching the current interface locale, or the default language, which is the first one, if a specific localization cannot be found.
So the data flow is: ask the OS which language the user has selected, look up that key in the string table, and if the key is not there, take the first entry. That fallback is the important part of the design. An app installed in French on a device set to German, where only English and French exist in the table, renders English rather than a key name or a crash.
The native module also has a custom version of getInterfaceLanguage to retrieve the interface language from the native OS. That is a deliberate difference from the upstream libraries it is built on, and it is what makes the interface language and the app's chosen content language the same thing by default.
It is also possible to force a language different from the interface one, so the user can pick a content language inside the app even when the device language is something else. That is a real requirement for apps that serve a market with several languages, and it is why the lookup is a plain function of a key rather than a read of a global set at startup.
The underlying engine is not in this repository. The library is built on top of react-localization 2.x and localized-strings 2.x, and the documentation directs you to react-localization if you want to share code with a React project, and to localized-strings for a generic JavaScript solution. All the basic code lives in those two projects, and this one adds the native side.
Installing it is two commands, and the Expo caveat is the real one
The installation section starts with the easiest path, running a couple of commands inside your React Native project folder:
yarn add react-native-localization
# or
npm i react-native-localization
# iOS only (React Native >= 0.60 uses autolinking)
cd ios && pod install && cd ..Android and iOS are linked automatically through autolinking for React Native 0.60 and later, and the documentation says not to forget to restart the app or bundler after installing. That last reminder is the classic native module gotcha, where the change is installed but the running bundle still has the old module registry.
Windows is the exception, because Windows does not support autolinking and requires a manual installation.
The caveat that will decide whether this library is usable for you is the Expo one, and it is called out in bold in the What it does section: Expo Go and managed Expo apps need a development build, or need to be ejected, before integrating native modules like this one.
That is worth understanding rather than skimming. Expo Go runs a fixed set of native modules, and a library that ships its own native code cannot be added to it. A managed Expo app has no native project directory to install into. So if your team is on Expo Go, this library is not an option until you move to a development build, and a development build is a real change to your pipeline, not a flag.
The manual installation instructions for iOS, Android and Windows are still in the README, and the Android one goes through settings.gradle, build.gradle and a MainApplication.java registration, while the Windows one is a Visual Studio project reference with a package added to a Packages list in MainPage.cs.
Version 3 is a rebuild, not an increment
There is a dedicated note about version 3.x, and it is worth reading because it describes a project that was restarted rather than evolved.
Version 3.x modernizes the library and is aligned with the current React Native ecosystem. The list is specific. It is written in TypeScript with bundled type declarations. It is built on top of react-localization 2.x and localized-strings 2.x. It requires React 19 or newer, which the documentation attributes to a react-localization 2.x requirement, and React Native 0.73 or newer. It ships CommonJS, ESM and TypeScript builds through a proper exports map. It works with the New Architecture through the legacy native module interop layer. And the native modules are resolved automatically via autolinking, so the legacy react-native link step is no longer needed.
That last point matters more than it looks. The react-native link command was the old manual linking mechanism, and requiring it put a step in every developer's setup. Removing it is the difference between a library that works after npm install and one that does not.
The New Architecture point deserves a note as well. React Native's New Architecture changed how native modules are written and registered, and a library written against the old bridge needs an interop path to keep working. The documentation says the library works with the New Architecture through the legacy native module interop layer, which is an honest description: the interop layer is the bridge for old-style modules, and it means the library is running in a compatibility mode rather than being a New Architecture native module.
The requirements list is the practical summary: React Native 0.73.0 or newer, React 19.0.0 or newer, iOS 13.0 or newer, Android minSdkVersion 24 or newer, and Node.js 20.19.0 or newer for building the library from source. Those floors are high for a library that has existed for years, and they are the price of the 3.x rebuild.
The package manifest shows how the build ships three module formats
The package manifest in the repository root is short and shows the publishing shape of the library.
The package is named react-native-localization, at version 3.0.0, with the source at src/index.ts. The main field points to lib/commonjs/index.js, the module field to lib/module/index.js, the types field to lib/typescript/index.d.ts, and the react-native field points back at src/index.ts so that the bundler consumes the TypeScript source directly rather than a compiled artefact.
The exports map is where the three formats are reconciled. The root export has a types entry, a react-native entry pointing at the source, an import condition that serves the ESM build with its own types, a require condition that serves the CommonJS build with its types, and a default that falls back to CommonJS. The package.json subpath is also exported, which is the conventional way to let tooling read the manifest without a bundler condition.
That is a properly built modern package. The old style of shipping a main field and hoping a bundler picks the right file does not work reliably across Metro, webpack, Node and Jest, and the exports map removes that guesswork.
The files list is explicit about what is published: src, lib, android, ios, windows, the podspec, the changelog, the licence and the readme. Publishing the native directories is what makes the autolinking work, since the CLI reads the podspec and the Android project from node_modules.
The build scripts are the other half. There is a build target that cleans and then compiles both formats, a typecheck that runs tsc with noEmit, a test script running vitest, and a prepare script that runs the build automatically on install from a git dependency. The prepublishOnly script chains clean, typecheck, test and build, so a published release cannot skip the type check or the tests.
The test tooling is vitest, with a vitest.config.mts at the root, and the repository also has a test directory and separate tsconfig files for the build, the module format and the general project.
Where a per-view string table stops scaling
Two boundaries decide whether this library is the right choice, and the documentation names the first one itself.
The first is the duplication problem. The author acknowledges that keeping strings next to the view can lead to duplications in the translated strings, and the proposed remedy is a common source module. But note what that remedy costs: once you extract the strings into a shared module, you have a translation file, and a translation file is a thing that needs a format, a loader and a process, which is what you were trying to avoid. The library does not remove that decision, it only delays it.
The second is the audience. The description is a class to localize the React Native interface, and the example is a breakfast ordering screen with boiled, soft-boiled and a choice prompt in English and Italian. That is a three-string, two-language case. A product with a dozen locales, plural forms, gender agreement and a translation team needs a different set of problems solved, and the interpolation support here is inherited from the upstream libraries rather than being the project's own contribution.
There is also the platform constraint that comes with any native module. A library whose only native responsibility is to report the device language has replaced a small problem with an infrastructure dependency: it cannot run in Expo Go, it needs a development build or ejection, and it needs the native toolchain in place for whoever builds the app.
And the version history is a genuine cost to weigh. The 3.x rebuild moved the dependency floor from whatever 1.x required to React 19 and React Native 0.73, and dropped the react-native link step while changing the underlying libraries. A project on an older React Native cannot take the current release, and the documentation points to a CHANGELOG for the full list of changes rather than describing a migration path.
Editorial conclusion
react-native-localization fits a small React Native app whose author wanted internationalisation without adopting a translation workflow, and it fits a team that keeps its string tables close to the components. It is the wrong choice for a large multi-locale product, because the design's acknowledged weakness is duplicated strings across views, and the wrong choice for a shared React codebase, since the documentation itself points you to react-localization for that case. Before adopting it, confirm the platform floor, which is React 19, React Native 0.73, iOS 13 and Android minSdkVersion 24, and check whether you are on Expo Go, because the documentation states that managed Expo apps need a development build or ejection before a native module like this one can be integrated.
Frequently asked questions
What does react-native-localization do?
It keeps a language keyed string table in the same file as the React Native view that uses it, looks up the string matching the current interface locale, and falls back to the default language, the first one, when a specific localization is not found. It is also possible to force a language different from the interface one.
How do I install react-native-localization?
Run yarn add react-native-localization or npm i react-native-localization in your project, then on iOS run cd ios and pod install and cd back. Android and iOS are linked automatically through autolinking for React Native 0.60 and later, and you should restart the app or bundler afterwards.
Can I use react-native-localization with Expo?
Not with Expo Go or a managed Expo app as they are. The documentation states that Expo Go and managed Expo apps need a development build, or need to be ejected, before integrating native modules like this one.
What are the requirements for react-native-localization 3.x?
React Native 0.73.0 or newer, React 19.0.0 or newer, iOS 13.0 or newer, Android minSdkVersion 24 or newer, and Node.js 20.19.0 or newer for building the library from source. Version 3 is written in TypeScript and ships CommonJS, ESM and TypeScript builds through an exports map.
Should I use react-native-localization or react-localization?
The project documentation says to use react-localization if you want to share code with a React project, and localized-strings for a generic JavaScript solution. ReactNativeLocalization is the React Native specific layer that adds the native interface language detection on top of those two.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/stefalda-reactnativelocalization)Was this useful?