MM-52261: Remove boards language selector, use Language in Display Settings (#23095)

Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
Caleb Roseland
2023-05-08 13:37:33 -05:00
коммит произвёл GitHub
родитель a1470c77ac
Коммит 657c0024f9
20 изменённых файлов: 134 добавлений и 1376 удалений

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

@@ -259,7 +259,6 @@
"Sidebar.no-boards-in-category": "No boards inside", "Sidebar.no-boards-in-category": "No boards inside",
"Sidebar.product-tour": "Product tour", "Sidebar.product-tour": "Product tour",
"Sidebar.random-icons": "Random icons", "Sidebar.random-icons": "Random icons",
"Sidebar.set-language": "Set language",
"Sidebar.set-theme": "Set theme", "Sidebar.set-theme": "Set theme",
"Sidebar.settings": "Settings", "Sidebar.settings": "Settings",
"Sidebar.template-from-board": "New template from board", "Sidebar.template-from-board": "New template from board",

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

@@ -1,7 +1,6 @@
// 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.
import React, {useEffect} from 'react' import React, {useEffect} from 'react'
import {IntlProvider} from 'react-intl'
import {DndProvider} from 'react-dnd' import {DndProvider} from 'react-dnd'
import {HTML5Backend} from 'react-dnd-html5-backend' import {HTML5Backend} from 'react-dnd-html5-backend'
import {TouchBackend} from 'react-dnd-touch-backend' import {TouchBackend} from 'react-dnd-touch-backend'
@@ -9,12 +8,10 @@ import {History} from 'history'
import TelemetryClient from './telemetry/telemetryClient' import TelemetryClient from './telemetry/telemetryClient'
import {getMessages} from './i18n'
import FlashMessages from './components/flashMessages' import FlashMessages from './components/flashMessages'
import NewVersionBanner from './components/newVersionBanner' import NewVersionBanner from './components/newVersionBanner'
import {Utils} from './utils' import {Utils} from './utils'
import {fetchMe, getMe} from './store/users' import {fetchMe, getMe} from './store/users'
import {fetchLanguage, getLanguage} from './store/language'
import {useAppDispatch, useAppSelector} from './store/hooks' import {useAppDispatch, useAppSelector} from './store/hooks'
import {fetchClientConfig} from './store/clientConfig' import {fetchClientConfig} from './store/clientConfig'
import FocalboardRouter from './router' import FocalboardRouter from './router'
@@ -26,12 +23,10 @@ type Props = {
} }
const App = (props: Props): JSX.Element => { const App = (props: Props): JSX.Element => {
const language = useAppSelector<string>(getLanguage)
const me = useAppSelector<IUser|null>(getMe) const me = useAppSelector<IUser|null>(getMe)
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
useEffect(() => { useEffect(() => {
dispatch(fetchLanguage())
dispatch(fetchMe()) dispatch(fetchMe())
dispatch(fetchClientConfig()) dispatch(fetchClientConfig())
}, []) }, [])
@@ -43,20 +38,15 @@ const App = (props: Props): JSX.Element => {
}, [me]) }, [me])
return ( return (
<IntlProvider <DndProvider backend={Utils.isMobile() ? TouchBackend : HTML5Backend}>
locale={language.split(/[_]/)[0]} <FlashMessages milliseconds={2000}/>
messages={getMessages(language)} <div id='frame'>
> <div id='main'>
<DndProvider backend={Utils.isMobile() ? TouchBackend : HTML5Backend}> <NewVersionBanner/>
<FlashMessages milliseconds={2000}/> <FocalboardRouter history={props.history}/>
<div id='frame'>
<div id='main'>
<NewVersionBanner/>
<FocalboardRouter history={props.history}/>
</div>
</div> </div>
</DndProvider> </div>
</IntlProvider> </DndProvider>
) )
} }

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

@@ -1,14 +1,11 @@
// 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.
import React, {useCallback, useMemo, useState} from 'react' import React, {useCallback, useMemo, useState} from 'react'
import {FormattedMessage, IntlProvider, useIntl} from 'react-intl' import {FormattedMessage, useIntl} from 'react-intl'
import debounce from 'lodash/debounce' import debounce from 'lodash/debounce'
import {SuiteWindow} from 'src/types/index' import {SuiteWindow} from 'src/types/index'
import {getMessages} from 'src/i18n'
import {getLanguage} from 'src/store/language'
import {useWebsockets} from 'src/hooks/websockets' import {useWebsockets} from 'src/hooks/websockets'
import octoClient from 'src/octoClient' import octoClient from 'src/octoClient'
@@ -220,17 +217,4 @@ const BoardSelector = () => {
) )
} }
const IntlBoardSelector = () => { export default BoardSelector
const language = useAppSelector<string>(getLanguage)
return (
<IntlProvider
locale={language.split(/[_]/)[0]}
messages={getMessages(language)}
>
<BoardSelector/>
</IntlProvider>
)
}
export default IntlBoardSelector

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

@@ -1,19 +1,17 @@
// 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.
import React, {useEffect, useState} from 'react' import React, {useEffect, useState} from 'react'
import {FormattedMessage, IntlProvider, useIntl} from 'react-intl' import {FormattedMessage, useIntl} from 'react-intl'
import WithWebSockets from 'src/components/withWebSockets' import WithWebSockets from 'src/components/withWebSockets'
import {useWebsockets} from 'src/hooks/websockets' import {useWebsockets} from 'src/hooks/websockets'
import {getLanguage} from 'src/store/language'
import {useAppSelector} from 'src/store/hooks' import {useAppSelector} from 'src/store/hooks'
import {getCurrentTeamId} from 'src/store/teams' import {getCurrentTeamId} from 'src/store/teams'
import {MMWebSocketClient, WSClient} from 'src/wsclient' import {MMWebSocketClient, WSClient} from 'src/wsclient'
import manifest from 'src/manifest' import manifest from 'src/manifest'
import {getMessages} from 'src/i18n'
import {Utils} from 'src/utils' import {Utils} from 'src/utils'
import {Block} from 'src/blocks/block' import {Block} from 'src/blocks/block'
import {Card} from 'src/blocks/card' import {Card} from 'src/blocks/card'
@@ -278,17 +276,4 @@ export const BoardsUnfurl = (props: Props): JSX.Element => {
) )
} }
const IntlBoardsUnfurl = (props: Props) => { export default BoardsUnfurl
const language = useAppSelector<string>(getLanguage)
return (
<IntlProvider
locale={language.split(/[_]/)[0]}
messages={getMessages(language)}
>
<BoardsUnfurl {...props}/>
</IntlProvider>
)
}
export default IntlBoardsUnfurl

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

@@ -7,8 +7,6 @@ import React, {
useState, useState,
} from 'react' } from 'react'
import {IntlProvider, createIntl, createIntlCache} from 'react-intl'
import Select from 'react-select/async' import Select from 'react-select/async'
import { import {
FormatOptionLabelMeta, FormatOptionLabelMeta,
@@ -20,10 +18,9 @@ import {
import {CSSObject} from '@emotion/serialize' import {CSSObject} from '@emotion/serialize'
import {getCurrentLanguage, getMessages} from 'src/i18n' import {useIntl} from 'react-intl'
import {getLanguage} from 'src/store/language'
import CompassIcon from 'src/widgets/icons/compassIcon' import CompassIcon from 'src/widgets/icons/compassIcon'
import {useAppSelector} from 'src/store/hooks'
import {mutator} from 'src/mutator' import {mutator} from 'src/mutator'
import {useGetAllTemplates} from 'src/hooks/useGetAllTemplates' import {useGetAllTemplates} from 'src/hooks/useGetAllTemplates'
@@ -46,12 +43,6 @@ type ReactSelectItem = {
const EMPTY_BOARD = 'empty_board' const EMPTY_BOARD = 'empty_board'
const TEMPLATE_DESCRIPTION_LENGTH = 70 const TEMPLATE_DESCRIPTION_LENGTH = 70
const cache = createIntlCache()
const intl = createIntl({
locale: getCurrentLanguage(),
messages: getMessages(getCurrentLanguage()),
}, cache)
const {ValueContainer, Placeholder} = components const {ValueContainer, Placeholder} = components
const CustomValueContainer = ({children, ...props}: any) => { const CustomValueContainer = ({children, ...props}: any) => {
return ( return (
@@ -67,6 +58,7 @@ const CustomValueContainer = ({children, ...props}: any) => {
} }
const CreateBoardFromTemplate = (props: Props) => { const CreateBoardFromTemplate = (props: Props) => {
const intl = useIntl()
const {formatMessage} = intl const {formatMessage} = intl
const [addBoard, setAddBoard] = useState(false) const [addBoard, setAddBoard] = useState(false)
@@ -259,17 +251,4 @@ const CreateBoardFromTemplate = (props: Props) => {
) )
} }
const IntlCreateBoardFromTemplate = (props: Props) => { export default CreateBoardFromTemplate
const language = useAppSelector<string>(getLanguage)
return (
<IntlProvider
locale={language.split(/[_]/)[0]}
messages={getMessages(language)}
>
<CreateBoardFromTemplate {...props}/>
</IntlProvider>
)
}
export default IntlCreateBoardFromTemplate

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

@@ -238,24 +238,6 @@ exports[`components/sidebar/GlobalHeaderSettingsMenu imports menu open should ma
</div> </div>
</div> </div>
</div> </div>
<div>
<div
class="MenuOption SubMenuOption menu-option open-left"
id="lang"
>
<div
class="noicon"
/>
<div
class="menu-name"
>
Set language
</div>
<i
class="CompassIcon icon-chevron-right"
/>
</div>
</div>
<div> <div>
<div <div
aria-label="Random icons" aria-label="Random icons"
@@ -390,499 +372,6 @@ exports[`components/sidebar/GlobalHeaderSettingsMenu languages menu open should
/> />
</div> </div>
</div> </div>
<div>
<div
class="MenuOption SubMenuOption menu-option open-left menu-option-active"
id="lang"
>
<div
class="noicon"
/>
<div
class="menu-name"
>
Set language
</div>
<i
class="CompassIcon icon-chevron-right"
/>
<div
class="SubMenu Menu noselect left-bottom"
>
<div
class="menu-contents"
>
<div
class="menu-options"
>
<div
aria-label="English"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
English
</div>
</div>
<svg
class="CheckIcon Icon"
viewBox="0 0 100 100"
xmlns="http://www.w3.org/2000/svg"
>
<polyline
points="20,60 40,80 80,40"
/>
</svg>
</div>
<div
aria-label="Español"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Español
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="Deutsch"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Deutsch
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="日本語"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
日本語
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="Français"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Français
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="Nederlands"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Nederlands
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="Pусский"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Pусский
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="中文 (繁體)"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
中文 (繁體)
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="中文 (简体)"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
中文 (简体)
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="Türkçe"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Türkçe
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="Occitan"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Occitan
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="Português (Brasil)"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Português (Brasil)
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="Català"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Català
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="Ελληνικά"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Ελληνικά
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="bahasa Indonesia"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
bahasa Indonesia
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="Italiano"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Italiano
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="Svenska"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Svenska
</div>
</div>
<div
class="noicon"
/>
</div>
</div>
<div
class="menu-spacer hideOnWidescreen"
/>
<div
class="menu-options hideOnWidescreen"
>
<div
aria-label="Cancel"
class="MenuOption TextOption menu-option menu-cancel"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Cancel
</div>
</div>
<div
class="noicon"
/>
</div>
</div>
</div>
</div>
</div>
</div>
<div> <div>
<div <div
aria-label="Random icons" aria-label="Random icons"
@@ -1039,24 +528,6 @@ exports[`components/sidebar/GlobalHeaderSettingsMenu settings menu open should m
/> />
</div> </div>
</div> </div>
<div>
<div
class="MenuOption SubMenuOption menu-option open-left"
id="lang"
>
<div
class="noicon"
/>
<div
class="menu-name"
>
Set language
</div>
<i
class="CompassIcon icon-chevron-right"
/>
</div>
</div>
<div> <div>
<div <div
aria-label="Random icons" aria-label="Random icons"

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

@@ -3,14 +3,10 @@
// //
import React from 'react' import React from 'react'
import {Provider as ReduxProvider} from 'react-redux' import {Provider as ReduxProvider} from 'react-redux'
import {IntlProvider} from 'react-intl'
import {History} from 'history' import {History} from 'history'
import HelpIcon from 'src/widgets/icons/help' import HelpIcon from 'src/widgets/icons/help'
import store from 'src/store' import store from 'src/store'
import {useAppSelector} from 'src/store/hooks'
import {getLanguage} from 'src/store/language'
import {getMessages} from 'src/i18n'
import {Constants} from 'src/constants' import {Constants} from 'src/constants'
@@ -23,27 +19,21 @@ type HeaderItemProps = {
} }
const HeaderItems = (props: HeaderItemProps) => { const HeaderItems = (props: HeaderItemProps) => {
const language = useAppSelector<string>(getLanguage)
const helpUrl = 'https://www.focalboard.com/fwlink/doc-boards.html?v=' + Constants.versionString const helpUrl = 'https://www.focalboard.com/fwlink/doc-boards.html?v=' + Constants.versionString
return ( return (
<IntlProvider <div className='GlobalHeaderComponent'>
locale={language.split(/[_]/)[0]} <span className='spacer'/>
messages={getMessages(language)} <a
> href={helpUrl}
<div className='GlobalHeaderComponent'> target='_blank'
<span className='spacer'/> rel='noreferrer'
<a className='GlobalHeaderComponent__button help-button'
href={helpUrl} >
target='_blank' <HelpIcon/>
rel='noreferrer' </a>
className='GlobalHeaderComponent__button help-button' <GlobalHeaderSettingsMenu history={props.history}/>
> </div>
<HelpIcon/>
</a>
<GlobalHeaderSettingsMenu history={props.history}/>
</div>
</IntlProvider>
) )
} }

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

@@ -8,13 +8,11 @@ import {Archiver} from 'src/archiver'
import Menu from 'src/widgets/menu' import Menu from 'src/widgets/menu'
import MenuWrapper from 'src/widgets/menuWrapper' import MenuWrapper from 'src/widgets/menuWrapper'
import {useAppDispatch, useAppSelector} from 'src/store/hooks' import {useAppDispatch, useAppSelector} from 'src/store/hooks'
import {storeLanguage} from 'src/store/language'
import {getMe, patchProps} from 'src/store/users' import {getMe, patchProps} from 'src/store/users'
import {Team, getCurrentTeam} from 'src/store/teams' import {Team, getCurrentTeam} from 'src/store/teams'
import {IUser, UserConfigPatch} from 'src/user' import {IUser, UserConfigPatch} from 'src/user'
import octoClient from 'src/octoClient' import octoClient from 'src/octoClient'
import {UserSettings} from 'src/userSettings' import {UserSettings} from 'src/userSettings'
import CheckIcon from 'src/widgets/icons/check'
import SettingsIcon from 'src/widgets/icons/settings' import SettingsIcon from 'src/widgets/icons/settings'
import {Constants} from 'src/constants' import {Constants} from 'src/constants'
@@ -72,23 +70,6 @@ const GlobalHeaderSettingsMenu = (props: Props) => {
)) ))
} }
</Menu.SubMenu> </Menu.SubMenu>
<Menu.SubMenu
id='lang'
name={intl.formatMessage({id: 'Sidebar.set-language', defaultMessage: 'Set language'})}
position='left-bottom'
>
{
Constants.languages.map((language) => (
<Menu.Text
key={language.code}
id={`${language.name}-lang`}
name={language.displayName}
onClick={async () => dispatch(storeLanguage(language.code))}
rightIcon={intl.locale.toLowerCase() === language.code ? <CheckIcon/> : null}
/>
))
}
</Menu.SubMenu>
<Menu.Switch <Menu.Switch
id='random-icons' id='random-icons'
name={intl.formatMessage({id: 'Sidebar.random-icons', defaultMessage: 'Random icons'})} name={intl.formatMessage({id: 'Sidebar.random-icons', defaultMessage: 'Random icons'})}

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

@@ -1,10 +1,7 @@
// 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.
import React, {useEffect} from 'react' import React, {useEffect} from 'react'
import {FormattedMessage, IntlProvider, useIntl} from 'react-intl' import {FormattedMessage, useIntl} from 'react-intl'
import {getMessages} from 'src/i18n'
import {getLanguage} from 'src/store/language'
import {useWebsockets} from 'src/hooks/websockets' import {useWebsockets} from 'src/hooks/websockets'
@@ -169,17 +166,4 @@ const RHSChannelBoards = () => {
) )
} }
const IntlRHSChannelBoards = () => { export default RHSChannelBoards
const language = useAppSelector<string>(getLanguage)
return (
<IntlProvider
locale={language.split(/[_]/)[0]}
messages={getMessages(language)}
>
<RHSChannelBoards/>
</IntlProvider>
)
}
export default IntlRHSChannelBoards

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

@@ -1,10 +1,8 @@
// 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.
import React from 'react' import React from 'react'
import {FormattedMessage, IntlProvider} from 'react-intl' import {FormattedMessage} from 'react-intl'
import {getMessages} from 'src/i18n'
import {getLanguage} from 'src/store/language'
import {getCurrentChannel} from 'src/store/channels' import {getCurrentChannel} from 'src/store/channels'
import {useAppSelector} from 'src/store/hooks' import {useAppSelector} from 'src/store/hooks'
@@ -12,31 +10,25 @@ import appBarIcon from 'static/app-bar-icon.png'
const RHSChannelBoardsHeader = () => { const RHSChannelBoardsHeader = () => {
const currentChannel = useAppSelector(getCurrentChannel) const currentChannel = useAppSelector(getCurrentChannel)
const language = useAppSelector<string>(getLanguage)
if (!currentChannel) { if (!currentChannel) {
return null return null
} }
return ( return (
<IntlProvider <div>
locale={language.split(/[_]/)[0]} <img
messages={getMessages(language)} className='boards-rhs-header-logo'
> src={appBarIcon}
<div> />
<img <span>
className='boards-rhs-header-logo' <FormattedMessage
src={appBarIcon} id='rhs-channel-boards-header.title'
defaultMessage='Boards'
/> />
<span> </span>
<FormattedMessage <span className='style--none sidebar--right__title__subtitle'>{currentChannel.display_name}</span>
id='rhs-channel-boards-header.title' </div>
defaultMessage='Boards'
/>
</span>
<span className='style--none sidebar--right__title__subtitle'>{currentChannel.display_name}</span>
</div>
</IntlProvider>
) )
} }

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

@@ -263,24 +263,6 @@ exports[`components/sidebar/SidebarSettingsMenu imports menu open should match s
/> />
</div> </div>
</div> </div>
<div>
<div
class="MenuOption SubMenuOption menu-option"
id="lang"
>
<div
class="noicon"
/>
<div
class="menu-name"
>
Set language
</div>
<i
class="CompassIcon icon-chevron-right"
/>
</div>
</div>
<div> <div>
<div <div
class="MenuOption SubMenuOption menu-option" class="MenuOption SubMenuOption menu-option"
@@ -431,499 +413,6 @@ exports[`components/sidebar/SidebarSettingsMenu languages menu open should match
/> />
</div> </div>
</div> </div>
<div>
<div
class="MenuOption SubMenuOption menu-option menu-option-active"
id="lang"
>
<div
class="noicon"
/>
<div
class="menu-name"
>
Set language
</div>
<i
class="CompassIcon icon-chevron-right"
/>
<div
class="SubMenu Menu noselect top"
>
<div
class="menu-contents"
>
<div
class="menu-options"
>
<div
aria-label="English"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
English
</div>
</div>
<svg
class="CheckIcon Icon"
viewBox="0 0 100 100"
xmlns="http://www.w3.org/2000/svg"
>
<polyline
points="20,60 40,80 80,40"
/>
</svg>
</div>
<div
aria-label="Español"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Español
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="Deutsch"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Deutsch
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="日本語"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
日本語
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="Français"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Français
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="Nederlands"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Nederlands
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="Pусский"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Pусский
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="中文 (繁體)"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
中文 (繁體)
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="中文 (简体)"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
中文 (简体)
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="Türkçe"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Türkçe
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="Occitan"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Occitan
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="Português (Brasil)"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Português (Brasil)
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="Català"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Català
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="Ελληνικά"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Ελληνικά
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="bahasa Indonesia"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
bahasa Indonesia
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="Italiano"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Italiano
</div>
</div>
<div
class="noicon"
/>
</div>
<div
aria-label="Svenska"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Svenska
</div>
</div>
<div
class="noicon"
/>
</div>
</div>
<div
class="menu-spacer hideOnWidescreen"
/>
<div
class="menu-options hideOnWidescreen"
>
<div
aria-label="Cancel"
class="MenuOption TextOption menu-option menu-cancel"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Cancel
</div>
</div>
<div
class="noicon"
/>
</div>
</div>
</div>
</div>
</div>
</div>
<div> <div>
<div <div
class="MenuOption SubMenuOption menu-option" class="MenuOption SubMenuOption menu-option"
@@ -1094,24 +583,6 @@ exports[`components/sidebar/SidebarSettingsMenu settings menu open should match
/> />
</div> </div>
</div> </div>
<div>
<div
class="MenuOption SubMenuOption menu-option"
id="lang"
>
<div
class="noicon"
/>
<div
class="menu-name"
>
Set language
</div>
<i
class="CompassIcon icon-chevron-right"
/>
</div>
</div>
<div> <div>
<div <div
class="MenuOption SubMenuOption menu-option" class="MenuOption SubMenuOption menu-option"
@@ -1262,24 +733,6 @@ exports[`components/sidebar/SidebarSettingsMenu theme menu open should match sna
/> />
</div> </div>
</div> </div>
<div>
<div
class="MenuOption SubMenuOption menu-option"
id="lang"
>
<div
class="noicon"
/>
<div
class="menu-name"
>
Set language
</div>
<i
class="CompassIcon icon-chevron-right"
/>
</div>
</div>
<div> <div>
<div <div
class="MenuOption SubMenuOption menu-option menu-option-active" class="MenuOption SubMenuOption menu-option menu-option-active"

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

@@ -17,8 +17,7 @@ import {
} from 'src/theme' } from 'src/theme'
import Menu from 'src/widgets/menu' import Menu from 'src/widgets/menu'
import MenuWrapper from 'src/widgets/menuWrapper' import MenuWrapper from 'src/widgets/menuWrapper'
import {useAppDispatch, useAppSelector} from 'src/store/hooks' import {useAppSelector} from 'src/store/hooks'
import {storeLanguage} from 'src/store/language'
import {Team, getCurrentTeam} from 'src/store/teams' import {Team, getCurrentTeam} from 'src/store/teams'
import {UserSettings} from 'src/userSettings' import {UserSettings} from 'src/userSettings'
@@ -34,7 +33,6 @@ type Props = {
const SidebarSettingsMenu = (props: Props) => { const SidebarSettingsMenu = (props: Props) => {
const intl = useIntl() const intl = useIntl()
const dispatch = useAppDispatch()
const currentTeam = useAppSelector<Team|null>(getCurrentTeam) const currentTeam = useAppSelector<Team|null>(getCurrentTeam)
// we need this as the sidebar doesn't always need to re-render // we need this as the sidebar doesn't always need to re-render
@@ -123,23 +121,6 @@ const SidebarSettingsMenu = (props: Props) => {
} }
}} }}
/> />
<Menu.SubMenu
id='lang'
name={intl.formatMessage({id: 'Sidebar.set-language', defaultMessage: 'Set language'})}
position='top'
>
{
Constants.languages.map((language) => (
<Menu.Text
key={language.code}
id={`${language.name}-lang`}
name={language.displayName}
onClick={async () => dispatch(storeLanguage(language.code))}
rightIcon={intl.locale.toLowerCase() === language.code ? <CheckIcon/> : null}
/>
))
}
</Menu.SubMenu>
<Menu.SubMenu <Menu.SubMenu
id='theme' id='theme'
name={intl.formatMessage({id: 'Sidebar.set-theme', defaultMessage: 'Set theme'})} name={intl.formatMessage({id: 'Sidebar.set-theme', defaultMessage: 'Set theme'})}

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

@@ -5,79 +5,81 @@ import messages_ca from 'i18n/ca.json'
import messages_de from 'i18n/de.json' import messages_de from 'i18n/de.json'
import messages_el from 'i18n/el.json' import messages_el from 'i18n/el.json'
import messages_en from 'i18n/en.json' import messages_en from 'i18n/en.json'
import messages_enAu from 'i18n/en_AU.json'
import messages_es from 'i18n/es.json' import messages_es from 'i18n/es.json'
import messages_fa from 'i18n/fa.json'
import messages_fr from 'i18n/fr.json' import messages_fr from 'i18n/fr.json'
import messages_hu from 'i18n/hu.json'
import messages_id from 'i18n/id.json' import messages_id from 'i18n/id.json'
import messages_it from 'i18n/it.json' import messages_it from 'i18n/it.json'
import messages_ja from 'i18n/ja.json' import messages_ja from 'i18n/ja.json'
import messages_ko from 'i18n/ko.json'
import messages_nl from 'i18n/nl.json' import messages_nl from 'i18n/nl.json'
import messages_oc from 'i18n/oc.json' import messages_oc from 'i18n/oc.json'
import messages_pl from 'i18n/pl.json'
import messages_ptBr from 'i18n/pt_BR.json' import messages_ptBr from 'i18n/pt_BR.json'
import messages_ru from 'i18n/ru.json' import messages_ru from 'i18n/ru.json'
import messages_sv from 'i18n/sv.json' import messages_sv from 'i18n/sv.json'
import messages_tr from 'i18n/tr.json' import messages_tr from 'i18n/tr.json'
import messages_uk from 'i18n/uk.json'
import messages_zhHans from 'i18n/zh_Hans.json' import messages_zhHans from 'i18n/zh_Hans.json'
import messages_zhHant from 'i18n/zh_Hant.json' import messages_zhHant from 'i18n/zh_Hant.json'
import {UserSettings} from './userSettings' export function getMessages(locale: string): {[key: string]: string} {
switch (locale) {
const supportedLanguages = ['ca', 'de', 'el', 'en', 'es', 'fr', 'id', 'it', 'ja', 'nl', 'oc', 'pt-br', 'ru', 'sv', 'tr', 'zh-cn', 'zh-tw'] // case 'bg':
// return messages_bg // TODO missing translation sourcefile
export function getMessages(lang: string): {[key: string]: string} {
switch (lang) {
case 'ca': case 'ca':
return messages_ca return messages_ca // TODO missing option in language selector
case 'de': case 'de':
return messages_de return messages_de
case 'el': case 'el':
return messages_el return messages_el // TODO missing option in language selector
case 'en':
default:
return messages_en
case 'en-AU':
return messages_enAu
case 'es': case 'es':
return messages_es return messages_es
case 'fa':
return messages_fa
case 'fr': case 'fr':
return messages_fr return messages_fr
case 'hu':
return messages_hu
case 'id': case 'id':
return messages_id return messages_id // TODO missing option in language selector
case 'it': case 'it':
return messages_it return messages_it
case 'ja': case 'ja':
return messages_ja return messages_ja
case 'ko':
return messages_ko
case 'nl': case 'nl':
return messages_nl return messages_nl
case 'oc': case 'oc':
return messages_oc return messages_oc // TODO missing option in language selector
case 'pt-br': case 'pl':
return messages_pl
case 'pt-BR':
return messages_ptBr return messages_ptBr
// case 'ro':
// return messages_ro // TODO missing translation sourcefile
case 'ru': case 'ru':
return messages_ru return messages_ru
case 'sv': case 'sv':
return messages_sv return messages_sv
case 'tr': case 'tr':
return messages_tr return messages_tr
case 'zh-cn': case 'uk':
return messages_uk
case 'zh-Hans':
case 'zh-CN':
return messages_zhHans
case 'zh-Hant':
case 'zh-TW':
return messages_zhHant return messages_zhHant
case 'zh-tx':
return messages_zhHans
case 'zh-tw':
return messages_zhHans
} }
return messages_en
}
export function getCurrentLanguage(): string {
let lang = UserSettings.language
if (!lang) {
if (supportedLanguages.includes(navigator.language)) {
lang = navigator.language
} else if (supportedLanguages.includes(navigator.language.split(/[-_]/)[0])) {
lang = navigator.language.split(/[-_]/)[0]
} else {
lang = 'en'
}
}
return lang
}
export function storeLanguage(lang: string): void {
UserSettings.language = lang
} }

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

@@ -1,7 +1,7 @@
// 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.
import React, {useEffect} from 'react' import React, {useEffect} from 'react'
import {createIntl, createIntlCache} from 'react-intl' import {FormattedMessage} from 'react-intl'
import {Action, Store} from 'redux' import {Action, Store} from 'redux'
import {Provider as ReduxProvider} from 'react-redux' import {Provider as ReduxProvider} from 'react-redux'
import {History, createBrowserHistory} from 'history' import {History, createBrowserHistory} from 'history'
@@ -21,7 +21,7 @@ import {Constants} from 'src/constants'
import {setTeam} from 'src/store/teams' import {setTeam} from 'src/store/teams'
import {UserSettings} from 'src/userSettings' import {UserSettings} from 'src/userSettings'
import {getCurrentLanguage, getMessages} from 'src/i18n' import {getMessages} from 'src/i18n'
const windowAny = (window as SuiteWindow) const windowAny = (window as SuiteWindow)
windowAny.baseURL = '/plugins/boards' windowAny.baseURL = '/plugins/boards'
@@ -232,13 +232,6 @@ export default class Plugin {
windowAny.frontendBaseURL = subpath + windowAny.frontendBaseURL windowAny.frontendBaseURL = subpath + windowAny.frontendBaseURL
windowAny.baseURL = subpath + windowAny.baseURL windowAny.baseURL = subpath + windowAny.baseURL
browserHistory = customHistory() browserHistory = customHistory()
const cache = createIntlCache()
const intl = createIntl({
// modeled after <IntlProvider> in app.tsx
locale: getCurrentLanguage(),
messages: getMessages(getCurrentLanguage()),
}, cache)
this.registry = registry this.registry = registry
@@ -248,6 +241,16 @@ export default class Plugin {
const productID = 'boards' const productID = 'boards'
registry.registerTranslations((locale: string) => {
try {
const messages = getMessages(locale)
return messages
} catch {
return {}
}
})
// register websocket handlers // register websocket handlers
this.registry?.registerWebSocketEventHandler(`custom_${productID}_${ACTION_UPDATE_BOARD}`, (e: any) => wsClient.updateHandler(e.data)) this.registry?.registerWebSocketEventHandler(`custom_${productID}_${ACTION_UPDATE_BOARD}`, (e: any) => wsClient.updateHandler(e.data))
this.registry?.registerWebSocketEventHandler(`custom_${productID}_${ACTION_UPDATE_CATEGORY}`, (e: any) => wsClient.updateHandler(e.data)) this.registry?.registerWebSocketEventHandler(`custom_${productID}_${ACTION_UPDATE_CATEGORY}`, (e: any) => wsClient.updateHandler(e.data))
@@ -389,11 +392,25 @@ export default class Plugin {
} }
if (registry.registerChannelIntroButtonAction) { if (registry.registerChannelIntroButtonAction) {
this.channelHeaderButtonId = registry.registerChannelIntroButtonAction(<FocalboardIcon/>, goToFocalboardTemplate, intl.formatMessage({id: 'ChannelIntro.CreateBoard', defaultMessage: 'Create a board'})) this.channelHeaderButtonId = registry.registerChannelIntroButtonAction(
<FocalboardIcon/>,
goToFocalboardTemplate,
<FormattedMessage
id='ChannelIntro.CreateBoard'
defaultMessage='Create a board'
/>
)
} }
if (this.registry.registerAppBarComponent) { if (this.registry.registerAppBarComponent) {
this.registry.registerAppBarComponent(appBarIcon, () => mmStore.dispatch(toggleRHSPlugin), intl.formatMessage({id: 'AppBar.Tooltip', defaultMessage: 'Toggle linked boards'})) this.registry.registerAppBarComponent(
appBarIcon,
() => mmStore.dispatch(toggleRHSPlugin),
<FormattedMessage
id='AppBar.Tooltip'
defaultMessage='Toggle linked boards'
/>
)
} }
if (this.registry.registerActionAfterChannelCreation) { if (this.registry.registerActionAfterChannelCreation) {
@@ -447,13 +464,23 @@ export default class Plugin {
if (siteStats) { if (siteStats) {
return { return {
boards_count: { boards_count: {
name: intl.formatMessage({id: 'SiteStats.total_boards', defaultMessage: 'Total boards'}), name: (
<FormattedMessage
id='SiteStats.total_boards'
defaultMessage='Total boards'
/>
),
id: 'total_boards', id: 'total_boards',
icon: 'icon-product-boards', icon: 'icon-product-boards',
value: siteStats.board_count, value: siteStats.board_count,
}, },
cards_count: { cards_count: {
name: intl.formatMessage({id: 'SiteStats.total_cards', defaultMessage: 'Total cards'}), name: (
<FormattedMessage
id='SiteStats.total_cards'
defaultMessage='Total cards'
/>
),
id: 'total_cards', id: 'total_cards',
icon: 'icon-products', icon: 'icon-products',
value: siteStats.card_count, value: siteStats.card_count,

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

@@ -3,7 +3,6 @@
import React from 'react' import React from 'react'
import {Router, Switch} from 'react-router-dom' import {Router, Switch} from 'react-router-dom'
import {IntlProvider} from 'react-intl'
import {DndProvider} from 'react-dnd' import {DndProvider} from 'react-dnd'
import {HTML5Backend} from 'react-dnd-html5-backend' import {HTML5Backend} from 'react-dnd-html5-backend'
import {TouchBackend} from 'react-dnd-touch-backend' import {TouchBackend} from 'react-dnd-touch-backend'
@@ -12,12 +11,9 @@ import {createBrowserHistory} from 'history'
import BoardPage from 'src/pages/boardPage/boardPage' import BoardPage from 'src/pages/boardPage/boardPage'
import FBRoute from 'src/route' import FBRoute from 'src/route'
import {getMessages} from 'src/i18n'
import FlashMessages from 'src/components/flashMessages' import FlashMessages from 'src/components/flashMessages'
import NewVersionBanner from 'src/components/newVersionBanner' import NewVersionBanner from 'src/components/newVersionBanner'
import {Utils} from 'src/utils' import {Utils} from 'src/utils'
import {getLanguage} from 'src/store/language'
import {useAppSelector} from 'src/store/hooks'
export const publicBaseURL = () => { export const publicBaseURL = () => {
return Utils.getFrontendBaseURL() + '/public' return Utils.getFrontendBaseURL() + '/public'
@@ -38,23 +34,16 @@ const PublicRouter = () => {
} }
const PublicApp = (): JSX.Element => { const PublicApp = (): JSX.Element => {
const language = useAppSelector<string>(getLanguage)
return ( return (
<IntlProvider <DndProvider backend={Utils.isMobile() ? TouchBackend : HTML5Backend}>
locale={language.split(/[_]/)[0]} <FlashMessages milliseconds={2000}/>
messages={getMessages(language)} <div id='frame'>
> <div id='main'>
<DndProvider backend={Utils.isMobile() ? TouchBackend : HTML5Backend}> <NewVersionBanner/>
<FlashMessages milliseconds={2000}/> <PublicRouter/>
<div id='frame'>
<div id='main'>
<NewVersionBanner/>
<PublicRouter/>
</div>
</div> </div>
</DndProvider> </div>
</IntlProvider> </DndProvider>
) )
} }

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

@@ -6,7 +6,6 @@ import {configureStore} from '@reduxjs/toolkit'
import {reducer as usersReducer} from './users' import {reducer as usersReducer} from './users'
import {reducer as teamsReducer} from './teams' import {reducer as teamsReducer} from './teams'
import {reducer as channelsReducer} from './channels' import {reducer as channelsReducer} from './channels'
import {reducer as languageReducer} from './language'
import {reducer as globalTemplatesReducer} from './globalTemplates' import {reducer as globalTemplatesReducer} from './globalTemplates'
import {reducer as boardsReducer} from './boards' import {reducer as boardsReducer} from './boards'
import {reducer as viewsReducer} from './views' import {reducer as viewsReducer} from './views'
@@ -25,7 +24,6 @@ const store = configureStore({
users: usersReducer, users: usersReducer,
teams: teamsReducer, teams: teamsReducer,
channels: channelsReducer, channels: channelsReducer,
language: languageReducer,
globalTemplates: globalTemplatesReducer, globalTemplates: globalTemplatesReducer,
boards: boardsReducer, boards: boardsReducer,
views: viewsReducer, views: viewsReducer,

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

@@ -1,46 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {PayloadAction, createAsyncThunk, createSlice} from '@reduxjs/toolkit'
import {getCurrentLanguage, storeLanguage as i18nStoreLanguage} from 'src/i18n'
import {RootState} from './index'
export const fetchLanguage = createAsyncThunk(
'language/fetch',
async () => getCurrentLanguage(),
)
export const storeLanguage = createAsyncThunk(
'language/store',
(lang: string) => {
i18nStoreLanguage(lang)
return lang
},
)
const languageSlice = createSlice({
name: 'language',
initialState: {value: 'en'} as {value: string},
reducers: {
setLanguage: (state, action: PayloadAction<string>) => {
state.value = action.payload
},
},
extraReducers: (builder) => {
builder.addCase(fetchLanguage.fulfilled, (state, action) => {
state.value = action.payload
})
builder.addCase(storeLanguage.fulfilled, (state, action) => {
state.value = action.payload
})
},
})
export const {reducer} = languageSlice
export function getLanguage(state: RootState): string {
return state.language.value
}

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

@@ -8,9 +8,10 @@ import type {Channel, ChannelMembership} from '@mattermost/types/channels'
type ReactResolvable = React.ReactNode | React.ElementType type ReactResolvable = React.ReactNode | React.ElementType
export interface PluginRegistry { export interface PluginRegistry {
registerTranslations(getTranslationsForLocale: (locale: string) => Record<string, string>): void
registerPostTypeComponent(typeName: string, component: ReactResolvable): any registerPostTypeComponent(typeName: string, component: ReactResolvable): any
registerChannelHeaderButtonAction(icon: ReactResolvable, action: () => void, dropdownText: string, tooltipText: string): any registerChannelHeaderButtonAction(icon: ReactResolvable, action: () => void, dropdownText: string, tooltipText: string): any
registerChannelIntroButtonAction(icon: ReactResolvable, action: () => void, tooltipText: string): any registerChannelIntroButtonAction(icon: ReactResolvable, action: () => void, tooltipText: ReactResolvable): any
registerCustomRoute(route: string, component: ReactResolvable): any registerCustomRoute(route: string, component: ReactResolvable): any
registerProductRoute(route: string, component: ReactResolvable): any registerProductRoute(route: string, component: ReactResolvable): any
unregisterComponent(componentId: string): any unregisterComponent(componentId: string): any

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

@@ -25,7 +25,6 @@ const PluggableIntroButtons = React.memo((props: Props) => {
key={buttonProps.id} key={buttonProps.id}
className={'intro-links color--link channelIntroButton style--none'} className={'intro-links color--link channelIntroButton style--none'}
onClick={() => buttonProps.action?.(props.channel, props.channelMember)} onClick={() => buttonProps.action?.(props.channel, props.channelMember)}
aria-label={buttonProps.text}
> >
{buttonProps.icon} {buttonProps.icon}
{buttonProps.text} {buttonProps.text}

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

@@ -208,7 +208,7 @@ export default class PluginRegistry {
// Accepts the following: // Accepts the following:
// - icon - React element to use as the button's icon // - icon - React element to use as the button's icon
// - action - a function called when the button is clicked, passed the channel and channel member as arguments // - action - a function called when the button is clicked, passed the channel and channel member as arguments
// - text - a localized string to use as the button's text // - text - a localized string or React element to use as the button's text
registerChannelIntroButtonAction = reArg([ registerChannelIntroButtonAction = reArg([
'icon', 'icon',
'action', 'action',
@@ -220,8 +220,7 @@ export default class PluginRegistry {
}: { }: {
icon: ReactResolvable; icon: ReactResolvable;
action: PluginComponent['action']; action: PluginComponent['action'];
tooltipText: string; text: ReactResolvable;
text: string;
}) => { }) => {
const id = generateId(); const id = generateId();