@plone/volto 17.0.0-alpha.6 → 17.0.0-alpha.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.yarn/install-state.gz +0 -0
- package/CHANGELOG.md +58 -0
- package/locales/ca/LC_MESSAGES/volto.po +146 -0
- package/locales/ca.json +1 -1
- package/locales/de/LC_MESSAGES/volto.po +146 -0
- package/locales/de.json +1 -1
- package/locales/en/LC_MESSAGES/volto.po +146 -0
- package/locales/en.json +1 -1
- package/locales/es/LC_MESSAGES/volto.po +146 -0
- package/locales/es.json +1 -1
- package/locales/eu/LC_MESSAGES/volto.po +146 -0
- package/locales/eu.json +1 -1
- package/locales/fi/LC_MESSAGES/volto.po +4762 -0
- package/locales/fi.json +1 -1
- package/locales/fr/LC_MESSAGES/volto.po +146 -0
- package/locales/fr.json +1 -1
- package/locales/it/LC_MESSAGES/volto.po +146 -0
- package/locales/it.json +1 -1
- package/locales/ja/LC_MESSAGES/volto.po +146 -0
- package/locales/ja.json +1 -1
- package/locales/nl/LC_MESSAGES/volto.po +801 -643
- package/locales/nl.json +1 -1
- package/locales/pt/LC_MESSAGES/volto.po +146 -0
- package/locales/pt.json +1 -1
- package/locales/pt_BR/LC_MESSAGES/volto.po +146 -0
- package/locales/pt_BR.json +1 -1
- package/locales/ro/LC_MESSAGES/volto.po +146 -0
- package/locales/ro.json +1 -1
- package/locales/volto.pot +147 -1
- package/locales/zh_CN/LC_MESSAGES/volto.po +146 -0
- package/locales/zh_CN.json +1 -1
- package/package.json +1 -1
- package/packages/volto-slate/build/messages/src/blocks/Table/TableBlockEdit.json +1 -1
- package/packages/volto-slate/build/messages/src/blocks/Text/DefaultTextBlockEditor.json +1 -1
- package/packages/volto-slate/build/messages/src/blocks/Text/DetachedTextBlockEditor.json +1 -1
- package/packages/volto-slate/build/messages/src/blocks/Text/SlashMenu.json +1 -1
- package/packages/volto-slate/build/messages/src/editor/plugins/AdvancedLink/index.json +1 -1
- package/packages/volto-slate/build/messages/src/editor/plugins/Link/index.json +1 -1
- package/packages/volto-slate/build/messages/src/editor/plugins/Table/index.json +1 -1
- package/packages/volto-slate/build/messages/src/elementEditor/messages.json +1 -1
- package/packages/volto-slate/build/messages/src/widgets/HtmlSlateWidget.json +1 -1
- package/packages/volto-slate/build/messages/src/widgets/RichTextWidgetView.json +1 -1
- package/packages/volto-slate/package.json +1 -1
- package/packages/volto-slate/src/blocks/Text/SlashMenu.jsx +4 -3
- package/packages/volto-slate/src/editor/deserialize.js +0 -1
- package/razzle.config.js +5 -0
- package/src/actions/index.js +6 -0
- package/src/actions/language/language.js +8 -8
- package/src/actions/relations/rebuild.js +25 -0
- package/src/actions/relations/relations.js +86 -0
- package/src/actions/relations/relations.test.js +15 -0
- package/src/components/index.js +1 -0
- package/src/components/manage/Add/Add.jsx +2 -2
- package/src/components/manage/BlockChooser/BlockChooser.jsx +8 -3
- package/src/components/manage/BlockChooser/BlockChooser.test.jsx +5 -0
- package/src/components/manage/Blocks/Search/components/DateRangeFacet.jsx +4 -1
- package/src/components/manage/Contents/Contents.jsx +5 -1
- package/src/components/manage/Contents/ContentsItem.jsx +6 -0
- package/src/components/manage/Controlpanels/Controlpanels.jsx +9 -0
- package/src/components/manage/Controlpanels/Relations/BrokenRelations.jsx +66 -0
- package/src/components/manage/Controlpanels/Relations/Relations.jsx +114 -0
- package/src/components/manage/Controlpanels/Relations/RelationsListing.jsx +479 -0
- package/src/components/manage/Controlpanels/Relations/RelationsMatrix.jsx +531 -0
- package/src/components/manage/Controlpanels/Users/UserGroupMembershipControlPanel.jsx +3 -3
- package/src/components/manage/Controlpanels/Users/UserGroupMembershipListing.jsx +51 -82
- package/src/components/manage/Controlpanels/Users/UserGroupMembershipMatrix.jsx +79 -75
- package/src/components/manage/Multilingual/CreateTranslation.jsx +2 -2
- package/src/components/manage/Multilingual/TranslationObject.jsx +4 -3
- package/src/components/manage/Preferences/PersonalPreferences.jsx +2 -2
- package/src/components/manage/Toast/Toast.jsx +1 -1
- package/src/components/manage/Toolbar/Types.jsx +2 -2
- package/src/components/manage/Widgets/DatetimeWidget.jsx +9 -5
- package/src/components/manage/Widgets/RecurrenceWidget/ByDayField.jsx +2 -1
- package/src/components/manage/Widgets/RecurrenceWidget/MonthOfTheYearField.jsx +2 -1
- package/src/components/manage/Widgets/RecurrenceWidget/Occurences.jsx +2 -1
- package/src/components/manage/Widgets/RecurrenceWidget/RecurrenceWidget.jsx +7 -2
- package/src/components/manage/Widgets/RecurrenceWidget/WeekdayOfTheMonthField.jsx +2 -1
- package/src/components/theme/Footer/Footer.jsx +2 -13
- package/src/components/theme/LanguageSelector/LanguageSelector.js +8 -3
- package/src/components/theme/Logo/Logo.jsx +2 -1
- package/src/components/theme/MultilingualRedirector/MultilingualRedirector.jsx +2 -2
- package/src/components/theme/Navigation/NavItem.jsx +4 -2
- package/src/components/theme/Sitemap/Sitemap.jsx +5 -3
- package/src/components/theme/View/EventDatesInfo.jsx +2 -1
- package/src/components/theme/Widgets/DateWidget.jsx +2 -1
- package/src/components/theme/Widgets/DatetimeWidget.jsx +2 -1
- package/src/components/theme/Widgets/RelationsWidget.jsx +13 -11
- package/src/config/ControlPanels.js +2 -0
- package/src/constants/ActionTypes.js +4 -0
- package/src/constants/Languages.js +8 -4
- package/src/helpers/Html/Html.jsx +3 -1
- package/src/helpers/Html/Html.test.jsx +5 -0
- package/src/helpers/MessageLabels/MessageLabels.js +72 -0
- package/src/helpers/Utils/Utils.js +21 -9
- package/src/helpers/Utils/Utils.test.js +4 -4
- package/src/helpers/index.js +5 -2
- package/src/middleware/api.js +7 -3
- package/src/reducers/actions/actions.js +1 -1
- package/src/reducers/breadcrumbs/breadcrumbs.js +1 -1
- package/src/reducers/index.js +2 -0
- package/src/reducers/navigation/navigation.js +1 -1
- package/src/reducers/relations/relations.js +173 -0
- package/src/reducers/types/types.js +1 -1
- package/src/routes.js +5 -0
- package/src/server.jsx +28 -23
- package/theme/themes/pastanaga/extras/userscontrolpanel.less +99 -76
- package/.changelog.draft +0 -33
- package/.editorconfig +0 -36
- package/.storybook/main.js +0 -127
- package/.storybook/manager.js +0 -15
- package/.storybook/preview.js +0 -21
- package/.storybook/static/previewImage.svg +0 -48
- package/.vale.ini +0 -10
- package/.yarnrc.yml +0 -5
- package/jsdoc.json +0 -16
- package/netlify.toml +0 -5
- package/pyvenv.cfg +0 -3
- package/share/man/man1/ttx.1 +0 -225
- package/styles/Vocab/Base/accept.txt +0 -0
- package/styles/Vocab/Base/reject.txt +0 -0
- package/styles/Vocab/Plone/accept.txt +0 -10
- package/styles/Vocab/Plone/reject.txt +0 -5
- package/towncrier.toml +0 -33
|
@@ -8,6 +8,7 @@ import { Image } from 'semantic-ui-react';
|
|
|
8
8
|
import { useSelector } from 'react-redux';
|
|
9
9
|
import config from '@plone/volto/registry';
|
|
10
10
|
import { UniversalLink } from '@plone/volto/components';
|
|
11
|
+
import { toBackendLang } from '@plone/volto/helpers';
|
|
11
12
|
import LogoImage from '@plone/volto/components/theme/Logo/Logo.svg';
|
|
12
13
|
|
|
13
14
|
const messages = defineMessages({
|
|
@@ -34,7 +35,7 @@ const Logo = () => {
|
|
|
34
35
|
|
|
35
36
|
return (
|
|
36
37
|
<UniversalLink
|
|
37
|
-
href={settings.isMultilingual ? `/${lang}` : '/'}
|
|
38
|
+
href={settings.isMultilingual ? `/${toBackendLang(lang)}` : '/'}
|
|
38
39
|
title={intl.formatMessage(messages.site)}
|
|
39
40
|
>
|
|
40
41
|
<Image
|
|
@@ -4,7 +4,7 @@ import { useDispatch } from 'react-redux';
|
|
|
4
4
|
import { useCookies } from 'react-cookie';
|
|
5
5
|
import config from '@plone/volto/registry';
|
|
6
6
|
import { changeLanguage } from '@plone/volto/actions';
|
|
7
|
-
import {
|
|
7
|
+
import { toGettextLang } from '@plone/volto/helpers';
|
|
8
8
|
|
|
9
9
|
const MultilingualRedirector = (props) => {
|
|
10
10
|
const { settings } = config;
|
|
@@ -23,7 +23,7 @@ const MultilingualRedirector = (props) => {
|
|
|
23
23
|
// const detectedLang = (navigator.language || navigator.userLanguage).substring(0, 2);
|
|
24
24
|
let mounted = true;
|
|
25
25
|
if (settings.isMultilingual && pathname === '/') {
|
|
26
|
-
const langFileName =
|
|
26
|
+
const langFileName = toGettextLang(redirectToLanguage);
|
|
27
27
|
import('@root/../locales/' + langFileName + '.json').then((locale) => {
|
|
28
28
|
if (mounted) {
|
|
29
29
|
dispatch(changeLanguage(redirectToLanguage, locale.default));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { NavLink } from 'react-router-dom';
|
|
3
|
-
import { isInternalURL } from '@plone/volto/helpers';
|
|
3
|
+
import { isInternalURL, toBackendLang } from '@plone/volto/helpers';
|
|
4
4
|
import config from '@plone/volto/registry';
|
|
5
5
|
|
|
6
6
|
const NavItem = ({ item, lang }) => {
|
|
@@ -15,7 +15,9 @@ const NavItem = ({ item, lang }) => {
|
|
|
15
15
|
className="item"
|
|
16
16
|
activeClassName="active"
|
|
17
17
|
exact={
|
|
18
|
-
settings.isMultilingual
|
|
18
|
+
settings.isMultilingual
|
|
19
|
+
? item.url === `/${toBackendLang(lang)}`
|
|
20
|
+
: item.url === ''
|
|
19
21
|
}
|
|
20
22
|
>
|
|
21
23
|
{item.title}
|
|
@@ -10,7 +10,7 @@ import { connect } from 'react-redux';
|
|
|
10
10
|
import { asyncConnect } from '@plone/volto/helpers';
|
|
11
11
|
import { defineMessages, injectIntl } from 'react-intl';
|
|
12
12
|
import { Container } from 'semantic-ui-react';
|
|
13
|
-
import { Helmet } from '@plone/volto/helpers';
|
|
13
|
+
import { Helmet, toBackendLang } from '@plone/volto/helpers';
|
|
14
14
|
import { Link } from 'react-router-dom';
|
|
15
15
|
import config from '@plone/volto/registry';
|
|
16
16
|
|
|
@@ -40,7 +40,7 @@ class Sitemap extends Component {
|
|
|
40
40
|
componentDidMount() {
|
|
41
41
|
const { settings } = config;
|
|
42
42
|
if (settings.isMultilingual) {
|
|
43
|
-
this.props.getNavigation(`${this.props.lang}`, 4);
|
|
43
|
+
this.props.getNavigation(`${toBackendLang(this.props.lang)}`, 4);
|
|
44
44
|
} else {
|
|
45
45
|
this.props.getNavigation('', 4);
|
|
46
46
|
}
|
|
@@ -108,7 +108,9 @@ export default compose(
|
|
|
108
108
|
const { settings } = config;
|
|
109
109
|
const lang = getState().intl.locale;
|
|
110
110
|
if (settings.isMultilingual) {
|
|
111
|
-
return
|
|
111
|
+
return (
|
|
112
|
+
__SERVER__ && dispatch(getNavigation(`${toBackendLang(lang)}`, 4))
|
|
113
|
+
);
|
|
112
114
|
} else {
|
|
113
115
|
return __SERVER__ && dispatch(getNavigation('', 4));
|
|
114
116
|
}
|
|
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
|
|
|
3
3
|
import { List } from 'semantic-ui-react';
|
|
4
4
|
import cx from 'classnames';
|
|
5
5
|
|
|
6
|
+
import { toBackendLang } from '@plone/volto/helpers';
|
|
6
7
|
import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
|
|
7
8
|
import { useSelector } from 'react-redux';
|
|
8
9
|
|
|
@@ -28,7 +29,7 @@ const When_ = ({ start, end, whole_day, open_end, moment: momentlib }) => {
|
|
|
28
29
|
const lang = useSelector((state) => state.intl.locale);
|
|
29
30
|
|
|
30
31
|
const moment = momentlib.default;
|
|
31
|
-
moment.locale(lang);
|
|
32
|
+
moment.locale(toBackendLang(lang));
|
|
32
33
|
|
|
33
34
|
const datesInfo = datesForDisplay(start, end, moment);
|
|
34
35
|
if (!datesInfo) {
|
|
@@ -2,10 +2,11 @@ import React from 'react';
|
|
|
2
2
|
import cx from 'classnames';
|
|
3
3
|
import moment from 'moment';
|
|
4
4
|
import { useSelector } from 'react-redux';
|
|
5
|
+
import { toBackendLang } from '@plone/volto/helpers';
|
|
5
6
|
|
|
6
7
|
const DateWidget = ({ value, children, className, format = 'll' }) => {
|
|
7
8
|
const lang = useSelector((state) => state.intl.locale);
|
|
8
|
-
moment.locale(lang);
|
|
9
|
+
moment.locale(toBackendLang(lang));
|
|
9
10
|
return value ? (
|
|
10
11
|
<span className={cx(className, 'date', 'widget')}>
|
|
11
12
|
{children
|
|
@@ -2,10 +2,11 @@ import React from 'react';
|
|
|
2
2
|
import cx from 'classnames';
|
|
3
3
|
import moment from 'moment';
|
|
4
4
|
import { useSelector } from 'react-redux';
|
|
5
|
+
import { toBackendLang } from '@plone/volto/helpers';
|
|
5
6
|
|
|
6
7
|
const DatetimeWidget = ({ value, children, className, format = 'lll' }) => {
|
|
7
8
|
const lang = useSelector((state) => state.intl.locale);
|
|
8
|
-
moment.locale(lang);
|
|
9
|
+
moment.locale(toBackendLang(lang));
|
|
9
10
|
return value ? (
|
|
10
11
|
<span className={cx(className, 'datetime', 'widget')}>
|
|
11
12
|
{children
|
|
@@ -5,17 +5,19 @@ import RelationWidget from './RelationWidget';
|
|
|
5
5
|
const RelationsWidget = ({ value, children, className }) =>
|
|
6
6
|
value ? (
|
|
7
7
|
<ul className={cx(className, 'relations', 'widget')}>
|
|
8
|
-
{value.map((item, key) =>
|
|
9
|
-
|
|
10
|
-
<
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
8
|
+
{value.map((item, key) => {
|
|
9
|
+
return item ? (
|
|
10
|
+
<li key={key}>
|
|
11
|
+
<RelationWidget
|
|
12
|
+
value={item || `relation target not found '${key}'`}
|
|
13
|
+
className={className}
|
|
14
|
+
key={item.token || item.title || item}
|
|
15
|
+
>
|
|
16
|
+
{children}
|
|
17
|
+
</RelationWidget>
|
|
18
|
+
</li>
|
|
19
|
+
) : null;
|
|
20
|
+
})}
|
|
19
21
|
</ul>
|
|
20
22
|
) : (
|
|
21
23
|
''
|
|
@@ -18,6 +18,7 @@ import settingsSVG from '@plone/volto/icons/settings.svg';
|
|
|
18
18
|
import rulesSVG from '@plone/volto/icons/content-existing.svg';
|
|
19
19
|
import undoControlPanelSVG from '@plone/volto/icons/undo-control-panel.svg';
|
|
20
20
|
import linkSVG from '@plone/volto/icons/link.svg';
|
|
21
|
+
import relationsSVG from '@plone/volto/icons/ahead.svg';
|
|
21
22
|
|
|
22
23
|
export const controlPanelsIcons = {
|
|
23
24
|
default: settingsSVG,
|
|
@@ -40,6 +41,7 @@ export const controlPanelsIcons = {
|
|
|
40
41
|
rules: rulesSVG,
|
|
41
42
|
undo: undoControlPanelSVG,
|
|
42
43
|
aliases: linkSVG,
|
|
44
|
+
relations: relationsSVG,
|
|
43
45
|
};
|
|
44
46
|
|
|
45
47
|
export const filterControlPanels = (controlpanels) => {
|
|
@@ -36,6 +36,10 @@ export const GET_NAVIGATION = 'GET_NAVIGATION';
|
|
|
36
36
|
export const GET_PRINCIPALS = 'GET_PRINCIPALS';
|
|
37
37
|
export const GET_QUERYSTRING = 'GET_QUERYSTRING';
|
|
38
38
|
export const GET_QUERYSTRING_RESULTS = 'GET_QUERYSTRING_RESULTS';
|
|
39
|
+
export const CREATE_RELATIONS = 'CREATE_RELATIONS';
|
|
40
|
+
export const DELETE_RELATIONS = 'DELETE_RELATIONS';
|
|
41
|
+
export const LIST_RELATIONS = 'LIST_RELATIONS';
|
|
42
|
+
export const REBUILD_RELATIONS = 'REBUILD_RELATIONS';
|
|
39
43
|
export const GET_SCHEMA = 'GET_SCHEMA';
|
|
40
44
|
export const POST_SCHEMA = 'POST_SCHEMA';
|
|
41
45
|
export const PUT_SCHEMA = 'PUT_SCHEMA';
|
|
@@ -4,14 +4,18 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
module.exports = {
|
|
7
|
-
|
|
7
|
+
ca: 'Català',
|
|
8
8
|
de: 'Deutsch',
|
|
9
|
+
en: 'English',
|
|
10
|
+
es: 'Español',
|
|
11
|
+
eu: 'Euskara',
|
|
12
|
+
fi: 'Suomi',
|
|
13
|
+
fr: 'Français',
|
|
14
|
+
it: 'Italiano',
|
|
9
15
|
nl: 'Nederlands',
|
|
10
16
|
ro: 'Română',
|
|
11
17
|
ja: '日本語',
|
|
12
18
|
pt: 'Português',
|
|
13
19
|
pt_BR: 'Português (Brasil)',
|
|
14
|
-
|
|
15
|
-
it: 'Italian',
|
|
16
|
-
eu: 'Euskara',
|
|
20
|
+
zh_CN: '中文',
|
|
17
21
|
};
|
|
@@ -97,8 +97,10 @@ class Html extends Component {
|
|
|
97
97
|
} = this.props;
|
|
98
98
|
const head = Helmet.rewind();
|
|
99
99
|
const bodyClass = join(BodyClass.rewind(), ' ');
|
|
100
|
+
const htmlAttributes = head.htmlAttributes.toComponent();
|
|
101
|
+
|
|
100
102
|
return (
|
|
101
|
-
<html lang=
|
|
103
|
+
<html lang={htmlAttributes.lang}>
|
|
102
104
|
<head>
|
|
103
105
|
<meta charSet="utf-8" />
|
|
104
106
|
{head.base.toComponent()}
|
|
@@ -260,4 +260,76 @@ export const messages = defineMessages({
|
|
|
260
260
|
id: 'Show groups of users below',
|
|
261
261
|
defaultMessage: 'Show groups of users below',
|
|
262
262
|
},
|
|
263
|
+
inspectRelations: {
|
|
264
|
+
id: 'Inspect relations',
|
|
265
|
+
defaultMessage: 'Inspect relations',
|
|
266
|
+
},
|
|
267
|
+
relations: {
|
|
268
|
+
id: 'Relations',
|
|
269
|
+
defaultMessage: 'Relations',
|
|
270
|
+
},
|
|
271
|
+
fixRelations: {
|
|
272
|
+
id: 'Fix relations',
|
|
273
|
+
defaultMessage: 'Fix relations',
|
|
274
|
+
},
|
|
275
|
+
searchRelationSource: {
|
|
276
|
+
id: 'Search sources by title or path',
|
|
277
|
+
defaultMessage: 'Search sources by title or path',
|
|
278
|
+
},
|
|
279
|
+
searchRelationTarget: {
|
|
280
|
+
id: 'Search targets by title or path',
|
|
281
|
+
defaultMessage: 'Search targets by title or path',
|
|
282
|
+
},
|
|
283
|
+
createOrDeleteRelationsToTarget: {
|
|
284
|
+
id: 'Create or delete relations to target',
|
|
285
|
+
defaultMessage: 'Create or delete relations to target',
|
|
286
|
+
},
|
|
287
|
+
relationName: {
|
|
288
|
+
id: 'Relation name',
|
|
289
|
+
defaultMessage: 'relation',
|
|
290
|
+
},
|
|
291
|
+
selectRelation: {
|
|
292
|
+
id: 'Select relation',
|
|
293
|
+
defaultMessage: 'Select relation',
|
|
294
|
+
},
|
|
295
|
+
norelationfound: {
|
|
296
|
+
id: 'No relation found',
|
|
297
|
+
defaultMessage: 'No relation found',
|
|
298
|
+
},
|
|
299
|
+
toomanyrelationsfound: {
|
|
300
|
+
id: 'Many relations found. Please search.',
|
|
301
|
+
defaultMessage: 'Many relations found. Please search.',
|
|
302
|
+
},
|
|
303
|
+
rebuildRelations: {
|
|
304
|
+
id: 'rebuild relations',
|
|
305
|
+
defaultMessage: 'rebuild relations',
|
|
306
|
+
},
|
|
307
|
+
flushAndRebuildRelations: {
|
|
308
|
+
id: 'flush intIds and rebuild relations',
|
|
309
|
+
defaultMessage: 'flush intIds and rebuild relations',
|
|
310
|
+
},
|
|
311
|
+
addPotentialTargetsPath: {
|
|
312
|
+
id: 'target path',
|
|
313
|
+
defaultMessage: 'target path',
|
|
314
|
+
},
|
|
315
|
+
addPotentialSourcesPath: {
|
|
316
|
+
id: 'sources path',
|
|
317
|
+
defaultMessage: 'sources path',
|
|
318
|
+
},
|
|
319
|
+
relationsUpdated: {
|
|
320
|
+
id: 'Relations updated',
|
|
321
|
+
defaultMessage: 'Relations updated',
|
|
322
|
+
},
|
|
323
|
+
select: {
|
|
324
|
+
id: 'Select',
|
|
325
|
+
defaultMessage: 'Select',
|
|
326
|
+
},
|
|
327
|
+
selected: {
|
|
328
|
+
id: 'Selected',
|
|
329
|
+
defaultMessage: 'Selected',
|
|
330
|
+
},
|
|
331
|
+
filter: {
|
|
332
|
+
id: 'Filter',
|
|
333
|
+
defaultMessage: 'Filter',
|
|
334
|
+
},
|
|
263
335
|
});
|
|
@@ -174,13 +174,13 @@ export const parseDateTime = (locale, value, format, moment) => {
|
|
|
174
174
|
};
|
|
175
175
|
|
|
176
176
|
/**
|
|
177
|
-
* Converts a language code to the format `lang_region`
|
|
177
|
+
* Converts a language code like pt-br to the format `pt_BR` (`lang_region`)
|
|
178
178
|
* Useful for passing from Plone's i18n lang names to Xnix locale names
|
|
179
|
-
* eg. LC_MESSAGES/lang_region.po filenames
|
|
179
|
+
* eg. LC_MESSAGES/lang_region.po filenames. Also used in the I18N_LANGUAGE cookie.
|
|
180
180
|
* @param {string} language Language to be converted
|
|
181
181
|
* @returns {string} Language converted
|
|
182
182
|
*/
|
|
183
|
-
export const
|
|
183
|
+
export const toGettextLang = (language) => {
|
|
184
184
|
if (language.includes('-')) {
|
|
185
185
|
let normalizedLang = language.split('-');
|
|
186
186
|
normalizedLang = `${normalizedLang[0]}_${normalizedLang[1].toUpperCase()}`;
|
|
@@ -189,23 +189,35 @@ export const normalizeLanguageName = (language) => {
|
|
|
189
189
|
|
|
190
190
|
return language;
|
|
191
191
|
};
|
|
192
|
+
export const normalizeLanguageName = toGettextLang;
|
|
192
193
|
|
|
193
194
|
/**
|
|
194
|
-
* Converts a language code to the format `
|
|
195
|
-
* `react-intl` only supports this syntax
|
|
196
|
-
*
|
|
195
|
+
* Converts a language code like pt-br or pt_BR to the format `pt-BR`.
|
|
196
|
+
* `react-intl` only supports this syntax. We also use it for the locales
|
|
197
|
+
* in the volto Redux store.
|
|
197
198
|
* @param {string} language Language to be converted
|
|
198
199
|
* @returns {string} Language converted
|
|
199
200
|
*/
|
|
200
|
-
export const
|
|
201
|
-
if (language.includes('_')) {
|
|
202
|
-
let langCode = language.split(
|
|
201
|
+
export const toReactIntlLang = (language) => {
|
|
202
|
+
if (language.includes('_') || language.includes('-')) {
|
|
203
|
+
let langCode = language.split(/[-_]/);
|
|
203
204
|
langCode = `${langCode[0]}-${langCode[1].toUpperCase()}`;
|
|
204
205
|
return langCode;
|
|
205
206
|
}
|
|
206
207
|
|
|
207
208
|
return language;
|
|
208
209
|
};
|
|
210
|
+
export const toLangUnderscoreRegion = toReactIntlLang; // old name for backwards-compat
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Converts a language code like pt_BR or pt-BR to the format `pt-br`.
|
|
214
|
+
* This format is used on the backend and in volto config settings.
|
|
215
|
+
* @param {string} language Language to be converted
|
|
216
|
+
* @returns {string} Language converted
|
|
217
|
+
*/
|
|
218
|
+
export const toBackendLang = (language) => {
|
|
219
|
+
return toReactIntlLang(language).toLowerCase();
|
|
220
|
+
};
|
|
209
221
|
|
|
210
222
|
/**
|
|
211
223
|
* Lookup if a given expander is set in apiExpanders for the given path and action type
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
getColor,
|
|
7
7
|
getInitials,
|
|
8
8
|
hasApiExpander,
|
|
9
|
-
|
|
9
|
+
toGettextLang,
|
|
10
10
|
parseDateTime,
|
|
11
11
|
removeFromArray,
|
|
12
12
|
reorderArray,
|
|
@@ -284,12 +284,12 @@ describe('Utils tests', () => {
|
|
|
284
284
|
});
|
|
285
285
|
});
|
|
286
286
|
|
|
287
|
-
describe('
|
|
287
|
+
describe('toGettextLang', () => {
|
|
288
288
|
it('Normalizes an extended language (pt_BR)', () => {
|
|
289
|
-
expect(
|
|
289
|
+
expect(toGettextLang('pt-br')).toStrictEqual('pt_BR');
|
|
290
290
|
});
|
|
291
291
|
it('Normalizes a simple language (ca)', () => {
|
|
292
|
-
expect(
|
|
292
|
+
expect(toGettextLang('ca')).toStrictEqual('ca');
|
|
293
293
|
});
|
|
294
294
|
});
|
|
295
295
|
|
package/src/helpers/index.js
CHANGED
|
@@ -80,8 +80,11 @@ export {
|
|
|
80
80
|
applyConfig,
|
|
81
81
|
withServerErrorCode,
|
|
82
82
|
parseDateTime,
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
toGettextLang,
|
|
84
|
+
normalizeLanguageName, // old name for toGettextLang
|
|
85
|
+
toReactIntlLang,
|
|
86
|
+
toLangUnderscoreRegion, // old name for toReactIntlLang
|
|
87
|
+
toBackendLang,
|
|
85
88
|
hasApiExpander,
|
|
86
89
|
replaceItemOfArray,
|
|
87
90
|
cloneDeepSchema,
|
package/src/middleware/api.js
CHANGED
|
@@ -18,7 +18,11 @@ import {
|
|
|
18
18
|
SET_APIERROR,
|
|
19
19
|
} from '@plone/volto/constants/ActionTypes';
|
|
20
20
|
import { changeLanguage } from '@plone/volto/actions';
|
|
21
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
toGettextLang,
|
|
23
|
+
toReactIntlLang,
|
|
24
|
+
getCookieOptions,
|
|
25
|
+
} from '@plone/volto/helpers';
|
|
22
26
|
let socket = null;
|
|
23
27
|
|
|
24
28
|
/**
|
|
@@ -205,11 +209,11 @@ const apiMiddlewareFactory = (api) => ({ dispatch, getState }) => (next) => (
|
|
|
205
209
|
const lang = result?.language?.token;
|
|
206
210
|
if (
|
|
207
211
|
lang &&
|
|
208
|
-
getState().intl.
|
|
212
|
+
getState().intl.locale !== toReactIntlLang(lang) &&
|
|
209
213
|
!subrequest &&
|
|
210
214
|
config.settings.supportedLanguages.includes(lang)
|
|
211
215
|
) {
|
|
212
|
-
const langFileName =
|
|
216
|
+
const langFileName = toGettextLang(lang);
|
|
213
217
|
import('~/../locales/' + langFileName + '.json').then((locale) => {
|
|
214
218
|
dispatch(changeLanguage(lang, locale.default));
|
|
215
219
|
});
|
package/src/reducers/index.js
CHANGED
|
@@ -25,6 +25,7 @@ import messages from '@plone/volto/reducers/messages/messages';
|
|
|
25
25
|
import navigation from '@plone/volto/reducers/navigation/navigation';
|
|
26
26
|
import querystring from '@plone/volto/reducers/querystring/querystring';
|
|
27
27
|
import querystringsearch from '@plone/volto/reducers/querystringsearch/querystringsearch';
|
|
28
|
+
import relations from '@plone/volto/reducers/relations/relations';
|
|
28
29
|
import roles from '@plone/volto/reducers/roles/roles';
|
|
29
30
|
import rules from '@plone/volto/reducers/rules/rules';
|
|
30
31
|
import controlpanelrule from '@plone/volto/reducers/controlPanelRule/controlPanelRule';
|
|
@@ -80,6 +81,7 @@ const reducers = {
|
|
|
80
81
|
navigation,
|
|
81
82
|
querystring,
|
|
82
83
|
querystringsearch,
|
|
84
|
+
relations,
|
|
83
85
|
roles,
|
|
84
86
|
rules,
|
|
85
87
|
controlpanelrule,
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relations reducer.
|
|
3
|
+
* @module reducers/relations/relations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
CREATE_RELATIONS,
|
|
8
|
+
DELETE_RELATIONS,
|
|
9
|
+
LIST_RELATIONS,
|
|
10
|
+
REBUILD_RELATIONS,
|
|
11
|
+
} from '@plone/volto/constants/ActionTypes';
|
|
12
|
+
|
|
13
|
+
const initialState = {
|
|
14
|
+
relations: null,
|
|
15
|
+
stats: null,
|
|
16
|
+
create: {
|
|
17
|
+
error: null,
|
|
18
|
+
loaded: false,
|
|
19
|
+
loading: false,
|
|
20
|
+
},
|
|
21
|
+
delete: {
|
|
22
|
+
error: null,
|
|
23
|
+
loaded: false,
|
|
24
|
+
loading: false,
|
|
25
|
+
},
|
|
26
|
+
list: {
|
|
27
|
+
error: null,
|
|
28
|
+
loaded: false,
|
|
29
|
+
loading: false,
|
|
30
|
+
},
|
|
31
|
+
rebuild: {
|
|
32
|
+
error: null,
|
|
33
|
+
loaded: false,
|
|
34
|
+
loading: false,
|
|
35
|
+
},
|
|
36
|
+
subrequests: {},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get request key
|
|
41
|
+
* @function getRequestKey
|
|
42
|
+
* @param {string} actionType Action type.
|
|
43
|
+
* @returns {string} Request key.
|
|
44
|
+
*/
|
|
45
|
+
function getRequestKey(actionType) {
|
|
46
|
+
return actionType.split('_')[0].toLowerCase();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Relations reducer.
|
|
51
|
+
* @function relations
|
|
52
|
+
* @param {Object} state Current state.
|
|
53
|
+
* @param {Object} action Action to be handled.
|
|
54
|
+
* @returns {Object} New state.
|
|
55
|
+
*/
|
|
56
|
+
export default function relations(state = initialState, action = {}) {
|
|
57
|
+
switch (action.type) {
|
|
58
|
+
case `${CREATE_RELATIONS}_PENDING`:
|
|
59
|
+
case `${DELETE_RELATIONS}_PENDING`:
|
|
60
|
+
case `${REBUILD_RELATIONS}_PENDING`:
|
|
61
|
+
return {
|
|
62
|
+
...state,
|
|
63
|
+
[getRequestKey(action.type)]: {
|
|
64
|
+
loading: true,
|
|
65
|
+
loaded: false,
|
|
66
|
+
error: null,
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
case `${LIST_RELATIONS}_PENDING`:
|
|
70
|
+
return action.subrequest
|
|
71
|
+
? {
|
|
72
|
+
...state,
|
|
73
|
+
subrequests: {
|
|
74
|
+
...state.subrequests,
|
|
75
|
+
[action.subrequest]: {
|
|
76
|
+
...(state.subrequests[action.subrequest] || {
|
|
77
|
+
relations: null,
|
|
78
|
+
stats: null,
|
|
79
|
+
}),
|
|
80
|
+
loaded: false,
|
|
81
|
+
loading: true,
|
|
82
|
+
error: null,
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
}
|
|
86
|
+
: {
|
|
87
|
+
...state,
|
|
88
|
+
[getRequestKey(action.type)]: {
|
|
89
|
+
loading: true,
|
|
90
|
+
loaded: false,
|
|
91
|
+
error: null,
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
case `${LIST_RELATIONS}_SUCCESS`:
|
|
95
|
+
return action.subrequest
|
|
96
|
+
? {
|
|
97
|
+
...state,
|
|
98
|
+
subrequests: {
|
|
99
|
+
...state.subrequests,
|
|
100
|
+
[action.subrequest]: {
|
|
101
|
+
loading: false,
|
|
102
|
+
loaded: true,
|
|
103
|
+
error: null,
|
|
104
|
+
relations: action.result.relations
|
|
105
|
+
? action.result.relations
|
|
106
|
+
: state.relations,
|
|
107
|
+
stats: null,
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
}
|
|
111
|
+
: {
|
|
112
|
+
...state,
|
|
113
|
+
relations: action.result.relations
|
|
114
|
+
? action.result.relations
|
|
115
|
+
: state.relations,
|
|
116
|
+
stats: action.result.stats ? action.result : state.stats,
|
|
117
|
+
[getRequestKey(action.type)]: {
|
|
118
|
+
loading: false,
|
|
119
|
+
loaded: true,
|
|
120
|
+
error: null,
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
case `${CREATE_RELATIONS}_SUCCESS`:
|
|
124
|
+
case `${DELETE_RELATIONS}_SUCCESS`:
|
|
125
|
+
case `${REBUILD_RELATIONS}_SUCCESS`:
|
|
126
|
+
return {
|
|
127
|
+
...state,
|
|
128
|
+
[getRequestKey(action.type)]: {
|
|
129
|
+
loading: false,
|
|
130
|
+
loaded: true,
|
|
131
|
+
error: null,
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
case `${LIST_RELATIONS}_FAIL`:
|
|
135
|
+
return action.subrequest
|
|
136
|
+
? {
|
|
137
|
+
...state,
|
|
138
|
+
subrequests: {
|
|
139
|
+
...state.subrequests,
|
|
140
|
+
[action.subrequest]: {
|
|
141
|
+
relations: null,
|
|
142
|
+
stats: null,
|
|
143
|
+
loading: false,
|
|
144
|
+
loaded: false,
|
|
145
|
+
error: action.error,
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
}
|
|
149
|
+
: {
|
|
150
|
+
...state,
|
|
151
|
+
relations: null,
|
|
152
|
+
stats: null,
|
|
153
|
+
[getRequestKey(action.type)]: {
|
|
154
|
+
loading: false,
|
|
155
|
+
loaded: false,
|
|
156
|
+
error: action.error,
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
case `${CREATE_RELATIONS}_FAIL`:
|
|
160
|
+
case `${DELETE_RELATIONS}_FAIL`:
|
|
161
|
+
case `${REBUILD_RELATIONS}_FAIL`:
|
|
162
|
+
return {
|
|
163
|
+
...state,
|
|
164
|
+
[getRequestKey(action.type)]: {
|
|
165
|
+
loading: false,
|
|
166
|
+
loaded: false,
|
|
167
|
+
error: action.error,
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
default:
|
|
171
|
+
return state;
|
|
172
|
+
}
|
|
173
|
+
}
|