写在前面
语言设置这个功能,对于面向国际市场的 App 来说是必须的。但说实话,大部分国内 App 都不做这个功能,因为用户群体就是中国人,没必要支持其他语言。
不过作为一个完整的商城项目,我还是把这个功能加上了。一方面是为了演示怎么做多语言切换,另一方面是万一以后要出海呢?提前把架子搭好,后面加语言包就方便了。
这篇文章记录一下语言设置页面的实现过程。页面本身很简单,就是一个语言列表,用户点击选择就行。但背后的多语言方案值得聊一聊。

支持哪些语言
先定义支持的语言列表:
tsx
const languages = [
{code: 'zh-CN', name: '简体中文', flag: '🇨🇳'},
{code: 'zh-TW', name: '繁體中文', flag: '🇹🇼'},
{code: 'en', name: 'English', flag: '🇺🇸'},
{code: 'ja', name: '日本語', flag: '🇯🇵'},
{code: 'ko', name: '한국어', flag: '🇰🇷'},
];
每种语言有三个属性:
code :语言代码,遵循 BCP 47 标准。
zh-CN是简体中文,zh-TW是繁体中文,en是英语,以此类推。name:语言名称,用该语言自己的文字显示。比如日语显示"日本語"而不是"Japanese",这样不管用户当前用什么语言,都能认出自己的母语。
flag:国旗 emoji,让列表更直观。
为什么选这五种语言?简体中文是主要用户群,繁体中文覆盖港澳台用户,英语是国际通用语言,日语和韩语是东亚主要市场。当然,实际项目中要根据目标市场来定。
引入需要的依赖
tsx
import React from 'react';
这个页面不需要本地状态,语言设置存在全局状态里。
tsx
import {View, Text, StyleSheet, TouchableOpacity, Alert} from 'react-native';
用
TouchableOpacity让每个语言选项可点击。Alert用来弹出设置成功的提示。
tsx
import {useApp} from '../store/AppContext';
import {Header} from '../components/Header';
useApp 里有 settings 对象和 updateSettings 方法。
获取全局状态
tsx
export const LanguageScreen = () => {
const {settings, updateSettings, goBack} = useApp();
三个东西:
settings :当前设置,里面有
language字段存储当前语言代码updateSettings:更新设置的方法
goBack:返回上一页
选择语言的逻辑
tsx
const handleSelect = (code: string) => {
updateSettings('language', code);
Alert.alert('设置成功', '语言设置已更新', [{text: '确定', onPress: goBack}]);
};
逻辑很简单:更新全局状态里的 language 字段,然后弹个提示,用户点确定返回上一页。
实际项目中,切换语言后应该立即生效,整个 App 的文字都要变。这需要配合 i18n 库来实现,后面会讲。我们这里只是保存了语言设置,没有真正实现多语言切换。
页面结构
tsx
return (
<View style={styles.container}>
<Header title="语言设置" />
<View style={styles.content}>
{languages.map(lang => (
// 语言选项
))}
</View>
</View>
);
结构很简单,一个 Header,下面是语言列表。
渲染语言选项
tsx
{languages.map(lang => (
<TouchableOpacity
key={lang.code}
style={styles.item}
onPress={() => handleSelect(lang.code)}
>
<Text style={styles.flag}>{lang.flag}</Text>
<Text style={styles.langName}>{lang.name}</Text>
{settings.language === lang.code && <Text style={styles.check}>✓</Text>}
</TouchableOpacity>
))}
每个语言选项包含三部分:
国旗:左边显示国旗 emoji,让用户快速识别
语言名称:中间显示语言名称
选中标记:如果是当前选中的语言,右边显示一个勾
选中标记用条件渲染:settings.language === lang.code 时才显示。
样式定义
typescript
const styles = StyleSheet.create({
container: {flex: 1, backgroundColor: '#f5f5f5'},
content: {flex: 1, backgroundColor: '#fff', marginTop: 12},
灰色背景上放白色的列表区域。
typescript
item: {
flexDirection: 'row',
alignItems: 'center',
padding: 16,
borderBottomWidth: 1,
borderBottomColor: '#f0f0f0'
},
每个选项横向排列,用
borderBottomWidth加分割线。最后一个选项的分割线会显示出来,如果觉得不好看可以用FlatList的ItemSeparatorComponent来处理。
typescript
flag: {fontSize: 24, marginRight: 12},
国旗用 24 号字,比较大,容易识别。
typescript
langName: {flex: 1, fontSize: 16, color: '#333'},
flex: 1让语言名称占据中间的空间,把选中标记挤到右边。
typescript
check: {fontSize: 20, color: '#3498db', fontWeight: 'bold'},
});
选中标记用蓝色,加粗,比较醒目。
关于多语言实现方案
上面只是做了语言设置的 UI,真正的多语言实现需要更多工作。聊一下常见的方案:
方案一:react-native-i18n / react-i18next
这是最常用的方案。把所有文案抽取到语言包文件里,根据当前语言加载对应的语言包。
tsx
// 语言包文件 zh-CN.json
{
"home": "首页",
"cart": "购物车",
"profile": "我的"
}
// 语言包文件 en.json
{
"home": "Home",
"cart": "Cart",
"profile": "Profile"
}
使用的时候:
tsx
import {useTranslation} from 'react-i18next';
const {t} = useTranslation();
<Text>{t('home')}</Text> // 根据当前语言显示"首页"或"Home"
这个方案的好处是成熟稳定,社区支持好。缺点是要把所有文案都抽取出来,工作量不小。
方案二:自己实现简易版
如果项目不大,可以自己实现一个简易版:
tsx
const translations = {
'zh-CN': {home: '首页', cart: '购物车'},
'en': {home: 'Home', cart: 'Cart'},
};
const t = (key: string) => {
const lang = settings.language || 'zh-CN';
return translations[lang][key] || key;
};
这个方案简单直接,但功能有限,不支持复数、插值等高级特性。
方案三:后端返回多语言
把文案存在后端,根据用户的语言设置返回对应语言的内容。
这个方案的好处是改文案不用发版,但增加了网络请求,而且离线时可能有问题。
我们这个项目为了简化,没有真正实现多语言,只是保存了语言设置。实际项目中建议用 react-i18next,功能完善,文档齐全。
多语言开发的一些经验
做过几个多语言项目,分享一些经验:
1. 文案长度差异
同样的意思,不同语言的文案长度可能差很多。比如"设置"两个字,英文是"Settings"八个字母。如果 UI 是按中文设计的,换成英文可能放不下。
解决办法:设计 UI 时留足空间,或者用
numberOfLines和ellipsizeMode处理超长文案。
2. 文字方向
阿拉伯语、希伯来语是从右往左书写的(RTL)。如果要支持这些语言,整个 UI 布局都要镜像。
React Native 支持 RTL,但需要额外处理。如果不打算支持 RTL 语言,可以先不管。
3. 日期和数字格式
不同地区的日期格式不一样。美国是 MM/DD/YYYY,中国是 YYYY-MM-DD,欧洲是 DD/MM/YYYY。数字的千位分隔符也不一样,有的用逗号,有的用点。
可以用
IntlAPI 或者moment.js/dayjs来处理。
4. 图片里的文字
如果图片里有文字(比如 Banner),切换语言后图片也要换。这个容易被忽略。
解决办法:尽量不在图片里放文字,或者为每种语言准备不同的图片。
5. 翻译质量
机器翻译的质量参差不齐,重要的文案最好人工翻译。特别是涉及到法律、金融的内容,翻译错了可能有法律风险。
语言设置的存储
语言设置应该持久化存储,不然用户每次打开 App 都要重新设置。
tsx
// 保存语言设置
await AsyncStorage.setItem('language', 'en');
// 读取语言设置
const language = await AsyncStorage.getItem('language') || 'zh-CN';
App 启动时读取存储的语言设置,应用到全局状态。如果没有存储过,就用默认语言(一般是简体中文,或者跟随系统语言)。
跟随系统语言
有些用户希望 App 语言跟随系统设置。可以加一个"跟随系统"选项:
tsx
const languages = [
{code: 'system', name: '跟随系统', flag: '🌐'},
{code: 'zh-CN', name: '简体中文', flag: '🇨🇳'},
// ...
];
选择"跟随系统"后,用 react-native-localize 获取系统语言:
tsx
import * as RNLocalize from 'react-native-localize';
const systemLanguage = RNLocalize.getLocales()[0].languageCode;
这个功能挺实用的,很多用户不想手动设置,跟随系统最省事。
小结
语言设置页面本身很简单,就是一个选择列表。但背后的多语言实现是个大话题。
几个关键点:
- 语言名称用该语言自己的文字显示
- 国旗 emoji 让列表更直观
- 选中状态用勾标记
- 切换后弹提示告知用户
关于多语言实现:
- 推荐用 react-i18next
- 注意文案长度差异
- 日期数字格式要本地化
- 语言设置要持久化存储
- 可以加"跟随系统"选项
多语言是个细活,做好了能让 App 走向国际市场,做不好会闹笑话。如果有出海计划,建议从项目一开始就考虑多语言架构。
下一篇写主题设置页面,敬请期待。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net