This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.
本地化
编辑页面
了解如何在 Expo 项目中使用 expo-localization 开始并配置本地化。
如果你希望应用对使用不同语言或来自不同文化背景的用户来说更易于使用,就应该对其进行本地化。本地化应用会使其适应用户设备的地区设置。应用将显示用户熟悉且能够理解的翻译内容和货币。数字、列表及其他内容也会按照用户习惯的格式进行显示。
本指南使用 expo-localization 库获取用户的语言设置,并添加多语言支持。同时以 i18n-js 为例,介绍如何添加多语言支持。
获取用户的语言
使用 expo-localization 库获取用户当前的语言。运行以下命令安装该软件包:
- npx expo install expo-localization然后,你就可以在应用中访问本地化方法和数据:
import { getLocales } from 'expo-localization'; const deviceLanguage = getLocales()[0].languageCode;
getLocales 方法会根据设备的系统设置返回当前区域设置。在较新版本的 Android 和 iOS 中,可以为每个应用单独设置应用语言,因此通常不需要构建自定义 UI 来让用户在应用中更改当前区域设置。
有时,构建一个 UI 以便用户为每个应用设置其他本地化偏好是有意义的。通常,你应该允许用户更改以下设置:
- 如果你的应用对本地化单位的使用程度中等或更高,则允许更改本地化单位(例如公制/英制、货币、温度等)
- 如果你支持的平台没有用于获取默认值的 API,则允许更改其他偏好设置(详情请参阅
expo-localizationAPI 文档)
通过系统设置启用按应用选择语言
Android 和 iOS 都允许用户通过系统设置为单个应用选择首选语言。要支持此功能,你的应用必须向系统声明其支持的区域设置。
为此,请使用 expo-localization 配置插件,并将 supportedLocales 属性传递给 expo-localization 配置插件。
你可以直接提供支持的区域设置数组,也可以使用 supportedLocales.ios 和 supportedLocales.android 字段来指定特定平台的值:
{ "expo": { "plugins": [ [ "expo-localization", { "supportedLocales": { "ios": ["en", "ja"], "android": ["en", "ja"] } } ] ] } }
在 Android 上,请参阅区域设置名称命名指南和最常用的区域设置列表。
在 iOS 上,请使用语言名称或 ISO 语言标识符。
翻译应用
创建和管理翻译很快就会变成一项大工程。你可以手动处理翻译,但最好使用库来帮你完成这项工作。
让我们让应用支持英语和日语。为此,本指南使用 i18n-js 包:
- npx expo install i18n-js查看其他翻译库,找到最适合你需求的库。
然后,为你的应用配置语言:
import { getLocales } from 'expo-localization'; import { I18n } from 'i18n-js'; // 为你想支持的不同语言设置键值对。 const i18n = new I18n({ en: { welcome: '你好' }, ja: { welcome: 'こんにちは' }, }); // 在应用开始时只设置一次地区。 i18n.locale = getLocales().at(0)?.languageCode ?? 'en'; // 你也可以写成 getLocales()[0].languageCode ?? 'en' console.log(i18n.t('welcome'));
现在,你可以在整个应用中使用 i18n.t 函数来翻译字符串。
对于某些内容,例如姓名,你可以不对其进行本地化。在这种情况下,你可以在默认语言中将它们 只定义一次,并通过 i18n.enableFallback = true; 复用它们。
在 Android 上,当用户更改设备语言时,应用不会重启。你可以使用 AppState API 监听应用状态变化,并在应用状态每次变化时调用 getLocales() 函数。
在 iOS 上,当用户更改设备语言时,应用会重启。这意味着你可以只设置一次语言,而无需更新任何 React 组件来响应语言变化。
完整示例
import { View, StyleSheet, Text } from 'react-native'; import { getLocales } from 'expo-localization'; import { I18n } from 'i18n-js'; // 为你想支持的不同语言设置键值对。 const translations = { en: { welcome: 'Hello', name: 'Charlie' }, ja: { welcome: 'こんにちは' }, }; const i18n = new I18n(translations); // 在应用开始时只设置一次地区。 i18n.locale = getLocales()[0].languageCode ?? 'en'; // 当某种语言缺少某个值时,会回退到另一个包含该键的语言。 i18n.enableFallback = true; // 如需查看回退机制,请取消下面一行的注释,强制应用使用日语。 // i18n.locale = 'ja'; export default function App() { return ( <View style={styles.container}> <Text style={styles.text}> {i18n.t('welcome')} {i18n.t('name')} </Text> <Text>当前地区:{i18n.locale}</Text> <Text>设备地区:{getLocales()[0].languageCode}</Text> </View> ); } const styles = StyleSheet.create({ container: { backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center', flex: 1, }, text: { fontSize: 20, marginBottom: 16, }, });
其他翻译库
本指南以 i18n-js 作为示例,但其他库也可以帮助你完成这项任务。创建翻译是一项重大工作。在选择库时,可以考虑以下几点:
- 与翻译管理工具集成,以便更轻松地管理字符串和进行自动化处理。
- 能够为字符串提供上下文,这样 AI 翻译工具和/或人工审校者就能理解字符串的上下文并提供更好的翻译。
- 开发体验——在 React / JSX 环境中的使用方式。有些库附带 ESLint 插件和其他工具来辅助开发。
- 不必担心日期或数字的本地化——请使用标准化的
IntlAPI 来处理这些内容。
下面是不完全列举的其他可考虑库:
-
Lingui 是一个成熟的库,原生支持 React(包括 React Server Components (RSC)),并且与翻译管理工具集成良好。
-
fbtee 是一个面向 JavaScript 和 React 的国际化框架,设计目标是强大、灵活且直观。
-
React i18next 是一个稳定、维护良好的库,基于
i18next。 -
Intlayer 是一个按组件划分的 i18n 库,带有提取器和 AI 工具,重点关注包体积和性能。
翻译应用元数据
如果你计划将应用发布到不同国家或地区,或者希望它支持多种语言,你可以为显示名称和系统对话框等内容提供本地化字符串。这可以很容易地在应用配置文件中设置。首先,将 ios.infoPlist.CFBundleAllowMixedLocalizations 设为 true,然后为 locales 提供文件路径列表。
{ "expo": { "ios": { "infoPlist": { "CFBundleAllowMixedLocalizations": true } }, "locales": { "ja": "./languages/japanese.json" } } }
传递给 locales 的键应该是语言标识符,由你想要的语言的2 字母语言代码组成,并可选带有地区代码(例如 en-US 或 en-GB),其值应指向一个类似下面这样的 JSON 文件:
{ "ios": { "CFBundleDisplayName": "こんにちは", "NSContactsUsageDescription": "日本語のこれらの言葉", "Localizable.strings": { "HELLO_NOTIFICATION_KEY": "こんにちは世界" } }, "android": { "app_name": "こんにちは", "HELLO_NOTIFICATION_KEY": "こんにちは世界" } }
现在,当应用安装在语言设置为日语的设备上时,其显示名称会被设置为 こんにちは。
在 SDK 55 及更高版本中,iOS 还提供一个选项,可以指定 Localizable.strings 对象,其条目会被用来创建原生本地化文件。这些条目可用于 iOS 本地化通知。
RTL 支持
世界上有一些地区使用从右到左(RTL)的书写方式。要让你的应用在 RTL 语言中呈现预期效果,你需要确保它能够相应地处理这些布局和文本方向的变化。
信息 本节介绍 SDK 58 及更高版本中的行为。在之前的版本中,RTL 支持默认启用,但在 Expo Go 中默认禁用。
RTL 支持默认启用。布局方向遵循 React Native 的 I18nManager。当设备设置为 RTL 语言(例如阿拉伯语或希伯来语)时,应用会以 RTL 方式渲染;否则会以从左到右(LTR)方式渲染。在 iOS 上,设备语言还必须是应用支持的语言环境之一,并通过 supportedLocales 选项声明。此行为适用于 Expo Go、开发构建版本,以及使用 EAS Build 或 npx expo prebuild 构建的应用。
禁用 RTL 支持
要选择退出 RTL 布局,请在 expo-localization 配置插件中将 supportsRTL 选项设置为 false:
{ "expo": { "plugins": [ [ "expo-localization", { "supportsRTL": false } ] ] } }
强制使用 RTL 布局
你可以强制使用 RTL 布局以进行测试,或者用于仅针对 RTL 语言环境进行本地化的应用。为此,请在 expo-localization 配置插件中将 forcesRTL 选项设置为 true:
{ "expo": { "plugins": [ [ "expo-localization", { "forcesRTL": true } ] ] } }
动态覆盖 RTL 设置
如果你想在应用代码中动态覆盖默认的 RTL 检测,就不能使用 app config 中的静态配置。相反,你需要从应用代码中动态应用这些更改。
这在 Expo Go 中不起作用,因为 Expo Go 在打开启动器或单个项目时会重置 RTL 偏好设置。
import { Text, View, StyleSheet, I18nManager, Platform } from 'react-native'; import Constants from 'expo-constants'; import * as Updates from 'expo-updates'; export default function App() { const shouldBeRTL = true; if (shouldBeRTL !== I18nManager.isRTL && Platform.OS !== 'web') { I18nManager.allowRTL(shouldBeRTL); I18nManager.forceRTL(shouldBeRTL); Updates.reloadAsync(); } return ( <View style={styles.container}> <Text style={styles.paragraph}>{I18nManager.isRTL ? ' RTL' : ' LTR'}</Text> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', paddingTop: Constants.statusBarHeight, padding: 8, }, paragraph: { fontSize: 18, fontWeight: 'bold', textAlign: 'left', width: '50%', backgroundColor: 'pink', }, });
让应用在 RTL 区域设置下正常运行
布局和视图
你不需要根据区域设置手动调整 <View> 的样式属性。你可以使用 justifyContent、alignItems 等属性。它们的属性值会按需改变行为。
- 在 LTR 区域设置中,
start和end等同于left和right。 - 在 RTL 区域设置中,
start和end等同于right和left。
有关 React Native 中 RTL 工作方式的更多细节,请查看介绍 RTL 支持的 React Native 博客文章。
Web 支持
RTL 布局的 Web 支持不需要更改应用配置。
Expo 在浏览器中运行 Expo 项目时使用 react-native-web。要让 react-native-web 自动适应区域方向,请在根 <View> 组件上添加 dir 属性。
import { View } from 'react-native'; import { getLocales } from 'expo-localization'; // ... return <View dir={getLocales()[0].textDirection || 'ltr'}>...</View>;
textDirection在 Firefox 和较旧的浏览器版本中不可用。必要时请手动检测。
文本对齐
React Native 的 textAlign 属性不接受你可以在 flex 属性中使用的 start 或 end 值。相反,left 实际上相当于 start(在 LTR 中左对齐,在 RTL 中右对齐),而 right 相当于 end。
不过,textAlign 属性默认未设置时表示实际的左侧(在 LTR 和 RTL 中都左对齐)。这意味着,如果你希望每个 <Text> 标签都能正确对齐,就应该为它设置 textAlign: left 或 textAlign: right 样式。
最好在你自定义的可复用 <Text> 组件中定义这个样式,然后在需要渲染文本字符串的所有地方导入它。
import { Text as RNText, TextProps as RNTextProps } from 'react-native'; const MobileText = (props: RNTextProps) => { return <RNText style={{ textAlign: 'left', ...props.style }} {...props} />; }; export default MobileText;
Web 支持
对于每个文本标签,你需要添加带有当前区域设置标识符的 lang 属性。最好在自定义的可复用组件中定义这个样式。
import { getLocales } from 'expo-localization'; const deviceLanguage = getLocales()[0].languageCode; const WebText = (props: RNTextProps) => { return <RNText lang={deviceLanguage} {...props} />; }; export default WebText;
然后,你可以根据当前平台选择移动端或 Web 版 Text 组件。
const Text = Platform.OS === 'web' ? WebText : MobileText; export default Text;
根据区域方向选择资源
如果你需要为 LTR/RTL 使用不同的图标,或者根据此设置更改样式,你可以使用 I18nManager.isRTL 来获取当前布局方向。
import { I18nManager } from 'react-native'; const isRTL = I18nManager.isRTL;
区域设置和单位
Expo 提供了 expo-localization 库,让你可以读取用户的区域设置和其他偏好。你可以使用同步的 getLocales() 和 getCalendars() 方法来获取用户设备当前的区域设置:
-
getLocales()会根据用户偏好的顺序返回一个区域设置列表。列表中始终至少会有一个区域设置。 -
getCalendars()会根据用户偏好的顺序返回一个日历列表。列表中始终至少会有一个日历。
import { getLocales, getCalendars } from 'expo-localization'; const { languageTag, languageCode, textDirection, digitGroupingSeparator, decimalSeparator, measurementSystem, currencyCode, currencySymbol, regionCode, } = getLocales()[0]; const { calendar, timeZone, uses24hourClock, firstWeekday } = getCalendars()[0];
限制
在依赖 expo-localization 自动检测到的区域偏好时,需要注意一些限制。
- 目前还没有办法从用户偏好中读取温度单位。在 Android 上,你可以使用基于区域设置的查找表。不过,在 iOS 上,用户可以在设备偏好设置中更改它。
- 某些属性在当前平台上不可用时可能为 null。
Intl API
如果你在应用中使用 Hermes,你可以在所有平台上使用 Intl API。
它提供了一组实用工具,可用于格式化列表、日期、数字、货币金额、单位、复数形式等更多内容。
如果你将 default 作为区域设置字符串传入,Intl API 会使用设备的区域设置,因此你无需依赖 expo-localization 来获取当前区域设置(例如 "en-US")。
new Intl.NumberFormat('default', { style: 'currency', currency: 'EUR' }).format(5.0);
一旦你知道用户期望看到什么,就可以使用
IntlAPI 来格式化字符串和值。
IntlAPI 不提供设备或当前区域设置的信息,因此你不能使用IntlAPI 来获取当前区域设置中的单位、货币或计量系统。为此,你需要使用
expo-localization、Web 上的 JS 代码,或者 Android 和 iOS 上的第三方或自定义原生代码。