Skip to content

Commit 584f698

Browse files
committed
bump version to 10.31.0-beta.0 and integrate i18n for improved localization support
1 parent e58903a commit 584f698

File tree

10 files changed

+333
-83
lines changed

10 files changed

+333
-83
lines changed

Example/testHotUpdate/bun.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"react-native-paper": "^5.14.5",
1313
"react-native-safe-area-context": "^5.5.0",
1414
"react-native-svg": "^15.12.0",
15-
"react-native-update": "^10.29.4",
15+
"react-native-update": "^10.31.0-beta.0",
1616
"react-native-vector-icons": "^10.2.0",
1717
},
1818
"devDependencies": {
@@ -1420,7 +1420,7 @@
14201420

14211421
"react-native-svg": ["[email protected]", "", { "dependencies": { "css-select": "^5.1.0", "css-tree": "^1.1.3", "warn-once": "0.1.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-iE25PxIJ6V0C6krReLquVw6R0QTsRTmEQc4K2Co3P6zsimU/jltcDBKYDy1h/5j9S/fqmMeXnpM+9LEWKJKI6A=="],
14221422

1423-
"react-native-update": ["react-native-update@10.29.4", "", { "dependencies": { "nanoid": "^3.3.3", "react-native-url-polyfill": "^2.0.0" }, "peerDependencies": { "react": ">=16.8.0", "react-native": ">=0.59.0" } }, "sha512-leQX3dq4yBi/oFn0l06nXd7OOFnZnlcMIrAXH7vgTRsqXCdYLoSsZXXkcSYxncn8tBqzh02w4880mlqouve6Sg=="],
1423+
"react-native-update": ["react-native-update@10.31.0-beta.0", "", { "dependencies": { "nanoid": "^3.3.3", "react-native-url-polyfill": "^2.0.0" }, "peerDependencies": { "react": ">=16.8.0", "react-native": ">=0.59.0" } }, "sha512-kQJxvc0q+acBfdBfeSjs8tq+0B79c+9QZUrHgLX9lWhnIl4qZ17QZ/WJOdkpPq6asPjUiCrUxdEhfp0lr50p4w=="],
14241424

14251425
"react-native-url-polyfill": ["[email protected]", "", { "dependencies": { "whatwg-url-without-unicode": "8.0.0-3" }, "peerDependencies": { "react-native": "*" } }, "sha512-My330Do7/DvKnEvwQc0WdcBnFPploYKp9CYlefDXzIdEaA+PAhDYllkvGeEroEzvc4Kzzj2O4yVdz8v6fjRvhA=="],
14261426

Example/testHotUpdate/ios/Podfile.lock

Lines changed: 4 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1407,7 +1407,7 @@ PODS:
14071407
- ReactCommon/turbomodule/bridging
14081408
- ReactCommon/turbomodule/core
14091409
- Yoga
1410-
- react-native-update (10.29.4):
1410+
- react-native-update (10.31.0-beta.0):
14111411
- DoubleConversion
14121412
- glog
14131413
- hermes-engine
@@ -1423,8 +1423,7 @@ PODS:
14231423
- React-hermes
14241424
- React-ImageManager
14251425
- React-jsi
1426-
- react-native-update/HDiffPatch (= 10.29.4)
1427-
- react-native-update/RCTPushy (= 10.29.4)
1426+
- react-native-update/RCTPushy (= 10.31.0-beta.0)
14281427
- React-NativeModulesApple
14291428
- React-RCTFabric
14301429
- React-renderercss
@@ -1435,33 +1434,7 @@ PODS:
14351434
- ReactCommon/turbomodule/core
14361435
- SSZipArchive
14371436
- Yoga
1438-
- react-native-update/HDiffPatch (10.29.4):
1439-
- DoubleConversion
1440-
- glog
1441-
- hermes-engine
1442-
- RCT-Folly (= 2024.11.18.00)
1443-
- RCTRequired
1444-
- RCTTypeSafety
1445-
- React
1446-
- React-Core
1447-
- React-debug
1448-
- React-Fabric
1449-
- React-featureflags
1450-
- React-graphics
1451-
- React-hermes
1452-
- React-ImageManager
1453-
- React-jsi
1454-
- React-NativeModulesApple
1455-
- React-RCTFabric
1456-
- React-renderercss
1457-
- React-rendererdebug
1458-
- React-utils
1459-
- ReactCodegen
1460-
- ReactCommon/turbomodule/bridging
1461-
- ReactCommon/turbomodule/core
1462-
- SSZipArchive
1463-
- Yoga
1464-
- react-native-update/RCTPushy (10.29.4):
1437+
- react-native-update/RCTPushy (10.31.0-beta.0):
14651438
- DoubleConversion
14661439
- glog
14671440
- hermes-engine
@@ -2187,7 +2160,7 @@ SPEC CHECKSUMS:
21872160
React-Mapbuffer: c3f4b608e4a59dd2f6a416ef4d47a14400194468
21882161
React-microtasksnativemodule: 054f34e9b82f02bd40f09cebd4083828b5b2beb6
21892162
react-native-safe-area-context: 11d29ae675265669f498d7d9de2341087e8fe162
2190-
react-native-update: 6d3a3eb322cbc382ad78853cb52e44e8c93e8072
2163+
react-native-update: 25c349c4edf9dc895beeb1281cccc9d93f1cb3be
21912164
React-NativeModulesApple: 2c4377e139522c3d73f5df582e4f051a838ff25e
21922165
React-oscompat: ef5df1c734f19b8003e149317d041b8ce1f7d29c
21932166
React-perflogger: 9a151e0b4c933c9205fd648c246506a83f31395d

Example/testHotUpdate/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"react-native-paper": "^5.14.5",
2323
"react-native-safe-area-context": "^5.5.0",
2424
"react-native-svg": "^15.12.0",
25-
"react-native-update": "^10.29.4",
25+
"react-native-update": "^10.31.0-beta.0",
2626
"react-native-vector-icons": "^10.2.0"
2727
},
2828
"devDependencies": {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-native-update",
3-
"version": "10.30.4",
3+
"version": "10.31.0-beta.0",
44
"description": "react-native hot update",
55
"main": "src/index",
66
"scripts": {

src/client.ts

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
promiseAny,
2929
testUrls,
3030
} from './utils';
31+
import i18n from './i18n';
3132

3233
const SERVER_PRESETS = {
3334
// cn
@@ -107,13 +108,18 @@ export class Pushy {
107108
})();
108109

109110
constructor(options: ClientOptions, clientType?: 'Pushy' | 'Cresc') {
111+
this.clientType = clientType || 'Pushy';
112+
this.options.server = SERVER_PRESETS[this.clientType];
113+
114+
// Initialize i18n based on clientType
115+
i18n.setLocale(this.clientType === 'Pushy' ? 'zh' : 'en');
116+
110117
if (Platform.OS === 'ios' || Platform.OS === 'android') {
111118
if (!options.appKey) {
112-
throw new Error('appKey is required');
119+
throw new Error(i18n.t('error_appkey_required'));
113120
}
114121
}
115-
this.clientType = clientType || 'Pushy';
116-
this.options.server = SERVER_PRESETS[this.clientType];
122+
117123
this.setOptions(options);
118124
if (isRolledBack) {
119125
this.report({
@@ -136,6 +142,16 @@ export class Pushy {
136142
}
137143
};
138144

145+
/**
146+
* Get translated text based on current clientType
147+
* @param key - Translation key
148+
* @param values - Values for interpolation (optional)
149+
* @returns Translated string
150+
*/
151+
t = (key: string, values?: Record<string, string | number>) => {
152+
return i18n.t(key as any, values);
153+
};
154+
139155
report = async ({
140156
type,
141157
message = '',
@@ -175,11 +191,7 @@ export class Pushy {
175191
};
176192
assertDebug = (matter: string) => {
177193
if (__DEV__ && !this.options.debug) {
178-
console.info(
179-
`You are currently in the development environment and have not enabled debug mode.
180-
${matter} will not be performed.
181-
If you need to debug ${matter} in the development environment, please set debug to true in the client.`,
182-
);
194+
console.info(this.t('dev_debug_disabled', { matter }));
183195
return false;
184196
}
185197
return true;
@@ -270,7 +282,7 @@ export class Pushy {
270282
} catch (e: any) {
271283
this.report({
272284
type: 'errorChecking',
273-
message: `Can not connect to update server: ${e.message}. Trying backup endpoints.`,
285+
message: this.t('error_cannot_connect_backup', { message: e.message }),
274286
});
275287
const backupEndpoints = await this.getBackupEndpoints();
276288
if (backupEndpoints) {
@@ -290,14 +302,17 @@ export class Pushy {
290302
if (!resp) {
291303
this.report({
292304
type: 'errorChecking',
293-
message: 'Can not connect to update server. Please check your network.',
305+
message: this.t('error_cannot_connect_server'),
294306
});
295307
this.throwIfEnabled(new Error('errorChecking'));
296308
return this.lastRespJson ? await this.lastRespJson : emptyObj;
297309
}
298310

299311
if (resp.status !== 200) {
300-
const errorMessage = `${resp.status}: ${resp.statusText}`;
312+
const errorMessage = this.t('error_http_status', {
313+
status: resp.status,
314+
statusText: resp.statusText,
315+
});
301316
this.report({
302317
type: 'errorChecking',
303318
message: errorMessage,
@@ -416,7 +431,9 @@ export class Pushy {
416431
});
417432
succeeded = 'diff';
418433
} catch (e: any) {
419-
const errorMessage = `diff error: ${e.message}`;
434+
const errorMessage = this.t('error_diff_failed', {
435+
message: e.message,
436+
});
420437
errorMessages.push(errorMessage);
421438
lastError = new Error(errorMessage);
422439
log(errorMessage);
@@ -433,7 +450,9 @@ export class Pushy {
433450
});
434451
succeeded = 'pdiff';
435452
} catch (e: any) {
436-
const errorMessage = `pdiff error: ${e.message}`;
453+
const errorMessage = this.t('error_pdiff_failed', {
454+
message: e.message,
455+
});
437456
errorMessages.push(errorMessage);
438457
lastError = new Error(errorMessage);
439458
log(errorMessage);
@@ -451,7 +470,9 @@ export class Pushy {
451470
});
452471
succeeded = 'full';
453472
} catch (e: any) {
454-
const errorMessage = `full patch error: ${e.message}`;
473+
const errorMessage = this.t('error_full_patch_failed', {
474+
message: e.message,
475+
});
455476
errorMessages.push(errorMessage);
456477
lastError = new Error(errorMessage);
457478
log(errorMessage);

src/i18n.ts

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import zhTranslations from './locales/zh';
2+
import enTranslations from './locales/en';
3+
4+
type TranslationKey = keyof typeof zhTranslations | keyof typeof enTranslations;
5+
type TranslationValues = Record<string, string | number>;
6+
7+
class I18n {
8+
private currentLocale: 'zh' | 'en' = 'en';
9+
private translations = {
10+
zh: zhTranslations,
11+
en: enTranslations,
12+
};
13+
14+
/**
15+
* Set locale directly
16+
* @param locale - 'zh' or 'en'
17+
*/
18+
setLocale(locale: 'zh' | 'en') {
19+
this.currentLocale = locale;
20+
}
21+
22+
/**
23+
* Get current locale
24+
*/
25+
getLocale(): 'zh' | 'en' {
26+
return this.currentLocale;
27+
}
28+
29+
/**
30+
* Translate a key with optional interpolation
31+
* @param key - Translation key
32+
* @param values - Values for interpolation (optional)
33+
* @returns Translated string with interpolated values
34+
*/
35+
t(key: TranslationKey, values?: TranslationValues): string {
36+
const translation =
37+
this.translations[this.currentLocale][
38+
key as keyof (typeof this.translations)[typeof this.currentLocale]
39+
];
40+
41+
if (!translation) {
42+
// Fallback to the other locale if key not found
43+
const fallbackLocale = this.currentLocale === 'zh' ? 'en' : 'zh';
44+
const fallbackTranslation =
45+
this.translations[fallbackLocale][
46+
key as keyof (typeof this.translations)[typeof fallbackLocale]
47+
];
48+
49+
if (!fallbackTranslation) {
50+
// If still not found, return the key itself
51+
return String(key);
52+
}
53+
54+
return this.interpolate(fallbackTranslation, values);
55+
}
56+
57+
return this.interpolate(translation, values);
58+
}
59+
60+
/**
61+
* Interpolate values into a string template
62+
* Supports {{key}} syntax
63+
* @param template - String template with {{key}} placeholders
64+
* @param values - Values to interpolate
65+
* @returns Interpolated string
66+
*/
67+
private interpolate(template: string, values?: TranslationValues): string {
68+
if (!values) {
69+
return template;
70+
}
71+
72+
return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
73+
const value = values[key];
74+
return value !== undefined ? String(value) : match;
75+
});
76+
}
77+
78+
/**
79+
* Add or update translations for a specific locale
80+
* @param locale - Target locale
81+
* @param translations - Translation object to merge
82+
*/
83+
addTranslations(locale: 'zh' | 'en', translations: Record<string, string>) {
84+
this.translations[locale] = {
85+
...this.translations[locale],
86+
...translations,
87+
};
88+
}
89+
}
90+
91+
// Create singleton instance
92+
const i18n = new I18n();
93+
94+
// Export both the instance and the class for flexibility
95+
export { i18n, I18n };
96+
export default i18n;
97+
98+
/**
99+
* Usage examples:
100+
*
101+
* // Direct locale setting (new preferred method)
102+
* i18n.setLocale('zh'); // Chinese
103+
* i18n.setLocale('en'); // English
104+
*
105+
* // Get translations
106+
* i18n.t('checking_update'); // Based on current locale
107+
* i18n.t('download_progress', { progress: 50 }); // With interpolation
108+
*/

src/locales/en.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
export default {
2+
// Common messages
3+
checking_update: 'Checking for updates...',
4+
downloading_update: 'Downloading update package...',
5+
installing_update: 'Installing update...',
6+
update_available: 'Update available',
7+
update_downloaded: 'Update downloaded successfully',
8+
update_installed: 'Update installed successfully',
9+
no_update_available: 'You are up to date',
10+
update_failed: 'Update failed',
11+
network_error: 'Network connection error',
12+
download_failed: 'Download failed',
13+
install_failed: 'Installation failed',
14+
15+
// Progress messages with interpolation
16+
download_progress: 'Download progress: {{progress}}%',
17+
download_speed: 'Download speed: {{speed}}/s',
18+
file_size: 'File size: {{size}}',
19+
time_remaining: 'Time remaining: {{time}}',
20+
21+
// Error messages
22+
error_code: 'Error code: {{code}}',
23+
error_message: 'Error message: {{message}}',
24+
retry_count: 'Retry attempt: {{count}}/{{max}}',
25+
26+
// Update info
27+
version_info: 'Version {{version}} ({{build}})',
28+
release_notes: 'Release notes: {{notes}}',
29+
update_size: 'Update size: {{size}}MB',
30+
31+
// Alert messages
32+
alert_title: 'Notice',
33+
alert_update_ready: 'Download completed. Update now?',
34+
alert_next_time: 'Later',
35+
alert_update_now: 'Update Now',
36+
alert_app_updated:
37+
'Your app version has been updated. Click update to download and install the new version',
38+
alert_update_button: 'Update',
39+
alert_cancel: 'Cancel',
40+
alert_confirm: 'OK',
41+
alert_info: 'Info',
42+
alert_no_update_wait:
43+
'No update found, please wait 10s for the server to generate the patch package',
44+
45+
// Error messages
46+
error_appkey_required: 'appKey is required',
47+
error_update_check_failed: 'Update check failed',
48+
error_cannot_connect_server:
49+
'Can not connect to update server. Please check your network.',
50+
error_cannot_connect_backup:
51+
'Can not connect to update server: {{message}}. Trying backup endpoints.',
52+
error_diff_failed: 'diff error: {{message}}',
53+
error_pdiff_failed: 'pdiff error: {{message}}',
54+
error_full_patch_failed: 'full patch error: {{message}}',
55+
error_all_promises_rejected: 'All promises were rejected',
56+
error_ping_failed: 'Ping failed',
57+
error_ping_timeout: 'Ping timeout',
58+
error_http_status: '{{status}} {{statusText}}',
59+
60+
// Development messages
61+
dev_debug_disabled:
62+
'You are currently in the development environment and have not enabled debug mode. {{matter}} will not be performed. If you need to debug {{matter}} in the development environment, please set debug to true in the client.',
63+
dev_log_prefix: 'react-native-update: ',
64+
dev_web_not_supported:
65+
'react-native-update does not support the Web platform and will not perform any operations',
66+
67+
// More alert messages
68+
alert_new_version_found:
69+
'New version {{name}} found. Download now?\n{{description}}',
70+
};

0 commit comments

Comments
 (0)