Przeglądaj źródła

feat(sounds) use audio files based on locale (#14104)

factor2
Mihaela Dumitru 1 rok temu
rodzic
commit
8504b4b5bb
No account linked to committer's email address

+ 16
- 3
react/features/base/media/components/native/Audio.ts Wyświetl plik

1
 import Sound from 'react-native-sound';
1
 import Sound from 'react-native-sound';
2
 
2
 
3
 import logger from '../../logger';
3
 import logger from '../../logger';
4
-import AbstractAudio from '../AbstractAudio';
4
+import AbstractAudio, { IProps } from '../AbstractAudio';
5
 
5
 
6
 /**
6
 /**
7
  * The React Native/mobile {@link Component} which is similar to Web's
7
  * The React Native/mobile {@link Component} which is similar to Web's
31
         }
31
         }
32
     }
32
     }
33
 
33
 
34
+    /**
35
+     * Implements React's {@link Component#componentDidUpdate()}.
36
+     *
37
+     * @inheritdoc
38
+     */
39
+    async componentDidUpdate(prevProps: IProps): Promise<void> {
40
+        // source is different !! call didunmount and call didmount
41
+        if (prevProps.src !== this.props.src) {
42
+            await this.componentWillUnmount();
43
+            await this.componentDidMount();
44
+        }
45
+    }
46
+
34
     /**
47
     /**
35
      * Will load the sound, after the component did mount.
48
      * Will load the sound, after the component did mount.
36
      *
49
      *
37
      * @returns {void}
50
      * @returns {void}
38
      */
51
      */
39
-    componentDidMount() {
52
+    async componentDidMount() {
40
         this._sound
53
         this._sound
41
             = this.props.src
54
             = this.props.src
42
                 ? new Sound(
55
                 ? new Sound(
50
      *
63
      *
51
      * @returns {void}
64
      * @returns {void}
52
      */
65
      */
53
-    componentWillUnmount() {
66
+    async componentWillUnmount() {
54
         if (this._sound) {
67
         if (this._sound) {
55
             this._sound.release();
68
             this._sound.release();
56
             this._sound = null;
69
             this._sound = null;

+ 9
- 0
react/features/base/media/constants.ts Wyświetl plik

38
     USER: 1 << 2
38
     USER: 1 << 2
39
 };
39
 };
40
 
40
 
41
+/**
42
+ * The languages supported for audio files.
43
+ */
44
+export enum AudioSupportedLanguage {
45
+    en = 'en',
46
+    fr = 'fr',
47
+    frCA = 'frCA'
48
+}
49
+
41
 /**
50
 /**
42
  * The types of authorities which may mute/unmute the local video.
51
  * The types of authorities which may mute/unmute the local video.
43
  *
52
  *

+ 18
- 1
react/features/base/media/functions.ts Wyświetl plik

2
 import { toState } from '../redux/functions';
2
 import { toState } from '../redux/functions';
3
 import { getPropertyValue } from '../settings/functions';
3
 import { getPropertyValue } from '../settings/functions';
4
 
4
 
5
-import { VIDEO_MUTISM_AUTHORITY } from './constants';
5
+import { AudioSupportedLanguage, VIDEO_MUTISM_AUTHORITY } from './constants';
6
 
6
 
7
 
7
 
8
 // XXX The configurations/preferences/settings startWithAudioMuted and startWithVideoMuted were introduced for
8
 // XXX The configurations/preferences/settings startWithAudioMuted and startWithVideoMuted were introduced for
127
             && !videoTrack.muted
127
             && !videoTrack.muted
128
             && (!waitForVideoStarted || videoTrack.videoStarted));
128
             && (!waitForVideoStarted || videoTrack.videoStarted));
129
 }
129
 }
130
+
131
+/**
132
+ * Computes the localized sound file source.
133
+ *
134
+ * @param {string} file - The default file source.
135
+ * @param {string} language - The language to use for localization.
136
+ * @returns {string}
137
+ */
138
+export const getSoundFileSrc = (file: string, language: string): string => {
139
+    if (!AudioSupportedLanguage[language as keyof typeof AudioSupportedLanguage]
140
+        || language === AudioSupportedLanguage.en) {
141
+        return file;
142
+    }
143
+    const fileTokens = file.split('.');
144
+
145
+    return `${fileTokens[0]}_${language}.${fileTokens[1]}`;
146
+};

+ 56
- 0
react/features/base/sounds/middleware.any.ts Wyświetl plik

1
+import i18next from 'i18next';
2
+
3
+import { registerE2eeAudioFiles } from '../../../features/e2ee/functions';
4
+import { registerRecordingAudioFiles } from '../../../features/recording/functions';
1
 import { IStore } from '../../app/types';
5
 import { IStore } from '../../app/types';
6
+import { AudioSupportedLanguage } from '../media/constants';
2
 import MiddlewareRegistry from '../redux/MiddlewareRegistry';
7
 import MiddlewareRegistry from '../redux/MiddlewareRegistry';
8
+import StateListenerRegistry from '../redux/StateListenerRegistry';
3
 
9
 
4
 import { PLAY_SOUND, STOP_SOUND } from './actionTypes';
10
 import { PLAY_SOUND, STOP_SOUND } from './actionTypes';
5
 import logger from './logger';
11
 import logger from './logger';
71
         logger.warn(`STOP_SOUND: no sound found for id: ${soundId}`);
77
         logger.warn(`STOP_SOUND: no sound found for id: ${soundId}`);
72
     }
78
     }
73
 }
79
 }
80
+
81
+/**
82
+ * Returns whether the language is supported for audio messages.
83
+ *
84
+ * @param {string} language - The requested language.
85
+ * @returns {boolean}
86
+ */
87
+function isLanguageSupported(language: string): Boolean {
88
+    return Boolean(AudioSupportedLanguage[language as keyof typeof AudioSupportedLanguage]);
89
+}
90
+
91
+/**
92
+ * Checking if it's necessary to reload the translated files.
93
+ *
94
+ * @param {string} language - The next language.
95
+ * @param {string} prevLanguage - The previous language.
96
+ * @returns {boolean}
97
+ */
98
+function shouldReloadAudioFiles(language: string, prevLanguage: string): Boolean {
99
+    const isNextLanguageSupported = isLanguageSupported(language);
100
+    const isPrevLanguageSupported = isLanguageSupported(prevLanguage);
101
+
102
+    return (
103
+
104
+        // From an unsupported language (which defaulted to English) to a supported language (that isn't English).
105
+        isNextLanguageSupported && language !== AudioSupportedLanguage.en && !isPrevLanguageSupported
106
+    ) || (
107
+
108
+        // From a supported language (that wasn't English) to English.
109
+        !isNextLanguageSupported && isPrevLanguageSupported && prevLanguage !== AudioSupportedLanguage.en
110
+    ) || (
111
+
112
+        // From a supported language to another.
113
+        isNextLanguageSupported && isPrevLanguageSupported
114
+    );
115
+}
116
+
117
+/**
118
+ * Set up state change listener for language.
119
+ */
120
+StateListenerRegistry.register(
121
+    () => i18next.language,
122
+    (language, { dispatch }, prevLanguage): void => {
123
+
124
+        if (language !== prevLanguage && shouldReloadAudioFiles(language, prevLanguage)) {
125
+            registerE2eeAudioFiles(dispatch, true);
126
+            registerRecordingAudioFiles(dispatch, true);
127
+        }
128
+    }
129
+);

+ 47
- 2
react/features/e2ee/functions.ts Wyświetl plik

1
-import { IReduxState } from '../app/types';
1
+import i18next from 'i18next';
2
+
3
+import { IReduxState, IStore } from '../app/types';
2
 import { IStateful } from '../base/app/types';
4
 import { IStateful } from '../base/app/types';
5
+import { getSoundFileSrc } from '../base/media/functions';
3
 import { getParticipantById, getParticipantCount, getParticipantCountWithFake } from '../base/participants/functions';
6
 import { getParticipantById, getParticipantCount, getParticipantCountWithFake } from '../base/participants/functions';
4
 import { toState } from '../base/redux/functions';
7
 import { toState } from '../base/redux/functions';
8
+import { registerSound, unregisterSound } from '../base/sounds/actions';
5
 
9
 
10
+import {
11
+    E2EE_OFF_SOUND_ID,
12
+    E2EE_ON_SOUND_ID,
13
+    MAX_MODE_LIMIT,
14
+    MAX_MODE_THRESHOLD
15
+} from './constants';
16
+import {
17
+    E2EE_OFF_SOUND_FILE,
18
+    E2EE_ON_SOUND_FILE
19
+} from './sounds';
6
 
20
 
7
-import { MAX_MODE_LIMIT, MAX_MODE_THRESHOLD } from './constants';
8
 
21
 
9
 /**
22
 /**
10
  * Gets the value of a specific React {@code Component} prop of the currently
23
  * Gets the value of a specific React {@code Component} prop of the currently
73
         && participant?.e2eeVerificationAvailable
86
         && participant?.e2eeVerificationAvailable
74
         && participant?.e2eeVerified === undefined);
87
         && participant?.e2eeVerified === undefined);
75
 }
88
 }
89
+
90
+/**
91
+ * Unregisters the audio files based on locale.
92
+ *
93
+ * @param {Dispatch<any>} dispatch - The redux dispatch function.
94
+ * @returns {void}
95
+ */
96
+export function unregisterE2eeAudioFiles(dispatch: IStore['dispatch']) {
97
+    dispatch(unregisterSound(E2EE_OFF_SOUND_ID));
98
+    dispatch(unregisterSound(E2EE_ON_SOUND_ID));
99
+}
100
+
101
+/**
102
+ * Registers the audio files based on locale.
103
+ *
104
+ * @param {Dispatch<any>} dispatch - The redux dispatch function.
105
+ * @param {boolean|undefined} shouldUnregister - Whether the sounds should be unregistered.
106
+ * @returns {void}
107
+ */
108
+export function registerE2eeAudioFiles(dispatch: IStore['dispatch'], shouldUnregister?: boolean) {
109
+    const language = i18next.language;
110
+
111
+    shouldUnregister && unregisterE2eeAudioFiles(dispatch);
112
+
113
+    dispatch(registerSound(
114
+        E2EE_OFF_SOUND_ID,
115
+        getSoundFileSrc(E2EE_OFF_SOUND_FILE, language)));
116
+
117
+    dispatch(registerSound(
118
+        E2EE_ON_SOUND_ID,
119
+        getSoundFileSrc(E2EE_ON_SOUND_FILE, language)));
120
+}

+ 9
- 14
react/features/e2ee/middleware.ts Wyświetl plik

1
-
2
 import { IStore } from '../app/types';
1
 import { IStore } from '../app/types';
3
 import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app/actionTypes';
2
 import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app/actionTypes';
4
 import { CONFERENCE_JOINED } from '../base/conference/actionTypes';
3
 import { CONFERENCE_JOINED } from '../base/conference/actionTypes';
14
 } from '../base/participants/functions';
13
 } from '../base/participants/functions';
15
 import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
14
 import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
16
 import StateListenerRegistry from '../base/redux/StateListenerRegistry';
15
 import StateListenerRegistry from '../base/redux/StateListenerRegistry';
17
-import { playSound, registerSound, unregisterSound } from '../base/sounds/actions';
16
+import { playSound } from '../base/sounds/actions';
18
 
17
 
19
 import { PARTICIPANT_VERIFIED, SET_MEDIA_ENCRYPTION_KEY, START_VERIFICATION, TOGGLE_E2EE } from './actionTypes';
18
 import { PARTICIPANT_VERIFIED, SET_MEDIA_ENCRYPTION_KEY, START_VERIFICATION, TOGGLE_E2EE } from './actionTypes';
20
 import { setE2EEMaxMode, toggleE2EE } from './actions';
19
 import { setE2EEMaxMode, toggleE2EE } from './actions';
21
 import ParticipantVerificationDialog from './components/ParticipantVerificationDialog';
20
 import ParticipantVerificationDialog from './components/ParticipantVerificationDialog';
22
 import { E2EE_OFF_SOUND_ID, E2EE_ON_SOUND_ID, MAX_MODE } from './constants';
21
 import { E2EE_OFF_SOUND_ID, E2EE_ON_SOUND_ID, MAX_MODE } from './constants';
23
-import { isMaxModeReached, isMaxModeThresholdReached } from './functions';
22
+import {
23
+    isMaxModeReached,
24
+    isMaxModeThresholdReached,
25
+    registerE2eeAudioFiles,
26
+    unregisterE2eeAudioFiles
27
+} from './functions';
24
 import logger from './logger';
28
 import logger from './logger';
25
-import { E2EE_OFF_SOUND_FILE, E2EE_ON_SOUND_FILE } from './sounds';
26
-
27
 
29
 
28
 /**
30
 /**
29
  * Middleware that captures actions related to E2EE.
31
  * Middleware that captures actions related to E2EE.
36
 
38
 
37
     switch (action.type) {
39
     switch (action.type) {
38
     case APP_WILL_MOUNT:
40
     case APP_WILL_MOUNT:
39
-        dispatch(registerSound(
40
-            E2EE_OFF_SOUND_ID,
41
-            E2EE_OFF_SOUND_FILE));
42
-
43
-        dispatch(registerSound(
44
-            E2EE_ON_SOUND_ID,
45
-            E2EE_ON_SOUND_FILE));
41
+        registerE2eeAudioFiles(dispatch);
46
         break;
42
         break;
47
 
43
 
48
     case APP_WILL_UNMOUNT:
44
     case APP_WILL_UNMOUNT:
49
-        dispatch(unregisterSound(E2EE_OFF_SOUND_ID));
50
-        dispatch(unregisterSound(E2EE_ON_SOUND_ID));
45
+        unregisterE2eeAudioFiles(dispatch);
51
         break;
46
         break;
52
 
47
 
53
     case CONFERENCE_JOINED:
48
     case CONFERENCE_JOINED:

+ 63
- 2
react/features/recording/functions.ts Wyświetl plik

1
-import { IReduxState } from '../app/types';
1
+import i18next from 'i18next';
2
+
3
+import { IReduxState, IStore } from '../app/types';
2
 import { isMobileBrowser } from '../base/environment/utils';
4
 import { isMobileBrowser } from '../base/environment/utils';
3
 import { isJwtFeatureEnabled } from '../base/jwt/functions';
5
 import { isJwtFeatureEnabled } from '../base/jwt/functions';
4
 import { JitsiRecordingConstants, browser } from '../base/lib-jitsi-meet';
6
 import { JitsiRecordingConstants, browser } from '../base/lib-jitsi-meet';
7
+import { getSoundFileSrc } from '../base/media/functions';
5
 import {
8
 import {
6
     getLocalParticipant,
9
     getLocalParticipant,
7
     getRemoteParticipants,
10
     getRemoteParticipants,
8
     isLocalParticipantModerator
11
     isLocalParticipantModerator
9
 } from '../base/participants/functions';
12
 } from '../base/participants/functions';
13
+import { registerSound, unregisterSound } from '../base/sounds/actions';
10
 import { isInBreakoutRoom } from '../breakout-rooms/functions';
14
 import { isInBreakoutRoom } from '../breakout-rooms/functions';
11
 import { isEnabled as isDropboxEnabled } from '../dropbox/functions';
15
 import { isEnabled as isDropboxEnabled } from '../dropbox/functions';
12
 import { extractFqnFromPath } from '../dynamic-branding/functions.any';
16
 import { extractFqnFromPath } from '../dynamic-branding/functions.any';
13
 
17
 
14
 import LocalRecordingManager from './components/Recording/LocalRecordingManager';
18
 import LocalRecordingManager from './components/Recording/LocalRecordingManager';
15
-import { RECORDING_STATUS_PRIORITIES, RECORDING_TYPES } from './constants';
19
+import {
20
+    LIVE_STREAMING_OFF_SOUND_ID,
21
+    LIVE_STREAMING_ON_SOUND_ID,
22
+    RECORDING_OFF_SOUND_ID,
23
+    RECORDING_ON_SOUND_ID,
24
+    RECORDING_STATUS_PRIORITIES,
25
+    RECORDING_TYPES
26
+} from './constants';
16
 import logger from './logger';
27
 import logger from './logger';
28
+import {
29
+    LIVE_STREAMING_OFF_SOUND_FILE,
30
+    LIVE_STREAMING_ON_SOUND_FILE,
31
+    RECORDING_OFF_SOUND_FILE,
32
+    RECORDING_ON_SOUND_FILE
33
+} from './sounds';
17
 
34
 
18
 /**
35
 /**
19
  * Searches in the passed in redux state for an active recording session of the
36
  * Searches in the passed in redux state for an active recording session of the
278
 
295
 
279
     return false;
296
     return false;
280
 }
297
 }
298
+
299
+/**
300
+ * Unregisters the audio files based on locale.
301
+ *
302
+ * @param {Dispatch<any>} dispatch - The redux dispatch function.
303
+ * @returns {void}
304
+ */
305
+export function unregisterRecordingAudioFiles(dispatch: IStore['dispatch']) {
306
+    dispatch(unregisterSound(LIVE_STREAMING_OFF_SOUND_FILE));
307
+    dispatch(unregisterSound(LIVE_STREAMING_ON_SOUND_FILE));
308
+    dispatch(unregisterSound(RECORDING_OFF_SOUND_FILE));
309
+    dispatch(unregisterSound(RECORDING_ON_SOUND_FILE));
310
+}
311
+
312
+/**
313
+ * Registers the audio files based on locale.
314
+ *
315
+ * @param {Dispatch<any>} dispatch - The redux dispatch function.
316
+ * @param {boolean|undefined} shouldUnregister - Whether the sounds should be unregistered.
317
+ * @returns {void}
318
+ */
319
+export function registerRecordingAudioFiles(dispatch: IStore['dispatch'], shouldUnregister?: boolean) {
320
+    const language = i18next.language;
321
+
322
+    if (shouldUnregister) {
323
+        unregisterRecordingAudioFiles(dispatch);
324
+    }
325
+
326
+    dispatch(registerSound(
327
+        LIVE_STREAMING_OFF_SOUND_ID,
328
+        getSoundFileSrc(LIVE_STREAMING_OFF_SOUND_FILE, language)));
329
+
330
+    dispatch(registerSound(
331
+        LIVE_STREAMING_ON_SOUND_ID,
332
+        getSoundFileSrc(LIVE_STREAMING_ON_SOUND_FILE, language)));
333
+
334
+    dispatch(registerSound(
335
+        RECORDING_OFF_SOUND_ID,
336
+        getSoundFileSrc(RECORDING_OFF_SOUND_FILE, language)));
337
+
338
+    dispatch(registerSound(
339
+        RECORDING_ON_SOUND_ID,
340
+        getSoundFileSrc(RECORDING_ON_SOUND_FILE, language)));
341
+}

+ 6
- 29
react/features/recording/middleware.ts Wyświetl plik

15
 import StateListenerRegistry from '../base/redux/StateListenerRegistry';
15
 import StateListenerRegistry from '../base/redux/StateListenerRegistry';
16
 import {
16
 import {
17
     playSound,
17
     playSound,
18
-    registerSound,
19
-    stopSound,
20
-    unregisterSound
18
+    stopSound
21
 } from '../base/sounds/actions';
19
 } from '../base/sounds/actions';
22
 import { TRACK_ADDED } from '../base/tracks/actionTypes';
20
 import { TRACK_ADDED } from '../base/tracks/actionTypes';
23
 import { showErrorNotification, showNotification } from '../notifications/actions';
21
 import { showErrorNotification, showNotification } from '../notifications/actions';
44
 } from './constants';
42
 } from './constants';
45
 import {
43
 import {
46
     getResourceId,
44
     getResourceId,
47
-    getSessionById
45
+    getSessionById,
46
+    registerRecordingAudioFiles,
47
+    unregisterRecordingAudioFiles
48
 } from './functions';
48
 } from './functions';
49
 import logger from './logger';
49
 import logger from './logger';
50
-import {
51
-    LIVE_STREAMING_OFF_SOUND_FILE,
52
-    LIVE_STREAMING_ON_SOUND_FILE,
53
-    RECORDING_OFF_SOUND_FILE,
54
-    RECORDING_ON_SOUND_FILE
55
-} from './sounds';
56
 
50
 
57
 /**
51
 /**
58
  * StateListenerRegistry provides a reliable way to detect the leaving of a
52
  * StateListenerRegistry provides a reliable way to detect the leaving of a
85
 
79
 
86
     switch (action.type) {
80
     switch (action.type) {
87
     case APP_WILL_MOUNT:
81
     case APP_WILL_MOUNT:
88
-        dispatch(registerSound(
89
-            LIVE_STREAMING_OFF_SOUND_ID,
90
-            LIVE_STREAMING_OFF_SOUND_FILE));
91
-
92
-        dispatch(registerSound(
93
-            LIVE_STREAMING_ON_SOUND_ID,
94
-            LIVE_STREAMING_ON_SOUND_FILE));
95
-
96
-        dispatch(registerSound(
97
-            RECORDING_OFF_SOUND_ID,
98
-            RECORDING_OFF_SOUND_FILE));
99
-
100
-        dispatch(registerSound(
101
-            RECORDING_ON_SOUND_ID,
102
-            RECORDING_ON_SOUND_FILE));
82
+        registerRecordingAudioFiles(dispatch);
103
 
83
 
104
         break;
84
         break;
105
 
85
 
106
     case APP_WILL_UNMOUNT:
86
     case APP_WILL_UNMOUNT:
107
-        dispatch(unregisterSound(LIVE_STREAMING_OFF_SOUND_ID));
108
-        dispatch(unregisterSound(LIVE_STREAMING_ON_SOUND_ID));
109
-        dispatch(unregisterSound(RECORDING_OFF_SOUND_ID));
110
-        dispatch(unregisterSound(RECORDING_ON_SOUND_ID));
87
+        unregisterRecordingAudioFiles(dispatch);
111
 
88
 
112
         break;
89
         break;
113
 
90
 

BIN
sounds/e2eeOff_fr.mp3 Wyświetl plik


BIN
sounds/e2eeOff_fr.opus Wyświetl plik


BIN
sounds/e2eeOff_frCA.mp3 Wyświetl plik


BIN
sounds/e2eeOff_frCA.opus Wyświetl plik


BIN
sounds/e2eeOn_fr.mp3 Wyświetl plik


BIN
sounds/e2eeOn_fr.opus Wyświetl plik


BIN
sounds/e2eeOn_frCA.mp3 Wyświetl plik


BIN
sounds/e2eeOn_frCA.opus Wyświetl plik


BIN
sounds/liveStreamingOff_fr.mp3 Wyświetl plik


BIN
sounds/liveStreamingOff_fr.opus Wyświetl plik


BIN
sounds/liveStreamingOff_frCA.mp3 Wyświetl plik


BIN
sounds/liveStreamingOff_frCA.opus Wyświetl plik


BIN
sounds/liveStreamingOn_fr.mp3 Wyświetl plik


BIN
sounds/liveStreamingOn_fr.opus Wyświetl plik


BIN
sounds/liveStreamingOn_frCA.mp3 Wyświetl plik


BIN
sounds/liveStreamingOn_frCA.opus Wyświetl plik


BIN
sounds/recordingOff_fr.mp3 Wyświetl plik


BIN
sounds/recordingOff_fr.opus Wyświetl plik


BIN
sounds/recordingOff_frCA.mp3 Wyświetl plik


BIN
sounds/recordingOff_frCA.opus Wyświetl plik


BIN
sounds/recordingOn_fr.mp3 Wyświetl plik


BIN
sounds/recordingOn_fr.opus Wyświetl plik


BIN
sounds/recordingOn_frCA.mp3 Wyświetl plik


BIN
sounds/recordingOn_frCA.opus Wyświetl plik


Ładowanie…
Anuluj
Zapisz