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-intlayer2️⃣ 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;