快速開始

Expo

本頁示範 Intor 在 Expo 專案中的最小整合流程。


安裝

本指南假設你已經建立好 Expo 專案。
專案建立方式請參考官方文件:Expo

為了啟用語系持久化功能,請安裝以下套件:

  • expo-localization
  • @react-native-async-storage/async-storage
npx expo install expo-localization @react-native-async-storage/async-storage

安裝 Intor:

npm install intor
yarn add intor
pnpm add intor
bun add intor

專案結構

index.json
U

index.json
U

_layout.tsx
M
index.tsx
M

intor-config.ts
U
intor-client-provider.tsx
U

整合步驟

♯1 翻譯內容

在專案中建立 messages 資料夾,並依語系建立子資料夾,每個語系提供一個 index.json

index.json
U

index.json
U
{
  "hello": "Hello, {name}",
  "rich": "A <tag>text</tag>."
}
{
  "hello": "Bonjour, {name}",
  "rich": "Un <tag>texte</tag>."
}

♯2 設定檔

src/ 下建立 i18n/ 資料夾,並於其中建立 intor-config.ts
本範例採用最基本的翻譯內容載入方式,直接將 messages 定義於設定檔中。

詳見:載入翻譯內容

intor-config.ts
U
import { defineIntorConfig } from "intor";
import EN from "../../messages/en/index.json";
import FR from "../../messages/fr/index.json";

export const intorConfig = defineIntorConfig({
  defaultLocale: "en",
  supportedLocales: ["en", "fr"],
  messages: {
    en: EN,
    fr: FR,
  },
});

♯3 初始化

i18n/ 資料夾中建立 intor-client-provider.tsx

intor-client-provider.tsx
U
import AsyncStorage from "@react-native-async-storage/async-storage";
import { getLocales } from "expo-localization";
import { matchLocale } from "intor";
import { IntorProvider } from "intor/react";
import { useEffect, useState, type ReactNode } from "react";
import { intorConfig } from "./intor-config";

const STORAGE_KEY = "locale";

function resolveLocale(candidate?: string): string {
  const matched = matchLocale(candidate, intorConfig.supportedLocales);
  return matched ?? intorConfig.defaultLocale;
}

function getInitialLocale(): string {
  return resolveLocale(getLocales()[0]?.languageTag);
}

export function IntorClientProvider({ children }: { children: ReactNode }) {
  const [locale, setLocale] = useState(getInitialLocale);

  useEffect(() => {
    (async () => {
      const stored = await AsyncStorage.getItem(STORAGE_KEY);
      if (stored) setLocale(resolveLocale(stored));
    })();
  }, []);

  return (
    <IntorProvider
      value={{
        config: intorConfig,
        locale,
        onLocaleChange: async (locale) => {
          await AsyncStorage.setItem(STORAGE_KEY, locale);
        },
      }}
    >
      {children}
    </IntorProvider>
  );
}

接著,在 _layout.tsx 中使用這個 provider 包裹整個應用程式。

_layout.tsx
M
// ...
import { IntorClientProvider } from "../i18n/intor-client-provider";

export default function TabLayout() {
  const colorScheme = useColorScheme();
  return (
    <IntorClientProvider>
      <ThemeProvider value={colorScheme === "dark" ? DarkTheme : DefaultTheme}>
        <AnimatedSplashOverlay />
        <AppTabs />
      </ThemeProvider>
    </IntorClientProvider>
  );
}

使用範例

透過 useTranslator 取得翻譯相關能力:

  • t:取得對應文字
  • tRich:渲染包含語意 tag 的結構化翻譯內容
index.tsx
M
import { useTranslator } from "intor/react";
import { Button, Text, View } from "react-native";

export default function HomeScreen() {
  const { t, tRich, setLocale } = useTranslator();

  return (
    <View style={{ margin: 80, gap: 20, backgroundColor: "white" }}>
      <Text>{t("hello", { name: "Intor" })}</Text>

      <Text>
        {tRich("rich", {
          tag: (children) => (
            <Text style={{ fontWeight: "bold" }}>{children}</Text>
          ),
        })}
      </Text>

      <Button title="English" onPress={() => setLocale("en")} />
      <Button title="French" onPress={() => setLocale("fr")} />
    </View>
  );
}