已合并
fix:I18nManager Optimization #1958
zheng-jun-feng创建于 2025年12月30日
fix:I18nManager Optimization #1958
已合并
共 2 个文件变更+92-12
| @@ -9,6 +9,8 @@ | |||
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | import NativeI18nManager from 'react-native/Libraries/ReactNative/NativeI18nManager'; | 11 | import NativeI18nManager from 'react-native/Libraries/ReactNative/NativeI18nManager'; |
| 12 | +import RCTDeviceEventEmitter from 'react-native/Libraries/EventEmitter/RCTDeviceEventEmitter'; | ||
| 13 | +import type {EventSubscription} from 'react-native/Libraries/vendor/emitter/EventEmitter'; | ||
| 12 | 14 | ||
| 13 | const i18nConstants: {| | 15 | const i18nConstants: {| |
| 14 | doLeftAndRightSwapInRTL: boolean, | 16 | doLeftAndRightSwapInRTL: boolean, |
| @@ -16,6 +18,12 @@ const i18nConstants: {| | |||
| 16 | localeIdentifier?: ?string, | 18 | localeIdentifier?: ?string, |
| 17 | |} = getI18nManagerConstants(); | 19 | |} = getI18nManagerConstants(); |
| 18 | 20 | ||
| 21 | +let harmonyI18nConstants: {| | ||
| 22 | + doLeftAndRightSwapInRTL: boolean, | ||
| 23 | + isRTL: boolean, | ||
| 24 | + localeIdentifier?: ?string, | ||
| 25 | +|} | null = null; | ||
| 26 | + | ||
| 19 | function getI18nManagerConstants() { | 27 | function getI18nManagerConstants() { |
| 20 | if (NativeI18nManager) { | 28 | if (NativeI18nManager) { |
| 21 | const {isRTL, doLeftAndRightSwapInRTL, localeIdentifier} = | 29 | const {isRTL, doLeftAndRightSwapInRTL, localeIdentifier} = |
| @@ -29,15 +37,46 @@ function getI18nManagerConstants() { | |||
| 29 | }; | 37 | }; |
| 30 | } | 38 | } |
| 31 | 39 | ||
| 40 | +function getHarmonyI18nManagerConstants() { | ||
| 41 | + if (harmonyI18nConstants == null) { | ||
| 42 | + harmonyI18nConstants = getI18nManagerConstants(); | ||
| 43 | + } | ||
| 44 | + return harmonyI18nConstants; | ||
| 45 | +} | ||
| 46 | + | ||
| 47 | +function invalidateHarmonyI18nConstantsCache() { | ||
| 48 | + harmonyI18nConstants = null; | ||
| 49 | +} | ||
| 50 | + | ||
| 51 | +let languageChangeListener: ?EventSubscription = null; | ||
| 52 | + | ||
| 53 | +function addLanguageListener() { | ||
| 54 | + languageChangeListener = RCTDeviceEventEmitter.addListener("i18nManagerLanguageChanged", (event) => { | ||
| 55 | + invalidateHarmonyI18nConstantsCache(); | ||
| 56 | + }); | ||
| 57 | +} | ||
| 58 | + | ||
| 59 | +function setupLanguageChangeListener() { | ||
| 60 | + if (!languageChangeListener) { | ||
| 61 | + try { | ||
| 62 | + if (RCTDeviceEventEmitter && typeof RCTDeviceEventEmitter.addListener === 'function') { | ||
| 63 | + addLanguageListener(); | ||
| 64 | + } | ||
| 65 | + } catch (error) { | ||
| 66 | + console.error('Failed to register listener:', error); | ||
| 67 | + } | ||
| 68 | + } | ||
| 69 | +} | ||
| 70 | + | ||
| 71 | +setupLanguageChangeListener(); | ||
| 72 | + | ||
| 32 | module.exports = { | 73 | module.exports = { |
| 33 | getConstants: (): {| | 74 | getConstants: (): {| |
| 34 | doLeftAndRightSwapInRTL: boolean, | 75 | doLeftAndRightSwapInRTL: boolean, |
| 35 | isRTL: boolean, | 76 | isRTL: boolean, |
| 36 | localeIdentifier: ?string, | 77 | localeIdentifier: ?string, |
| 37 | |} => { | 78 | |} => { |
| 38 | - // RNOH patch | 79 | + return getHarmonyI18nManagerConstants(); |
| 39 | - // return i18nConstants; | ||
| 40 | - return Platform.OS === "harmony" ? getI18nManagerConstants() : i18nConstants; | ||
| 41 | }, | 80 | }, |
| 42 | 81 | ||
| 43 | allowRTL: (shouldAllow: boolean) => { | 82 | allowRTL: (shouldAllow: boolean) => { |
| @@ -46,6 +85,7 @@ module.exports = { | |||
| 46 | } | 85 | } |
| 47 | 86 | ||
| 48 | NativeI18nManager.allowRTL(shouldAllow); | 87 | NativeI18nManager.allowRTL(shouldAllow); |
| 88 | + invalidateHarmonyI18nConstantsCache(); | ||
| 49 | }, | 89 | }, |
| 50 | 90 | ||
| 51 | forceRTL: (shouldForce: boolean) => { | 91 | forceRTL: (shouldForce: boolean) => { |
| @@ -54,6 +94,7 @@ module.exports = { | |||
| 54 | } | 94 | } |
| 55 | 95 | ||
| 56 | NativeI18nManager.forceRTL(shouldForce); | 96 | NativeI18nManager.forceRTL(shouldForce); |
| 97 | + invalidateHarmonyI18nConstantsCache(); | ||
| 57 | }, | 98 | }, |
| 58 | 99 | ||
| 59 | swapLeftAndRightInRTL: (flipStyles: boolean) => { | 100 | swapLeftAndRightInRTL: (flipStyles: boolean) => { |
| @@ -62,17 +103,14 @@ module.exports = { | |||
| 62 | } | 103 | } |
| 63 | 104 | ||
| 64 | NativeI18nManager.swapLeftAndRightInRTL(flipStyles); | 105 | NativeI18nManager.swapLeftAndRightInRTL(flipStyles); |
| 106 | + invalidateHarmonyI18nConstantsCache(); | ||
| 65 | }, | 107 | }, |
| 66 | 108 | ||
| 67 | - // RNOH patch | ||
| 68 | get isRTL() { | 109 | get isRTL() { |
| 69 | - return Platform.OS === "harmony" ? getI18nManagerConstants().isRTL : i18nConstants.isRTL; | 110 | + return getHarmonyI18nManagerConstants().isRTL; |
| 70 | }, | 111 | }, |
| 71 | - // isRTL: i18nConstants.isRTL, | ||
| 72 | 112 | ||
| 73 | - // RNOH patch | ||
| 74 | get doLeftAndRightSwapInRTL() { | 113 | get doLeftAndRightSwapInRTL() { |
| 75 | - return Platform.OS === "harmony" ? getI18nManagerConstants().doLeftAndRightSwapInRTL : i18nConstants.doLeftAndRightSwapInRTL; | 114 | + return getHarmonyI18nManagerConstants().doLeftAndRightSwapInRTL; |
| 76 | }, | 115 | }, |
| 77 | - // doLeftAndRightSwapInRTL: i18nConstants.doLeftAndRightSwapInRTL, | ||
| 78 | }; | 116 | }; |
| @@ -5,6 +5,7 @@ | |||
| 5 | * LICENSE-MIT file in the root directory of this source tree. | 5 | * LICENSE-MIT file in the root directory of this source tree. |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | +import type { TurboModuleContext } from '../../RNOH/TurboModule'; | ||
| 8 | import I18n from '@ohos.i18n'; | 9 | import I18n from '@ohos.i18n'; |
| 9 | import { TurboModule } from "../../RNOH/TurboModule"; | 10 | import { TurboModule } from "../../RNOH/TurboModule"; |
| 10 | 11 | ||
| @@ -13,16 +14,50 @@ export class I18nManagerTurboModule extends TurboModule { | |||
| 13 | 14 | ||
| 14 | private RTLAllowed = true; | 15 | private RTLAllowed = true; |
| 15 | private RTLForced = false; | 16 | private RTLForced = false; |
| 17 | + private lastLanguage: string | null = null; | ||
| 18 | + private cleanUpCallbacks: (() => void)[] = []; | ||
| 19 | + | ||
| 20 | + constructor(protected ctx: TurboModuleContext) { | ||
| 21 | + super(ctx); | ||
| 22 | + this.lastLanguage = this.ctx.uiAbilityContext.config.language; | ||
| 23 | + this.subscribeToLanguageChanges(); | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | + private subscribeToLanguageChanges() { | ||
| 27 | + // Monitor for configuration update events and detect language changes. | ||
| 28 | + const onConfigurationUpdate = (newConfig: any) => { | ||
| 29 | + const newLanguage = newConfig?.language || this.ctx.uiAbilityContext.config.language; | ||
| 30 | + | ||
| 31 | + if (this.lastLanguage !== newLanguage) { | ||
| 32 | + this.lastLanguage = newLanguage; | ||
| 33 | + const newIsRTL = this.RTLForced || (this.RTLAllowed && I18n.isRTL(newLanguage)); | ||
| 34 | + const eventPayload = { | ||
| 35 | + localeIdentifier: newLanguage, | ||
| 36 | + isRTL: newIsRTL | ||
| 37 | + }; | ||
| 38 | + this.ctx.rnInstance.emitDeviceEvent("i18nManagerLanguageChanged", eventPayload); | ||
| 39 | + this.ctx.rnInstance.updateRTL(newIsRTL); | ||
| 40 | + } | ||
| 41 | + }; | ||
| 42 | + | ||
| 43 | + this.cleanUpCallbacks.push( | ||
| 44 | + this.ctx.rnInstance.subscribeToLifecycleEvents("CONFIGURATION_UPDATE", onConfigurationUpdate) | ||
| 45 | + ); | ||
| 46 | + } | ||
| 16 | 47 | ||
| 17 | get isRTL() { | 48 | get isRTL() { |
| 18 | - return this.RTLForced || (this.RTLAllowed && I18n.isRTL(this.ctx.uiAbilityContext.config.language)); | 49 | + const currentLanguage = this.lastLanguage || this.ctx.uiAbilityContext.config.language; |
| 50 | + return this.RTLForced || (this.RTLAllowed && I18n.isRTL(currentLanguage)); | ||
| 19 | } | 51 | } |
| 20 | 52 | ||
| 21 | getConstants() { | 53 | getConstants() { |
| 54 | + const currentLanguage = this.lastLanguage || this.ctx.uiAbilityContext.config.language; | ||
| 55 | + const currentIsRTL = this.RTLForced || (this.RTLAllowed && I18n.isRTL(currentLanguage)); | ||
| 56 | + | ||
| 22 | return { | 57 | return { |
| 23 | - isRTL: this.isRTL, | 58 | + isRTL: currentIsRTL, |
| 24 | doLeftAndRightSwapInRTL: true, | 59 | doLeftAndRightSwapInRTL: true, |
| 25 | - localeIdentifier: this.ctx.uiAbilityContext.config.language | 60 | + localeIdentifier: currentLanguage |
| 26 | }; | 61 | }; |
| 27 | } | 62 | } |
| 28 | 63 | ||
| @@ -35,4 +70,11 @@ export class I18nManagerTurboModule extends TurboModule { | |||
| 35 | this.RTLForced = force; | 70 | this.RTLForced = force; |
| 36 | this.ctx.rnInstance.updateRTL(this.isRTL); | 71 | this.ctx.rnInstance.updateRTL(this.isRTL); |
| 37 | } | 72 | } |
| 73 | + | ||
| 74 | + __onDestroy__() { | ||
| 75 | + super.__onDestroy__(); | ||
| 76 | + this.cleanUpCallbacks.forEach(cb => cb()); | ||
| 77 | + this.cleanUpCallbacks = []; | ||
| 78 | + } | ||
| 38 | } | 79 | } |
| 80 | + | ||