A React Native & Lynx i18n solution that keeps your translations organized

от автора

If you’re building a multilingual React Native (or web) app, you’ve probably tried react-i18next, i18n-js, LinguiJS, or similar libraries.

But in every project, the same issues come up:

❌ Unused key-value pairs are never removed
❌ Content gets duplicated
❌ Ensuring format consistency across languages is painful
❌ i18next doesn’t generate TypeScript types by default – so t(«my.key») won’t throw even if it’s been deleted
❌ Localization platforms like Lokalise or Locize get expensive fast

Frustrated by these challenges, I waited for a better solution… then decided to build one myself: Intlayer.

✨ Key points

✅ Works with React Native and Lynx
✅ Easy integration
Localized content close to your components
Autogenerated TypeScript types
✅ Define content in JSON, JS, or TS
Embed external files (Markdown, TXT…)
✅ Fetch and type remote content instantly
✅ Native CMS compatibility for editing content externally

⚡ Getting Started (React Native)

1️⃣ Install

npm install intlayer react-intlayer react-native-intlayer

2️⃣ Configure Locales

Create intlayer.config.ts at the root:

import { Locales, type IntlayerConfig } from "intlayer";  const config: IntlayerConfig = {   internationalization: {     locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],     defaultLocale: Locales.ENGLISH,   }, };  export default config;

3️⃣ Add Metro Support

In metro.config.js:

const { getDefaultConfig } = require("expo/metro-config"); const { configMetroIntlayer } = require("react-native-intlayer/metro");  module.exports = (async () => {   const defaultConfig = getDefaultConfig(__dirname);   return await configMetroIntlayer(defaultConfig); })();

4️⃣ Wrap Your App

In _layout.tsx:

import { Stack } from "expo-router"; import { getLocales } from "expo-localization"; import { IntlayerProviderContent } from "react-intlayer"; import { intlayerPolyfill } from "react-native-intlayer";  intlayerPolyfill();  const RootLayout = () => {   return (     <IntlayerProviderContent defaultLocale={getLocales()[0]?.languageTag}>       <Stack>         <Stack.Screen name="(tabs)" />       </Stack>     </IntlayerProviderContent>   ); };  export default RootLayout;

5️⃣ Define Localized Content by Component

Keep translations close to your UI:

import { t, md, file, type Dictionary } from "intlayer";  const homeScreenContent = {   key: "home-screen",   content: {     title: t({       en: "My Title",       fr: "Mon titre",       es: "Mi título",     }),     description: t({       en: md(file("./myDescription.en.md")),       fr: md(file("./myDescription.fr.md")),       es: md(file("./myDescription.es.md")),     }),     contentFetch: fetch("https://example.com").then((res) => res.text()),   }, } satisfies Dictionary;  export default homeScreenContent;

Then use them like this:

import { Text, View } from "react-native"; import { useIntlayer } from "react-intlayer";  const MyComponent = () => {   const { title, description, contentFetch } = useIntlayer("my-component");    return (     <View>       <Text>{title}</Text>       <Text>{description}</Text>       <Text>{contentFetch}</Text>     </View>   ); }; 

🔄 Switch Languages at Runtime

import { View, Text, TouchableOpacity } from "react-native"; import { getLocaleName } from "intlayer"; import { useLocale } from "react-intlayer";  const LocaleSwitcher = () => {   const { setLocale, availableLocales } = useLocale();    return (     <View>       {availableLocales.map((locale) => (         <TouchableOpacity key={locale} onPress={() => setLocale(locale)}>           <Text>{getLocaleName(locale)}</Text>         </TouchableOpacity>       ))}     </View>   ); };  export default LocaleSwitcher;

📚 Resources


ссылка на оригинал статьи https://habr.com/ru/articles/893170/