了解如何使用 expo-localization 在 Expo 项目中开始和配置本地化。
如果你希望你的应用易于使用不同语言或来自不同文化的用户,则应该对其进行本地化。本地化应用可以使其适应用户设备的区域设置。该应用将显示用户知道和理解的翻译和货币。数字、列表等将以用户习惯的方式格式化。
¥If you want your app to be easy to use for users who speak different languages or come from different cultures, you should localize it. Localizing an app makes it adapt to the locale of the user's device. The app will show translations and currencies that the user knows and understands. Numbers, lists, and more will be formatted in a way that the user is used to.
本指南使用 expo-localization
库来访问用户语言设置并添加对多种语言的支持。以 i18n-js
为例添加多语言支持。
¥This guide uses the expo-localization
library for accessing user language settings and adding support for multiple languages. It uses i18n-js
as an example to add multi-language support.
¥Getting the user's language
使用 expo-localization
库获取用户当前的语言。通过运行以下命令来安装该软件包:
¥Use the expo-localization
library to get the user's current language. Install the package by running the following command:
-
npx expo install expo-localization
然后,你将能够在应用中访问本地化方法和数据:
¥Then, you will be able to access localization methods and data in your app:
import { getLocales } from 'expo-localization';
const deviceLanguage = getLocales()[0].languageCode;
getLocales
方法根据设备的系统设置返回当前区域设置。在较新的 Android 和 iOS 版本上,可以为每个应用设置应用语言,因此你通常不需要构建自定义 UI 来允许用户更改应用内部的当前区域设置。
¥The getLocales
method returns the current locale based on the system settings of the device. On newer Android and iOS versions, app language can be set per app, so you usually don't need to build a custom UI to allow users to change the current locale inside of your app.
有时,构建一个 UI 以允许用户在每个应用的基础上设置其他本地化首选项是有意义的。作为一般规则,你应该允许用户更改以下内容:
¥Sometimes, it makes sense to build a UI to allow the user to set other localization preferences on a per-app basis. As a general rule, you should allow the user to change the following:
本地化单位(如果你的应用至少适度使用它们)(例如公制/英制测量、货币、温度等)
¥Localized units if your app makes at least a moderate use of them (such as metric/imperial measurements, currency, temperature, and more)
如果没有 API 可以在你想要支持的平台上获取默认值,则其他首选项(有关详细信息,请查看 expo-localization
API 文档)
¥Other preferences if there's no API to get the default value on platforms you want to support (check expo-localization
API documentation for details)
¥Translating an app
快速创建和管理翻译成为一项艰巨的任务。你可以手动处理翻译,但最好使用库来为你处理此操作。
¥Creating and managing translations quickly becomes a large task. You can handle translations manually, but it's best to use a library to handle this for you.
让我们让应用支持英语和日语。要实现此目的,请安装 i18n 软件包 i18n-js
:
¥Let's make the app support English and Japanese. To achieve this install the i18n package i18n-js
:
-
npx expo install i18n-js
然后,为你的应用配置语言:
¥Then, configure the languages for your app:
import { getLocales } from 'expo-localization';
import { I18n } from 'i18n-js';
// Set the key-value pairs for the different languages you want to support.
const i18n = new I18n({
en: { welcome: 'Hello' },
ja: { welcome: 'こんにちは' },
});
// Set the locale once at the beginning of your app.
i18n.locale = getLocales()[0].languageCode;
console.log(i18n.t('welcome'));
现在,你可以使用 i18n.t
函数在整个应用中翻译字符串。
¥Now, you can use the i18n.t
function to translate strings throughout your application.
你可以避免本地化某些内容的文本,例如名称。在这种情况下,你可以使用默认语言定义它们一次,然后在 i18n.enableFallback = true;
中重用它们。
¥You can refrain from localizing text for certain things, for example, names. In this case, you can define them once in your default language and reuse them with i18n.enableFallback = true;
.
在 Android 上,当用户更改设备语言时,应用不会重置。你可以使用 AppState
API 监听应用状态的更改,并在每次应用状态更改时调用 getLocales()
函数。
¥On Android, when a user changes the device's language, the app will not reset. You can use the AppState
API to listen for changes to the app's state and call the getLocales()
function each time the app's state changes.
在 iOS 上,当用户更改设备语言时,应用将重置。这意味着你可以设置一次语言,而无需更新任何 React 组件来应对语言更改。
¥On iOS, when a user changes the device's language, the app will reset. This means you can set the language once without updating any of your React components to account for the language changes.
¥Complete example
import { View, StyleSheet, Text } from 'react-native';
import { getLocales } from 'expo-localization';
import { I18n } from 'i18n-js';
// Set the key-value pairs for the different languages you want to support.
const translations = {
en: { welcome: 'Hello', name: 'Charlie' },
ja: { welcome: 'こんにちは' },
};
const i18n = new I18n(translations);
// Set the locale once at the beginning of your app.
i18n.locale = getLocales()[0].languageCode ?? 'en';
// When a value is missing from a language it'll fall back to another language with the key present.
i18n.enableFallback = true;
// To see the fallback mechanism uncomment the line below to force the app to use the Japanese language.
// i18n.locale = 'ja';
export default function App() {
return (
<View style={styles.container}>
<Text style={styles.text}>
{i18n.t('welcome')} {i18n.t('name')}
</Text>
<Text>Current locale: {i18n.locale}</Text>
<Text>Device locale: {getLocales()[0].languageCode}</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
flex: 1,
},
text: {
fontSize: 20,
marginBottom: 16,
},
});
¥Other translation libraries
本指南以 i18n-js
为例。其他库也可以帮助你进行翻译,每个库都有不同的功能:
¥This guide uses i18n-js
as an example. Other libraries can also help you with translations, and each has different features:
创建翻译是一项巨大的工作。考虑聘请专家并使用具有管理工具的翻译库,以更轻松地进行编辑和自动化。一些翻译库可以与翻译管理工具集成(本质上是一种 Web 服务,可让你外包、自动生成或更轻松地创建翻译)。
¥Creating translations is a huge effort. Consider hiring experts and using translation libraries with management tools for easier edits and automation. Some translation libraries can integrate with translation management tools (essentially, a web service that lets you outsource, auto-generate, or make it easier to create translations).
一些库允许根据翻译字符串重新排列组件结构。例如,你想要本地化包含 <Pressable>
链接的字符串,并且根据翻译,你希望链接的顺序与文本其余部分的顺序不同。
¥Some libraries allow rearranging component structures based on translation strings. For example, you want to localize a string that includes a <Pressable>
link, and depending on the translation you want the link to be in a different order from the rest of the text.
以下是一些库:
¥Here are some libraries:
React i18next
是一个基于 i18next
的稳定、维护良好的库。
¥React i18next
is a stable, well-maintained library based on i18next
.
typesafe-i18n
编译翻译以节省生产包中的空间。它还为你的翻译生成 TypeScript 类型,以便你可以在代码中使用它们并获得自动补齐和类型安全。它需要 Intl
API 来实现某些功能,因此它只能在启用了 Hermes 的项目中使用。
¥typesafe-i18n
compiles translations to save space in the production bundle. It also generates TypeScript types for your translations so that you can use them in your code and get autocomplete and type safety. It requires the Intl
API for some features, so it's only usable in projects with Hermes enabled.
¥Translating app metadata
如果你计划将应用发布到不同的国家或地区或希望它支持多种语言,你可以为显示名称和系统对话框等内容提供 localized 字符串。这很容易设置 在应用配置中 文件。首先,设置 ios.infoPlist.CFBundleAllowMixedLocalizations: true
,然后提供 locales
的文件路径列表。
¥If you plan on shipping your app to different countries or regions or want it to support various languages, you can provide localized strings for things like the display name and system dialogs. This is easily set up in the app config file. First, set ios.infoPlist.CFBundleAllowMixedLocalizations: true
, then provide a list of file paths to locales
.
{
"expo": {
"ios": {
"infoPlist": {
"CFBundleAllowMixedLocalizations": true
}
},
"locales": {
"ja": "./languages/japanese.json"
}
}
}
提供给 locales
的键应该是 语言标识符,由所需语言的 2 个字母的语言代码 组成,带有可选的区域代码(例如 en-US
或 en-GB
),并且该值应指向如下所示的 JSON 文件:
¥The keys provided to locales
should be the language identifier, made up of a 2-letter language code of your desired language, with an optional region code (for example, en-US
or en-GB
), and the value should point to a JSON file that looks something like below:
{
"CFBundleDisplayName": "こんにちは",
"NSContactsUsageDescription": "日本語のこれらの言葉"
}
现在,只要应用安装在语言设置为日语的设备上,iOS 就会将应用的显示名称设置为 こんにちは
。
¥Now, iOS knows to set the display name of your app to こんにちは
whenever it's installed on a device with the language set to Japanese.
¥Enabling RTL support
世界上的一些地区从右到左书写文本。如果你想要本地化你的应用,使其在 RTL 语言中看起来符合预期,你需要确保你的应用相应地处理这些布局和文本方向更改。
¥Several regions around the world write text from right to left. If you want to localize your app, so it looks as expected in RTL languages, you need to make sure your app handles these layout and text direction changes accordingly.
要启用 RTL 支持,请使用 expo-localization
配置插件并在应用配置中启用 extra.supportsRTL
属性:
¥To enable RTL support, use the expo-localization
config plugin and enable extra.supportsRTL
property in app config:
{
"expo": {
"extra": {
"supportsRTL": true
},
"plugins": ["expo-localization"]
}
}
当你的应用加载到 Expo Go、Expo dev Client 以及使用 EAS Build 或 npx expo prebuild
构建的应用中时,这将启用 RTL。
¥This enables RTL when your app is loaded in Expo Go, in Expo dev Client, and in applications built using EAS Build or npx expo prebuild
.
当应用启动时,Expo 会检查当前设备区域设置是否应以 RTL 布局渲染,以便看起来正确。例如,在应用配置文件中标记为支持 RTL 的应用将在希伯来语或阿拉伯语区域设置中以 RTL 模式渲染。
¥When an application starts, Expo checks if the current device locale should render in RTL layout to look correctly. For example, an app marked to support RTL in the app config file will render in RTL mode in Hebrew or Arabic locale.
¥Forcing RTL layout
你还可以通过在应用配置中启用 extra.forcesRTL
属性来强制 RTL 布局进行测试或仅针对 RTL 语言环境进行本地化的应用:
¥You can also force the RTL layout for testing or for applications that are only localized for RTL locales by enabling extra.forcesRTL
property in the app config:
{
"expo": {
"extra": {
"supportsRTL": true,
"forcesRTL": true
},
"plugins": ["expo-localization"]
}
}
如果你想动态覆盖应用代码中的默认 RTL 检测,则无法在应用配置中使用静态配置。相反,从应用代码动态应用这些更改。
¥If you want to override the default RTL detection from your application code dynamically, you cannot use the static configuration in app config. Instead, apply these changes dynamically from your application code.
这在 Expo Go 中不起作用,因为 Expo Go 在打开启动器或单个项目时会重置 RTL 首选项。
¥This does not work in Expo Go, as Expo Go resets RTL preferences when opening the launcher or individual projects.
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',
},
});
¥Making an app behave correctly on RTL locales
¥Layouts and views
你不需要根据区域设置手动调整 <View>
样式属性。你可以使用 justifyContext
、alignItems
等属性。它们的属性值根据需要改变行为。
¥You don't need to manually adjust <View>
styling properties based on locale. You can use properties like justifyContext
, alignItems
, and others. Their property values change behavior as required.
在 LTR 语言环境中,start
和 end
与 left
和 right
相同。
¥On LTR locales, start
and end
are the same as left
and right
.
在 RTL 语言环境中,start
和 end
与 right
和 left
相同。
¥On RTL locales, start
and end
are the same as right
and left
.
有关 RTL 如何在 React Native 中工作的更多详细信息,请查看引入 RTL 支持的 React Native 博客文章。
¥Web support
对 RTL 布局的 Web 支持不需要更改应用配置。
¥Web support for RTL layouts requires no app config changes.
Expo 使用 react-native-web
在浏览器中运行 Expo 项目。要使 react-native-web
自动适应区域设置方向,请将 dir
属性添加到根 <View>
组件。
¥Expo uses react-native-web
for running Expo projects in the browser. To make react-native-web
automatically adapt to locale direction, add a dir
property to your root <View>
component.
import { View } from 'react-native';
import { getLocales } from 'expo-localization';
// ...
return <View dir={getLocales()[0].textDirection || 'ltr'}>//...</View>;
textDirection
在 Firefox 和旧版浏览器上不可用。手动检测(如果需要)。
¥Text alignment
React Native 的 textDirection
属性不接受可在 flex 属性中使用的 start
或 end
值。相反,left
实际上充当 start
(在 LTR 上向左对齐,在 RTL 上向右对齐),而 right
则充当 end
。
¥The React Native's textDirection
property does not accept start
or end
values that you can use in flex properties. Instead, left
effectively works as start
(aligns to the left on LTR and the right on RTL), and right
works as end
.
但是,textDirection
属性的默认未设置值表示实际左侧(在 LTR 和 RTL 上均向左对齐)。这意味着如果你希望正确对齐每个 <Text>
标签,则应设置 textDirection: left
或 textDirection: right
样式。
¥However, the default unset value of textDirection
property signifies the actual left (aligns to the left both on LTR and RTL). This means each <Text>
tag should have the textDirection: left
or textDirection: right
style set if you want it to be aligned correctly.
最好在自定义可重用 <Text>
组件中定义此样式,然后可以将其导入到渲染文本字符串所需的任何位置。
¥It's best to define this style in your custom reusable <Text>
component that you can then import everywhere you need to render text strings.
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 support
对于每个文本标记,你需要添加带有当前区域设置标识符的 lang
属性。最好在自定义可重用组件中定义此样式。
¥For each text tag, you need to add the lang
property with the current locale identifier. It's best to define this style in a custom reusable component.
import { getLocales } from 'expo-localization';
const deviceLanguage = getLocales()[0].languageCode;
const WebText = (props: RNTextProps) => {
return <RNText lang={deviceLanguage} {...props} />;
};
export default WebText;
然后,你可以根据当前平台选择移动或网络文本组件。
¥You can then pick either the mobile or web Text component based on the current platform.
const Text = Platform.OS === 'web' ? WebText : MobileText;
export default Text;
¥Selecting assets based on locale direction
如果你需要为 LTR/RTL 使用不同的图标或根据此设置更改样式,可以使用 I18nManager.isRTL
获取当前的布局方向。
¥If you need to use different icons for LTR/RTL or change styles based on this setting, you can use I18nManager.isRTL
to get the current layout direction.
¥Locale settings and units
Expo 提供了 expo-localization
库,允许你读取用户的区域设置和其他首选项。
¥Expo provides the expo-localization
library to allow you to read the user's locale and other preferences.
你可以使用同步 getLocales()
和 getCalendars()
方法来获取用户设备的当前区域设置。
¥You can use synchronous getLocales()
and getCalendars()
methods to get the current locale settings of the user device.
getLocales()
根据用户偏好的顺序返回区域设置列表。列表中始终至少有一个区域设置。
¥getLocales()
returns a list of locales based on the order in which the user prefers them. There will always be at least one locale in the list.
getCalendars()
根据用户偏好的顺序返回日历列表。列表中总会至少有一个日历。
¥getCalendars()
returns a list of calendars based on the order in which the user prefers them. There will always be at least one calendar on the list.
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
自动检测的区域设置首选项时,需要记住一些限制。
¥There are a few limitations to keep in mind when relying on auto-detected locale preferences from expo-localization
.
目前还没有一种方法可以从用户偏好中读取温度单位。在 Android 上,你可以使用基于区域设置的查找表。但是,在 iOS 上,用户可以在设备首选项中更改它。
¥There is yet to be a way to read temperature units from user preferences. On Android, you can use a lookup table based on locale. However, on iOS, the user can change it in device preferences.
当某些属性在当前平台上不可用时,它们可以为 null。
¥Some properties can be null when they are unavailable on the current platform.
¥Intl API
如果你在应用中使用 Hermes,则可以在所有平台上使用 Intl
API。
¥If you're using Hermes in your app, you can use the Intl
API on all platforms.
它提供了一组实用程序,可用于格式化列表、日期、数字、货币金额、单位、复数形式等。
¥It provides a set of utilities you can use to format lists, dates, numbers, monetary amounts, units, plural forms, and more.
如果你传递 default
作为区域设置字符串,Intl
API 将使用设备的区域设置,因此你不需要依赖 expo-localization
来获取当前区域设置(例如 "en-US"
)。
¥If you pass default
as the locale string, the Intl
API will use the device's locale, so you don't need to rely on expo-localization
to get the current locale (such as "en-US"
).
new Intl.NumberFormat('default', { style: 'currency', currency: 'EUR' }).format(5.0);
一旦你知道用户期望看到什么,你就可以使用
Intl
API 来格式化字符串和值。¥You can use
Intl
APIs to format strings and values once you know what the user expects to see.
Intl
API 不提供有关设备或当前区域设置的信息,因此你无法使用Intl
API 获取当前区域设置单位、货币或测量系统。¥
Intl
APIs do not provide information about the device or current locale, so you can't use theIntl
APIs to get current locale units, currencies, or measurement systems.为此,你需要在 Web 上使用
expo-localization
、JS 代码,或者在 Android 和 iOS 上使用第三方或自定义原生代码。¥For this you need to use
expo-localization
, JS code on the web, or third-party or custom native code on Android and iOS.