diff --git a/app/i18n/index.js b/app/i18n/index.js index ae4846ee6..6ac163a0d 100644 --- a/app/i18n/index.js +++ b/app/i18n/index.js @@ -1,66 +1,71 @@ import i18n from 'i18n-js'; import { I18nManager } from 'react-native'; import * as RNLocalize from 'react-native-localize'; +import moment from 'moment'; +import 'moment/min/locales'; -export * from './isRTL'; +import { toMomentLocale } from '../utils/moment'; +import { isRTL } from './isRTL'; + +export { isRTL }; export const LANGUAGES = [ { label: 'English', value: 'en', - file: require('./locales/en.json') + file: () => require('./locales/en.json') }, { label: '简体中文', value: 'zh-CN', - file: require('./locales/zh-CN.json') + file: () => require('./locales/zh-CN.json') }, { label: '繁體中文', value: 'zh-TW', - file: require('./locales/zh-TW.json') + file: () => require('./locales/zh-TW.json') }, { label: 'Deutsch', value: 'de', - file: require('./locales/de.json') + file: () => require('./locales/de.json') }, { label: 'Español (ES)', value: 'es-ES', - file: require('./locales/es-ES.json') + file: () => require('./locales/es-ES.json') }, { label: 'Français', value: 'fr', - file: require('./locales/fr.json') + file: () => require('./locales/fr.json') }, { label: 'Português (BR)', value: 'pt-BR', - file: require('./locales/pt-BR.json') + file: () => require('./locales/pt-BR.json') }, { label: 'Português (PT)', value: 'pt-PT', - file: require('./locales/pt-PT.json') + file: () => require('./locales/pt-PT.json') }, { label: 'Russian', value: 'ru', - file: require('./locales/ru.json') + file: () => require('./locales/ru.json') }, { label: 'Nederlands', value: 'nl', - file: require('./locales/nl.json') + file: () => require('./locales/nl.json') }, { label: 'Italiano', value: 'it', - file: require('./locales/it.json') + file: () => require('./locales/it.json') }, { label: '日本語', value: 'ja', - file: require('./locales/ja.json') + file: () => require('./locales/ja.json') }, { label: 'العربية', value: 'ar', - file: require('./locales/ar.json') + file: () => require('./locales/ar.json') }, { label: 'Türkçe', value: 'tr', - file: require('./locales/tr.json') + file: () => require('./locales/tr.json') } ]; @@ -69,16 +74,29 @@ const translations = LANGUAGES.reduce((ret, item) => { return ret; }, {}); -i18n.translations = translations; -i18n.fallbacks = true; +export const setLanguage = (l) => { + if (!l) { + return; + } + // server uses lowercase pattern (pt-br), but we're forced to use standard pattern (pt-BR) + const locale = LANGUAGES.find(ll => ll.value.toLowerCase() === l.toLowerCase())?.value; + // don't go forward if it's the same language and default language (en) was setup already + if (i18n.locale === locale && i18n.translations?.en) { + return; + } + i18n.locale = locale; + i18n.translations = { ...i18n.translations, [locale]: translations[locale]() }; + I18nManager.forceRTL(isRTL(locale)); + I18nManager.swapLeftAndRightInRTL(isRTL(locale)); + i18n.isRTL = I18nManager.isRTL; + moment.locale(toMomentLocale(locale)); +}; const defaultLanguage = { languageTag: 'en', isRTL: false }; -const availableLanguages = Object.keys(i18n.translations); -const { languageTag, isRTL } = RNLocalize.findBestAvailableLanguage(availableLanguages) || defaultLanguage; +const availableLanguages = Object.keys(translations); +const { languageTag } = RNLocalize.findBestAvailableLanguage(availableLanguages) || defaultLanguage; -I18nManager.forceRTL(isRTL); -I18nManager.swapLeftAndRightInRTL(isRTL); -i18n.locale = languageTag; -i18n.isRTL = I18nManager.isRTL; +setLanguage(languageTag); +i18n.fallbacks = true; export default i18n; diff --git a/app/sagas/login.js b/app/sagas/login.js index 7673e9a6f..77eda7611 100644 --- a/app/sagas/login.js +++ b/app/sagas/login.js @@ -2,11 +2,7 @@ import { put, call, takeLatest, select, take, fork, cancel, race, delay } from 'redux-saga/effects'; import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord'; -import moment from 'moment'; -import 'moment/min/locales'; import { Q } from '@nozbe/watermelondb'; -import { I18nManager } from 'react-native'; - import * as types from '../actions/actionsTypes'; import { appStart, ROOT_SET_USERNAME, ROOT_INSIDE, ROOT_LOADING, ROOT_OUTSIDE @@ -16,10 +12,9 @@ import { loginFailure, loginSuccess, setUser, logout } from '../actions/login'; import { roomsRequest } from '../actions/rooms'; -import { toMomentLocale } from '../utils/moment'; import RocketChat from '../lib/rocketchat'; import log, { logEvent, events } from '../utils/log'; -import I18n, { LANGUAGES, isRTL } from '../i18n'; +import I18n, { setLanguage } from '../i18n'; import database from '../lib/database'; import EventEmitter from '../utils/events'; import { inviteLinksRequest } from '../actions/inviteLinks'; @@ -140,8 +135,7 @@ const handleLoginSuccess = function* handleLoginSuccess({ user }) { yield fork(fetchEnterpriseModules, { user }); yield put(encryptionInit()); - I18n.locale = user.language; - moment.locale(toMomentLocale(user.language)); + setLanguage(user?.language); const serversDB = database.servers; const usersCollection = serversDB.get('users'); @@ -246,13 +240,7 @@ const handleLogout = function* handleLogout({ forcedByServer }) { }; const handleSetUser = function* handleSetUser({ user }) { - if (user && user.language) { - const locale = LANGUAGES.find(l => l.value.toLowerCase() === user.language)?.value || user.language; - I18n.locale = locale; - I18nManager.forceRTL(isRTL(locale)); - I18nManager.swapLeftAndRightInRTL(isRTL(locale)); - moment.locale(toMomentLocale(locale)); - } + setLanguage(user?.language); if (user && user.status) { const userId = yield select(state => state.login.user.id);