Remove access to global state from i18n/i18n (#26750)

Этот коммит содержится в:
Harrison Healey
2024-04-22 13:32:55 -04:00
коммит произвёл GitHub
родитель f3b80f77a6
Коммит b091ef5686
8 изменённых файлов: 62 добавлений и 27 удалений

Просмотреть файл

@@ -7,6 +7,7 @@ import type {Dispatch} from 'redux';
import timezones from 'timezones.json'; import timezones from 'timezones.json';
import {CollapsedThreads} from '@mattermost/types/config'; import {CollapsedThreads} from '@mattermost/types/config';
import type {UserProfile} from '@mattermost/types/users';
import {savePreferences} from 'mattermost-redux/actions/preferences'; import {savePreferences} from 'mattermost-redux/actions/preferences';
import {autoUpdateTimezone} from 'mattermost-redux/actions/timezone'; import {autoUpdateTimezone} from 'mattermost-redux/actions/timezone';
@@ -17,14 +18,19 @@ import {getCurrentTimezoneFull, getCurrentTimezoneLabel} from 'mattermost-redux/
import {getCurrentUserId, getUser} from 'mattermost-redux/selectors/entities/users'; import {getCurrentUserId, getUser} from 'mattermost-redux/selectors/entities/users';
import {getUserCurrentTimezone} from 'mattermost-redux/utils/timezone_utils'; import {getUserCurrentTimezone} from 'mattermost-redux/utils/timezone_utils';
import {getLanguages, isLanguageAvailable} from 'i18n/i18n';
import {Preferences} from 'utils/constants'; import {Preferences} from 'utils/constants';
import type {GlobalState} from 'types/store'; import type {GlobalState} from 'types/store';
import UserSettingsDisplay from './user_settings_display'; import UserSettingsDisplay from './user_settings_display';
type OwnProps = {
user: UserProfile;
}
export function makeMapStateToProps() { export function makeMapStateToProps() {
return (state: GlobalState) => { return (state: GlobalState, props: OwnProps) => {
const config = getConfig(state); const config = getConfig(state);
const currentUserId = getCurrentUserId(state); const currentUserId = getCurrentUserId(state);
const userTimezone = getCurrentTimezoneFull(state); const userTimezone = getCurrentTimezoneFull(state);
@@ -33,7 +39,6 @@ export function makeMapStateToProps() {
const timezoneLabel = getCurrentTimezoneLabel(state); const timezoneLabel = getCurrentTimezoneLabel(state);
const allowCustomThemes = config.AllowCustomThemes === 'true'; const allowCustomThemes = config.AllowCustomThemes === 'true';
const enableLinkPreviews = config.EnableLinkPreviews === 'true'; const enableLinkPreviews = config.EnableLinkPreviews === 'true';
const defaultClientLocale = config.DefaultClientLocale as string;
const enableThemeSelection = config.EnableThemeSelection === 'true'; const enableThemeSelection = config.EnableThemeSelection === 'true';
const lockTeammateNameDisplay = getLicense(state).LockTeammateNameDisplay === 'true' && config.LockTeammateNameDisplay === 'true'; const lockTeammateNameDisplay = getLicense(state).LockTeammateNameDisplay === 'true' && config.LockTeammateNameDisplay === 'true';
const configTeammateNameDisplay = config.TeammateNameDisplay as string; const configTeammateNameDisplay = config.TeammateNameDisplay as string;
@@ -45,12 +50,18 @@ export function makeMapStateToProps() {
lastActiveDisplay = false; lastActiveDisplay = false;
} }
let userLocale = props.user.locale;
if (!isLanguageAvailable(state, userLocale)) {
userLocale = config.DefaultClientLocale as string;
}
return { return {
lockTeammateNameDisplay, lockTeammateNameDisplay,
allowCustomThemes, allowCustomThemes,
configTeammateNameDisplay, configTeammateNameDisplay,
enableLinkPreviews, enableLinkPreviews,
defaultClientLocale, locales: getLanguages(state),
userLocale,
enableThemeSelection, enableThemeSelection,
timezones, timezones,
timezoneLabel, timezoneLabel,

Просмотреть файл

@@ -7,8 +7,18 @@ import type {Dispatch} from 'redux';
import {updateMe} from 'mattermost-redux/actions/users'; import {updateMe} from 'mattermost-redux/actions/users';
import {getLanguages} from 'i18n/i18n';
import type {GlobalState} from 'types/store';
import ManageLanguages from './manage_languages'; import ManageLanguages from './manage_languages';
function mapStateToProps(state: GlobalState) {
return {
locales: getLanguages(state),
};
}
function mapDispatchToProps(dispatch: Dispatch) { function mapDispatchToProps(dispatch: Dispatch) {
return { return {
actions: bindActionCreators({ actions: bindActionCreators({
@@ -17,4 +27,4 @@ function mapDispatchToProps(dispatch: Dispatch) {
}; };
} }
export default connect(null, mapDispatchToProps)(ManageLanguages); export default connect(mapStateToProps, mapDispatchToProps)(ManageLanguages);

Просмотреть файл

@@ -5,6 +5,7 @@ import React from 'react';
import type {UserProfile} from '@mattermost/types/users'; import type {UserProfile} from '@mattermost/types/users';
import {getAllLanguages} from 'i18n/i18n';
import {shallowWithIntl} from 'tests/helpers/intl-test-helper'; import {shallowWithIntl} from 'tests/helpers/intl-test-helper';
import ManageLanguages from './manage_languages'; import ManageLanguages from './manage_languages';
@@ -18,6 +19,7 @@ describe('components/user_settings/display/manage_languages/manage_languages', (
const requiredProps = { const requiredProps = {
user: user as UserProfile, user: user as UserProfile,
locale: 'en', locale: 'en',
locales: getAllLanguages(),
updateSection: jest.fn(), updateSection: jest.fn(),
actions: { actions: {
updateMe: jest.fn(() => Promise.resolve({})), updateMe: jest.fn(() => Promise.resolve({})),

Просмотреть файл

@@ -14,7 +14,7 @@ import type {ActionResult} from 'mattermost-redux/types/actions';
import ExternalLink from 'components/external_link'; import ExternalLink from 'components/external_link';
import SettingItemMax from 'components/setting_item_max'; import SettingItemMax from 'components/setting_item_max';
import * as I18n from 'i18n/i18n.jsx'; import type {Language} from 'i18n/i18n';
import Constants from 'utils/constants'; import Constants from 'utils/constants';
import {isKeyPressed} from 'utils/keyboard'; import {isKeyPressed} from 'utils/keyboard';
@@ -26,6 +26,7 @@ type Props = {
intl: IntlShape; intl: IntlShape;
user: UserProfile; user: UserProfile;
locale: string; locale: string;
locales: Record<string, Language>;
updateSection: (section: string) => void; updateSection: (section: string) => void;
actions: Actions; actions: Actions;
}; };
@@ -47,11 +48,10 @@ export class ManageLanguage extends React.PureComponent<Props, State> {
reactSelectContainer: React.RefObject<HTMLDivElement>; reactSelectContainer: React.RefObject<HTMLDivElement>;
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
const locales: any = I18n.getLanguages();
const userLocale = props.locale; const userLocale = props.locale;
const selectedOption = { const selectedOption = {
value: locales[userLocale].value, value: props.locales[userLocale].value,
label: locales[userLocale].name, label: props.locales[userLocale].name,
}; };
this.reactSelectContainer = React.createRef(); this.reactSelectContainer = React.createRef();
@@ -155,7 +155,8 @@ export class ManageLanguage extends React.PureComponent<Props, State> {
}; };
render() { render() {
const {intl} = this.props; const {intl, locales} = this.props;
let serverError; let serverError;
if (this.state.serverError) { if (this.state.serverError) {
serverError = ( serverError = (
@@ -164,7 +165,6 @@ export class ManageLanguage extends React.PureComponent<Props, State> {
} }
const options: SelectedOption[] = []; const options: SelectedOption[] = [];
const locales: any = I18n.getLanguages();
const languages = Object.keys(locales). const languages = Object.keys(locales).
map((l) => { map((l) => {

Просмотреть файл

@@ -9,6 +9,7 @@ import type {UserProfile} from '@mattermost/types/users';
import configureStore from 'store'; import configureStore from 'store';
import {getAllLanguages} from 'i18n/i18n';
import {mountWithIntl} from 'tests/helpers/intl-test-helper'; import {mountWithIntl} from 'tests/helpers/intl-test-helper';
import UserSettingsDisplay from './user_settings_display'; import UserSettingsDisplay from './user_settings_display';
@@ -35,7 +36,8 @@ describe('components/user_settings/display/UserSettingsDisplay', () => {
setEnforceFocus: jest.fn(), setEnforceFocus: jest.fn(),
enableLinkPreviews: true, enableLinkPreviews: true,
enableThemeSelection: false, enableThemeSelection: false,
defaultClientLocale: 'en', locales: getAllLanguages(),
userLocale: 'en',
canCreatePublicChannel: true, canCreatePublicChannel: true,
canCreatePrivateChannel: true, canCreatePrivateChannel: true,
timezoneLabel: '', timezoneLabel: '',

Просмотреть файл

@@ -20,7 +20,8 @@ import SettingItem from 'components/setting_item';
import SettingItemMax from 'components/setting_item_max'; import SettingItemMax from 'components/setting_item_max';
import ThemeSetting from 'components/user_settings/display/user_settings_theme'; import ThemeSetting from 'components/user_settings/display/user_settings_theme';
import * as I18n from 'i18n/i18n.jsx'; import type {Language} from 'i18n/i18n';
import {getLanguageInfo} from 'i18n/i18n';
import Constants from 'utils/constants'; import Constants from 'utils/constants';
import {t} from 'utils/i18n'; import {t} from 'utils/i18n';
import {getBrowserTimezone} from 'utils/timezone'; import {getBrowserTimezone} from 'utils/timezone';
@@ -104,7 +105,8 @@ type Props = {
userTimezone: UserTimezone; userTimezone: UserTimezone;
allowCustomThemes: boolean; allowCustomThemes: boolean;
enableLinkPreviews: boolean; enableLinkPreviews: boolean;
defaultClientLocale: string; locales: Record<string, Language>;
userLocale: string;
enableThemeSelection: boolean; enableThemeSelection: boolean;
configTeammateNameDisplay: string; configTeammateNameDisplay: string;
currentUserTimezone: string; currentUserTimezone: string;
@@ -1015,11 +1017,8 @@ export default class UserSettingsDisplay extends React.PureComponent<Props, Stat
}); });
let languagesSection; let languagesSection;
let userLocale = this.props.user.locale; const userLocale = this.props.userLocale;
if (!I18n.isLanguageAvailable(userLocale)) { const localeName = getLanguageInfo(userLocale).name;
userLocale = this.props.defaultClientLocale;
}
const localeName = I18n.getLanguageInfo(userLocale).name;
languagesSection = ( languagesSection = (
<div> <div>
@@ -1047,7 +1046,7 @@ export default class UserSettingsDisplay extends React.PureComponent<Props, Stat
</div> </div>
); );
if (Object.keys(I18n.getLanguages()).length === 1) { if (Object.keys(this.props.locales).length === 1) {
languagesSection = null; languagesSection = null;
} }

Просмотреть файл

@@ -1,6 +1,10 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
/**
* @typedef {} Language
*/
/* eslint-disable import/order */ /* eslint-disable import/order */
import bg from './bg.json'; import bg from './bg.json';
import de from './de.json'; import de from './de.json';
@@ -26,8 +30,6 @@ import zhCN from './zh-CN.json';
import {getConfig} from 'mattermost-redux/selectors/entities/general'; import {getConfig} from 'mattermost-redux/selectors/entities/general';
import store from 'stores/redux_store';
// should match the values in server/public/shared/i18n/i18n.go // should match the values in server/public/shared/i18n/i18n.go
const languages = { const languages = {
de: { de: {
@@ -168,8 +170,12 @@ export function getAllLanguages() {
return languages; return languages;
} }
export function getLanguages() { /**
const config = getConfig(store.getState()); * @param {import('types/store').GlobalState} state
* @returns {Record<string, Language>}
*/
export function getLanguages(state) {
const config = getConfig(state);
if (!config.AvailableLocales) { if (!config.AvailableLocales) {
return getAllLanguages(); return getAllLanguages();
} }
@@ -185,6 +191,11 @@ export function getLanguageInfo(locale) {
return getAllLanguages()[locale]; return getAllLanguages()[locale];
} }
export function isLanguageAvailable(locale) { /**
return Boolean(getLanguages()[locale]); * @param {import('types/store').GlobalState} state
* @param {string} locale
* @returns {boolean}
*/
export function isLanguageAvailable(state, locale) {
return Boolean(getLanguages(state)[locale]);
} }

Просмотреть файл

@@ -15,10 +15,10 @@ export function getCurrentLocale(state: GlobalState): string {
// If locale is provided in query parameter and the user is not logged in, we try get locale from param // If locale is provided in query parameter and the user is not logged in, we try get locale from param
const localeFromParam: string | null = (new URLSearchParams(window.location?.search)).get('locale'); const localeFromParam: string | null = (new URLSearchParams(window.location?.search)).get('locale');
const defaultLocale: string | undefined = const defaultLocale: string | undefined =
localeFromParam && I18n.isLanguageAvailable(localeFromParam) ? localeFromParam : getConfig(state).DefaultClientLocale; localeFromParam && I18n.isLanguageAvailable(state, localeFromParam) ? localeFromParam : getConfig(state).DefaultClientLocale;
const currentLocale: string = getCurrentUserLocale(state, defaultLocale); const currentLocale: string = getCurrentUserLocale(state, defaultLocale);
if (I18n.isLanguageAvailable(currentLocale)) { if (I18n.isLanguageAvailable(state, currentLocale)) {
return currentLocale; return currentLocale;
} }
return General.DEFAULT_LOCALE; return General.DEFAULT_LOCALE;