Skip to content

Commit

Permalink
feat(mobile): add i18n support in rn
Browse files Browse the repository at this point in the history
  • Loading branch information
moonrailgun committed Mar 28, 2023
1 parent 6ab48b0 commit 5668e09
Show file tree
Hide file tree
Showing 11 changed files with 180 additions and 12 deletions.
6 changes: 6 additions & 0 deletions client/mobile/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,8 @@ PODS:
- React-Core
- RNGestureHandler (2.9.0):
- React-Core
- RNLocalize (2.2.6):
- React-Core
- RNNotifee (7.4.0):
- React-Core
- RNNotifee/NotifeeCore (= 7.4.0)
Expand Down Expand Up @@ -533,6 +535,7 @@ DEPENDENCIES:
- ReactNativeUiLib (from `../node_modules/react-native-ui-lib`)
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
- RNLocalize (from `../node_modules/react-native-localize`)
- "RNNotifee (from `../node_modules/@notifee/react-native`)"
- RNReanimated (from `../node_modules/react-native-reanimated`)
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
Expand Down Expand Up @@ -636,6 +639,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/@react-native-async-storage/async-storage"
RNGestureHandler:
:path: "../node_modules/react-native-gesture-handler"
RNLocalize:
:path: "../node_modules/react-native-localize"
RNNotifee:
:path: "../node_modules/@notifee/react-native"
RNReanimated:
Expand Down Expand Up @@ -697,6 +702,7 @@ SPEC CHECKSUMS:
ReactNativeUiLib: 8d3804947431a465a69f09c5e785c988314612a9
RNCAsyncStorage: 8616bd5a58af409453ea4e1b246521bb76578d60
RNGestureHandler: 071d7a9ad81e8b83fe7663b303d132406a7d8f39
RNLocalize: d4b8af4e442d4bcca54e68fc687a2129b4d71a81
RNNotifee: da8dcf09f079ea22f46e239d7c406e10d4525a5f
RNReanimated: cc5e3aa479cb9170bcccf8204291a6950a3be128
SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608
Expand Down
1 change: 1 addition & 0 deletions client/mobile/ios/Tailchat.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@
knownRegions = (
en,
Base,
"zh-Hans",
);
mainGroup = 83CBB9F61A601CBA00E9B192;
productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
2 changes: 2 additions & 0 deletions client/mobile/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"test": "jest"
},
"dependencies": {
"@formatjs/intl": "^2.6.9",
"@notifee/react-native": "^7.4.0",
"@react-native-async-storage/async-storage": "^1.17.11",
"immer": "^9.0.19",
Expand All @@ -26,6 +27,7 @@
"react-native-config": "^1.5.0",
"react-native-gesture-handler": "^2.9.0",
"react-native-getui": "^1.1.42",
"react-native-localize": "^2.2.6",
"react-native-reanimated": "^2.14.4",
"react-native-ui-lib": "^6.29.1",
"react-native-webview": "^11.26.1",
Expand Down
20 changes: 11 additions & 9 deletions client/mobile/src/Entry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
ActionSheet,
} from 'react-native-ui-lib';
import { isValidUrl } from './lib/utils';
import { translate } from './lib/i18n';

export const Entry: React.FC = React.memo(() => {
const { serverList, selectServer, addServer, removeServer } =
Expand Down Expand Up @@ -40,16 +41,19 @@ export const Entry: React.FC = React.memo(() => {
);
})}

<ServerCard name={'添加服务器'} onPress={() => setDialogVisible(true)} />
<ServerCard
name={translate('core.addServer')}
onPress={() => setDialogVisible(true)}
/>

<ActionSheet
visible={!!selectedServer}
message={`选中服务器: ${selectedServer}`}
message={`${translate('core.selectedServer')}: ${selectedServer}`}
onDismiss={() => setSelectedServer('')}
destructiveButtonIndex={0}
options={[
{
label: '删除服务器',
label: translate('core.deleteServer'),
onPress: () => {
removeServer(selectedServer);
},
Expand All @@ -64,7 +68,7 @@ export const Entry: React.FC = React.memo(() => {
onDismiss={() => setDialogVisible(false)}
>
<View backgroundColor="white" style={styles.dialog}>
<Text>输入服务器地址:</Text>
<Text>{translate('core.inputServerUrl')}:</Text>

<TextInput
style={styles.textInput}
Expand All @@ -74,11 +78,11 @@ export const Entry: React.FC = React.memo(() => {
/>

<Button
label={'确认'}
label={translate('core.confirm')}
disabled={loading}
onPress={async () => {
if (!isValidUrl(serverUrl)) {
Alert.alert('输入不是一个有效的url');
Alert.alert(translate('core.invalidUrl'));
return;
}

Expand All @@ -87,9 +91,7 @@ export const Entry: React.FC = React.memo(() => {
await addServer(serverUrl);
setDialogVisible(false);
} catch (e) {
Alert.alert(
'添加服务器失败, 可能输入的地址不是一个Tailchat服务地址'
);
Alert.alert(translate('core.addServerError'));
}

setLoading(false);
Expand Down
33 changes: 33 additions & 0 deletions client/mobile/src/lib/i18n/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import * as RNLocalize from 'react-native-localize';
import { createIntl, createIntlCache } from '@formatjs/intl';
import { I18nManager } from 'react-native';

const translations = {
en: require('./translations/en.json'),
zh: require('./translations/zh.json'),
} as const;

type Translation = keyof typeof translations;

const fallback = { languageTag: 'en', isRTL: false };

const { languageTag, isRTL } =
RNLocalize.findBestAvailableLanguage(Object.keys(translations)) ?? fallback;

I18nManager.forceRTL(isRTL);

const intl = createIntl(
{
defaultLocale: 'en',
locale: languageTag,
messages: translations[languageTag as Translation],
},
createIntlCache()
);

type TranslationParams = Parameters<(typeof intl)['formatMessage']>[1];

export const translate = (key: string, params?: TranslationParams) =>
intl
.formatMessage({ id: key, defaultMessage: translations.en[key] }, params)
.toString();
12 changes: 12 additions & 0 deletions client/mobile/src/lib/i18n/translations/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"core.addServer": "Add Server",
"core.selectedServer": "Selected Server",
"core.deleteServer": "Delete Server",
"core.inputServerUrl": "Input Server Url",
"core.confirm": "Confirm",
"core.invalidUrl": "Input is not a valid url",
"core.addServerError": "Failed to add server, maybe the address entered is not a Tailchat service address",
"core.foregroundServiceTip": "Continue to keep the service running normally, and may not be able to receive message pushes after closing",
"core.foregroundServiceStopAction": "Stop Foreground Service"

}
11 changes: 11 additions & 0 deletions client/mobile/src/lib/i18n/translations/zh.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"core.addServer": "添加服务器",
"core.selectedServer": "选中服务器",
"core.deleteServer": "删除服务器",
"core.inputServerUrl": "输入服务器地址",
"core.confirm": "确认",
"core.invalidUrl": "输入不是一个有效的url",
"core.addServerError": "添加服务器失败, 可能输入的地址不是一个Tailchat服务地址",
"core.foregroundServiceTip": "持续保持服务正常运行, 关闭后可能无法正常接受到消息推送",
"core.foregroundServiceStopAction": "停止前台服务"
}
5 changes: 3 additions & 2 deletions client/mobile/src/lib/notifications/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import notifee, { EventType } from '@notifee/react-native';
import { translate } from '../i18n';
import { bindAlias } from './getui';

interface NotificationInfo {
Expand Down Expand Up @@ -78,13 +79,13 @@ async function initForegroundService(options: NotificationOptions) {

notifee.displayNotification({
title: `Tailchat: ${options.nickname}`,
body: '持续保持服务正常运行, 关闭后可能无法正常接受到消息推送',
body: translate('core.foregroundServiceTip'),
android: {
channelId,
asForegroundService: true,
actions: [
{
title: '停止前台服务',
title: translate('core.foregroundServiceStopAction'),
pressAction: {
id: 'stop',
},
Expand Down
87 changes: 86 additions & 1 deletion client/mobile/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,76 @@
minimatch "^3.1.2"
strip-json-comments "^3.1.1"

"@formatjs/ecma402-abstract@1.14.3":
version "1.14.3"
resolved "https://registry.npmmirror.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.14.3.tgz#6428f243538a11126180d121ce8d4b2f17465738"
integrity sha512-SlsbRC/RX+/zg4AApWIFNDdkLtFbkq3LNoZWXZCE/nHVKqoIJyaoQyge/I0Y38vLxowUn9KTtXgusLD91+orbg==
dependencies:
"@formatjs/intl-localematcher" "0.2.32"
tslib "^2.4.0"

"@formatjs/fast-memoize@2.0.1":
version "2.0.1"
resolved "https://registry.npmmirror.com/@formatjs/fast-memoize/-/fast-memoize-2.0.1.tgz#f15aaa73caad5562899c69bdcad8db82adcd3b0b"
integrity sha512-M2GgV+qJn5WJQAYewz7q2Cdl6fobQa69S1AzSM2y0P68ZDbK5cWrJIcPCO395Of1ksftGZoOt4LYCO/j9BKBSA==
dependencies:
tslib "^2.4.0"

"@formatjs/icu-messageformat-parser@2.3.0":
version "2.3.0"
resolved "https://registry.npmmirror.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.3.0.tgz#8e8fd577c3e39454ef14bba4963f2e1d5f2cc46c"
integrity sha512-xqtlqYAbfJDF4b6e4O828LBNOWXrFcuYadqAbYORlDRwhyJ2bH+xpUBPldZbzRGUN2mxlZ4Ykhm7jvERtmI8NQ==
dependencies:
"@formatjs/ecma402-abstract" "1.14.3"
"@formatjs/icu-skeleton-parser" "1.3.18"
tslib "^2.4.0"

"@formatjs/icu-skeleton-parser@1.3.18":
version "1.3.18"
resolved "https://registry.npmmirror.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.18.tgz#7aed3d60e718c8ad6b0e64820be44daa1e29eeeb"
integrity sha512-ND1ZkZfmLPcHjAH1sVpkpQxA+QYfOX3py3SjKWMUVGDow18gZ0WPqz3F+pJLYQMpS2LnnQ5zYR2jPVYTbRwMpg==
dependencies:
"@formatjs/ecma402-abstract" "1.14.3"
tslib "^2.4.0"

"@formatjs/intl-displaynames@6.2.6":
version "6.2.6"
resolved "https://registry.npmmirror.com/@formatjs/intl-displaynames/-/intl-displaynames-6.2.6.tgz#6bc02fe0bf6571391aac0e01e74ecbf38542ff32"
integrity sha512-scf5AQTk9EjpvPhboo5sizVOvidTdMOnajv9z+0cejvl7JNl9bl/aMrNBgC72UH+bP3l45usPUKAGskV6sNIrA==
dependencies:
"@formatjs/ecma402-abstract" "1.14.3"
"@formatjs/intl-localematcher" "0.2.32"
tslib "^2.4.0"

"@formatjs/intl-listformat@7.1.9":
version "7.1.9"
resolved "https://registry.npmmirror.com/@formatjs/intl-listformat/-/intl-listformat-7.1.9.tgz#0c2ce67b610054f215dd2635a6da7da308cfbe3d"
integrity sha512-5YikxwRqRXTVWVujhswDOTCq6gs+m9IcNbNZLa6FLtyBStAjEsuE2vAU+lPsbz9ZTST57D5fodjIh2JXT6sMWQ==
dependencies:
"@formatjs/ecma402-abstract" "1.14.3"
"@formatjs/intl-localematcher" "0.2.32"
tslib "^2.4.0"

"@formatjs/intl-localematcher@0.2.32":
version "0.2.32"
resolved "https://registry.npmmirror.com/@formatjs/intl-localematcher/-/intl-localematcher-0.2.32.tgz#00d4d307cd7d514b298e15a11a369b86c8933ec1"
integrity sha512-k/MEBstff4sttohyEpXxCmC3MqbUn9VvHGlZ8fauLzkbwXmVrEeyzS+4uhrvAk9DWU9/7otYWxyDox4nT/KVLQ==
dependencies:
tslib "^2.4.0"

"@formatjs/intl@^2.6.9":
version "2.6.9"
resolved "https://registry.npmmirror.com/@formatjs/intl/-/intl-2.6.9.tgz#d4bdd8c21888f579a95341580141d0aafe761610"
integrity sha512-EtcMZ9O24YSASu/jGOaTQtArx7XROjlKiO4KmkxJ/3EyAQLCr5hrS+KKvNud0a7GIwBucOb3IFrZ7WiSm2A/Cw==
dependencies:
"@formatjs/ecma402-abstract" "1.14.3"
"@formatjs/fast-memoize" "2.0.1"
"@formatjs/icu-messageformat-parser" "2.3.0"
"@formatjs/intl-displaynames" "6.2.6"
"@formatjs/intl-listformat" "7.1.9"
intl-messageformat "10.3.3"
tslib "^2.4.0"

"@hapi/hoek@^9.0.0":
version "9.3.0"
resolved "https://registry.npmmirror.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb"
Expand Down Expand Up @@ -4460,6 +4530,16 @@ internal-slot@^1.0.3, internal-slot@^1.0.4:
has "^1.0.3"
side-channel "^1.0.4"

intl-messageformat@10.3.3:
version "10.3.3"
resolved "https://registry.npmmirror.com/intl-messageformat/-/intl-messageformat-10.3.3.tgz#576798d31c9f8d90f9beadaa5a3878b8d30177a2"
integrity sha512-un/f07/g2e/3Q8e1ghDKET+el22Bi49M7O/rHxd597R+oLpPOMykSv5s51cABVfu3FZW+fea4hrzf2MHu1W4hw==
dependencies:
"@formatjs/ecma402-abstract" "1.14.3"
"@formatjs/fast-memoize" "2.0.1"
"@formatjs/icu-messageformat-parser" "2.3.0"
tslib "^2.4.0"

invariant@*, invariant@2.2.4, invariant@^2.2.4:
version "2.2.4"
resolved "https://registry.npmmirror.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
Expand Down Expand Up @@ -7073,6 +7153,11 @@ react-native-gradle-plugin@^0.71.14:
resolved "https://registry.npmmirror.com/react-native-gradle-plugin/-/react-native-gradle-plugin-0.71.14.tgz#cc399662f04fbfcc0e352d03eae1d3efbd5f635a"
integrity sha512-nnLawTZEPPRAKq92UqDkzoGgCBl9aa9zAihFHMwmwzn4WRVdK4O6Cd4XYiyoNOiQzx3Hh9k5WOckHE80C92ivQ==

react-native-localize@^2.2.6:
version "2.2.6"
resolved "https://registry.npmmirror.com/react-native-localize/-/react-native-localize-2.2.6.tgz#484f8c700bc629f230066e819265f80f6dd3ef58"
integrity sha512-EZETlC1ZlW/4g6xfsNCwAkAw5BDL2A6zk/08JjFR/GRGxYuKRD7iP1hHn1+h6DEu+xROjPpoNeXfMER2vkTVIQ==

react-native-reanimated@^2.14.4:
version "2.14.4"
resolved "https://registry.npmmirror.com/react-native-reanimated/-/react-native-reanimated-2.14.4.tgz#3fa3da4e7b99f5dfb28f86bcf24d9d1024d38836"
Expand Down Expand Up @@ -8191,7 +8276,7 @@ tslib@^1.8.1:
resolved "https://registry.npmmirror.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==

tslib@^2.0.1, tslib@^2.1.0:
tslib@^2.0.1, tslib@^2.1.0, tslib@^2.4.0:
version "2.5.0"
resolved "https://registry.npmmirror.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf"
integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==
Expand Down

0 comments on commit 5668e09

Please sign in to comment.