Remove access to global state from i18n/i18n (#26750)
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
f3b80f77a6
Коммит
b091ef5686
@@ -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;
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user