@plone/volto 17.0.0-alpha.5 → 17.0.0-alpha.7
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 +91 -13
- package/CONTRIBUTING.md +1 -1
- package/README.md +4 -4
- package/locales/de/LC_MESSAGES/volto.po +17 -17
- package/locales/de.json +1 -1
- package/package.json +3 -2
- package/packages/volto-slate/package.json +1 -1
- package/src/actions/language/language.js +8 -8
- package/src/components/manage/Add/Add.jsx +2 -2
- package/src/components/manage/Blocks/Listing/Edit.jsx +0 -14
- package/src/components/manage/Blocks/Listing/getAsyncData.js +10 -2
- package/src/components/manage/Blocks/Listing/withQuerystringResults.jsx +18 -13
- package/src/components/manage/Blocks/Search/SearchBlockView.jsx +2 -1
- package/src/components/manage/Blocks/Search/components/DateRangeFacet.jsx +4 -1
- package/src/components/manage/Contents/Contents.jsx +16 -14
- package/src/components/manage/Controlpanels/Controlpanels.jsx +190 -224
- package/src/components/manage/Controlpanels/Controlpanels.test.jsx +46 -7
- package/src/components/manage/Form/InlineForm.jsx +39 -9
- package/src/components/manage/Form/InlineFormState.js +8 -0
- 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/Toolbar/Types.jsx +2 -2
- package/src/components/manage/Widgets/DatetimeWidget.jsx +9 -5
- package/src/components/manage/Widgets/ObjectListWidget.jsx +3 -8
- 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/Icon/Icon.jsx +2 -2
- package/src/components/theme/LanguageSelector/LanguageSelector.js +8 -3
- package/src/components/theme/Login/Login.jsx +1 -0
- 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/config/index.js +1 -0
- package/src/helpers/Robots/Robots.js +16 -1
- package/src/helpers/Url/Url.js +8 -3
- package/src/helpers/Url/Url.test.js +14 -0
- package/src/helpers/Utils/Utils.js +38 -13
- package/src/helpers/Utils/Utils.test.js +4 -4
- package/src/helpers/index.js +7 -2
- package/src/middleware/Api.test.js +54 -0
- package/src/middleware/api.js +8 -4
- package/src/server.jsx +28 -23
- package/test-setup-config.js +1 -0
- package/theme/themes/pastanaga/extras/sidebar.less +4 -0
- package/.changelog.draft +0 -13
- 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
|
@@ -15,7 +15,8 @@ import {
|
|
|
15
15
|
Api,
|
|
16
16
|
flattenToAppURL,
|
|
17
17
|
langmap,
|
|
18
|
-
|
|
18
|
+
toGettextLang,
|
|
19
|
+
toReactIntlLang,
|
|
19
20
|
} from '@plone/volto/helpers';
|
|
20
21
|
import { createBrowserHistory } from 'history';
|
|
21
22
|
const messages = defineMessages({
|
|
@@ -55,9 +56,9 @@ const TranslationObject = ({
|
|
|
55
56
|
setLoadingLocale(true);
|
|
56
57
|
let lang =
|
|
57
58
|
config.settings.supportedLanguages[Object.keys(locales).length];
|
|
58
|
-
const langFileName =
|
|
59
|
+
const langFileName = toGettextLang(lang);
|
|
59
60
|
import('@root/../locales/' + langFileName + '.json').then((locale) => {
|
|
60
|
-
setLocales({ ...locales, [lang]: locale.default });
|
|
61
|
+
setLocales({ ...locales, [toReactIntlLang(lang)]: locale.default });
|
|
61
62
|
setLoadingLocale(false);
|
|
62
63
|
});
|
|
63
64
|
}
|
|
@@ -15,7 +15,7 @@ import { toast } from 'react-toastify';
|
|
|
15
15
|
import { Form, Toast } from '@plone/volto/components';
|
|
16
16
|
import languages from '@plone/volto/constants/Languages';
|
|
17
17
|
import { changeLanguage } from '@plone/volto/actions';
|
|
18
|
-
import {
|
|
18
|
+
import { toGettextLang } from '@plone/volto/helpers';
|
|
19
19
|
import config from '@plone/volto/registry';
|
|
20
20
|
|
|
21
21
|
const messages = defineMessages({
|
|
@@ -86,7 +86,7 @@ class PersonalPreferences extends Component {
|
|
|
86
86
|
onSubmit(data) {
|
|
87
87
|
let language = data.language || 'en';
|
|
88
88
|
if (config.settings.supportedLanguages.includes(language)) {
|
|
89
|
-
const langFileName =
|
|
89
|
+
const langFileName = toGettextLang(language);
|
|
90
90
|
import('@root/../locales/' + langFileName + '.json').then((locale) => {
|
|
91
91
|
this.props.changeLanguage(language, locale.default);
|
|
92
92
|
});
|
|
@@ -4,7 +4,7 @@ import { connect } from 'react-redux';
|
|
|
4
4
|
import { Link } from 'react-router-dom';
|
|
5
5
|
import { filter, find, isEmpty, map } from 'lodash';
|
|
6
6
|
import { FormattedMessage } from 'react-intl';
|
|
7
|
-
import { flattenToAppURL, langmap } from '@plone/volto/helpers';
|
|
7
|
+
import { flattenToAppURL, langmap, toBackendLang } from '@plone/volto/helpers';
|
|
8
8
|
import config from '@plone/volto/registry';
|
|
9
9
|
|
|
10
10
|
const Types = ({ types, pathname, content, currentLanguage }) => {
|
|
@@ -59,7 +59,7 @@ const Types = ({ types, pathname, content, currentLanguage }) => {
|
|
|
59
59
|
find(content['@components'].translations.items, {
|
|
60
60
|
language: lang,
|
|
61
61
|
}),
|
|
62
|
-
) && currentLanguage !== lang,
|
|
62
|
+
) && toBackendLang(currentLanguage) !== lang,
|
|
63
63
|
);
|
|
64
64
|
|
|
65
65
|
return (
|
|
@@ -10,7 +10,7 @@ import { connect } from 'react-redux';
|
|
|
10
10
|
import loadable from '@loadable/component';
|
|
11
11
|
import cx from 'classnames';
|
|
12
12
|
import { Icon, FormFieldWrapper } from '@plone/volto/components';
|
|
13
|
-
import { parseDateTime } from '@plone/volto/helpers';
|
|
13
|
+
import { parseDateTime, toBackendLang } from '@plone/volto/helpers';
|
|
14
14
|
import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
|
|
15
15
|
|
|
16
16
|
import leftKey from '@plone/volto/icons/left-key.svg';
|
|
@@ -101,7 +101,7 @@ export class DatetimeWidgetComponent extends Component {
|
|
|
101
101
|
// if passed value matches the construction time, we guess it's a default
|
|
102
102
|
isDefault:
|
|
103
103
|
parseDateTime(
|
|
104
|
-
this.props.lang,
|
|
104
|
+
toBackendLang(this.props.lang),
|
|
105
105
|
this.props.value,
|
|
106
106
|
undefined,
|
|
107
107
|
this.moment,
|
|
@@ -111,7 +111,7 @@ export class DatetimeWidgetComponent extends Component {
|
|
|
111
111
|
|
|
112
112
|
getInternalValue() {
|
|
113
113
|
return parseDateTime(
|
|
114
|
-
this.props.lang,
|
|
114
|
+
toBackendLang(this.props.lang),
|
|
115
115
|
this.props.value,
|
|
116
116
|
undefined,
|
|
117
117
|
this.moment,
|
|
@@ -211,7 +211,9 @@ export class DatetimeWidgetComponent extends Component {
|
|
|
211
211
|
{...(noPastDates ? {} : { isOutsideRange: () => false })}
|
|
212
212
|
onFocusChange={this.onFocusChange}
|
|
213
213
|
noBorder
|
|
214
|
-
displayFormat={moment
|
|
214
|
+
displayFormat={moment
|
|
215
|
+
.localeData(toBackendLang(lang))
|
|
216
|
+
.longDateFormat('L')}
|
|
215
217
|
navPrev={<PrevIcon />}
|
|
216
218
|
navNext={<NextIcon />}
|
|
217
219
|
id={`${id}-date`}
|
|
@@ -233,7 +235,9 @@ export class DatetimeWidgetComponent extends Component {
|
|
|
233
235
|
showSecond={false}
|
|
234
236
|
use12Hours={lang === 'en'}
|
|
235
237
|
id={`${id}-time`}
|
|
236
|
-
format={moment
|
|
238
|
+
format={moment
|
|
239
|
+
.localeData(toBackendLang(lang))
|
|
240
|
+
.longDateFormat('LT')}
|
|
237
241
|
placeholder={intl.formatMessage(messages.time)}
|
|
238
242
|
focusOnOpen
|
|
239
243
|
placement="bottomRight"
|
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { defineMessages, useIntl } from 'react-intl';
|
|
3
3
|
import { Accordion, Button, Segment } from 'semantic-ui-react';
|
|
4
4
|
import { DragDropList, FormFieldWrapper, Icon } from '@plone/volto/components';
|
|
5
|
-
import { applySchemaDefaults } from '@plone/volto/helpers';
|
|
5
|
+
import { applySchemaDefaults, reorderArray } from '@plone/volto/helpers';
|
|
6
6
|
import ObjectWidget from '@plone/volto/components/manage/Widgets/ObjectWidget';
|
|
7
7
|
|
|
8
8
|
import upSVG from '@plone/volto/icons/up-key.svg';
|
|
@@ -164,13 +164,8 @@ const ObjectListWidget = (props) => {
|
|
|
164
164
|
if (!destination) {
|
|
165
165
|
return;
|
|
166
166
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
const second = value[destination.index];
|
|
170
|
-
value[destination.index] = first;
|
|
171
|
-
value[source.index] = second;
|
|
172
|
-
|
|
173
|
-
onChange(id, value);
|
|
167
|
+
const newValue = reorderArray(value, source.index, destination.index);
|
|
168
|
+
onChange(id, newValue);
|
|
174
169
|
return true;
|
|
175
170
|
}}
|
|
176
171
|
>
|
|
@@ -7,6 +7,7 @@ import React from 'react';
|
|
|
7
7
|
import PropTypes from 'prop-types';
|
|
8
8
|
import { Form, Grid, Button } from 'semantic-ui-react';
|
|
9
9
|
import { Days } from './Utils';
|
|
10
|
+
import { toBackendLang } from '@plone/volto/helpers';
|
|
10
11
|
import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
|
|
11
12
|
import { useSelector } from 'react-redux';
|
|
12
13
|
|
|
@@ -18,7 +19,7 @@ import { useSelector } from 'react-redux';
|
|
|
18
19
|
const ByDayField = ({ label, value, onChange, moment: momentlib }) => {
|
|
19
20
|
const lang = useSelector((state) => state.intl.locale);
|
|
20
21
|
const moment = momentlib.default;
|
|
21
|
-
moment.locale(lang);
|
|
22
|
+
moment.locale(toBackendLang(lang));
|
|
22
23
|
|
|
23
24
|
const toggleWeekDay = (dayName) => {
|
|
24
25
|
var day = Days[dayName];
|
|
@@ -8,6 +8,7 @@ import PropTypes from 'prop-types';
|
|
|
8
8
|
import { map } from 'lodash';
|
|
9
9
|
import { Form } from 'semantic-ui-react';
|
|
10
10
|
import SelectInput from './SelectInput';
|
|
11
|
+
import { toBackendLang } from '@plone/volto/helpers';
|
|
11
12
|
import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
|
|
12
13
|
import { useSelector } from 'react-redux';
|
|
13
14
|
|
|
@@ -25,7 +26,7 @@ const MonthOfTheYearField = ({
|
|
|
25
26
|
}) => {
|
|
26
27
|
const moment = momentlib.default;
|
|
27
28
|
const lang = useSelector((state) => state.intl.locale);
|
|
28
|
-
moment.locale(lang);
|
|
29
|
+
moment.locale(toBackendLang(lang));
|
|
29
30
|
const monthList = [
|
|
30
31
|
...map(moment.months(), (m, i) => ({
|
|
31
32
|
value: i + 1,
|
|
@@ -11,6 +11,7 @@ import { List, Button, Header, Label } from 'semantic-ui-react';
|
|
|
11
11
|
import { Icon } from '@plone/volto/components';
|
|
12
12
|
import addSVG from '@plone/volto/icons/circle-plus.svg';
|
|
13
13
|
import trashSVG from '@plone/volto/icons/delete.svg';
|
|
14
|
+
import { toBackendLang } from '@plone/volto/helpers';
|
|
14
15
|
import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
|
|
15
16
|
|
|
16
17
|
import { useSelector } from 'react-redux';
|
|
@@ -68,7 +69,7 @@ const Occurences_ = ({
|
|
|
68
69
|
}) => {
|
|
69
70
|
const moment = momentlib.default;
|
|
70
71
|
const lang = useSelector((state) => state.intl.locale);
|
|
71
|
-
moment.locale(lang);
|
|
72
|
+
moment.locale(toBackendLang(lang));
|
|
72
73
|
let all = [];
|
|
73
74
|
const isExcluded = (date) => {
|
|
74
75
|
var dateISO = toISOString(date);
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
} from 'semantic-ui-react';
|
|
24
24
|
|
|
25
25
|
import { SelectWidget, Icon, DatetimeWidget } from '@plone/volto/components';
|
|
26
|
+
import { toBackendLang } from '@plone/volto/helpers';
|
|
26
27
|
import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
|
|
27
28
|
|
|
28
29
|
import saveSVG from '@plone/volto/icons/save.svg';
|
|
@@ -183,7 +184,7 @@ class RecurrenceWidget extends Component {
|
|
|
183
184
|
const { RRuleSet, rrulestr } = props.rrule;
|
|
184
185
|
|
|
185
186
|
this.moment = this.props.moment.default;
|
|
186
|
-
this.moment.locale(this.props.lang);
|
|
187
|
+
this.moment.locale(toBackendLang(this.props.lang));
|
|
187
188
|
|
|
188
189
|
let rruleSet = this.props.value
|
|
189
190
|
? rrulestr(props.value, {
|
|
@@ -201,7 +202,11 @@ class RecurrenceWidget extends Component {
|
|
|
201
202
|
open: false,
|
|
202
203
|
rruleSet: rruleSet,
|
|
203
204
|
formValues: this.getFormValues(rruleSet),
|
|
204
|
-
RRULE_LANGUAGE: rrulei18n(
|
|
205
|
+
RRULE_LANGUAGE: rrulei18n(
|
|
206
|
+
this.props.intl,
|
|
207
|
+
this.moment,
|
|
208
|
+
toBackendLang(this.props.lang),
|
|
209
|
+
),
|
|
205
210
|
};
|
|
206
211
|
}
|
|
207
212
|
|
|
@@ -8,6 +8,7 @@ import { map } from 'lodash';
|
|
|
8
8
|
import { Days } from './Utils';
|
|
9
9
|
import SelectInput from './SelectInput';
|
|
10
10
|
import { Form } from 'semantic-ui-react';
|
|
11
|
+
import { toBackendLang } from '@plone/volto/helpers';
|
|
11
12
|
import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
|
|
12
13
|
import { useSelector } from 'react-redux';
|
|
13
14
|
|
|
@@ -22,7 +23,7 @@ const WeekdayOfTheMonthField = (props) => {
|
|
|
22
23
|
const lang = useSelector((state) => state.intl.locale);
|
|
23
24
|
|
|
24
25
|
const moment = momentlib.default;
|
|
25
|
-
moment.locale(lang);
|
|
26
|
+
moment.locale(toBackendLang(lang));
|
|
26
27
|
|
|
27
28
|
const weekdayOfTheMonthList = [
|
|
28
29
|
...map(Object.keys(Days), (d) => ({
|
|
@@ -9,7 +9,6 @@ import { map } from 'lodash';
|
|
|
9
9
|
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
|
|
10
10
|
import { useSelector, shallowEqual } from 'react-redux';
|
|
11
11
|
import { UniversalLink } from '@plone/volto/components';
|
|
12
|
-
import config from '@plone/volto/registry';
|
|
13
12
|
import { flattenToAppURL, addAppURL } from '@plone/volto/helpers';
|
|
14
13
|
|
|
15
14
|
const messages = defineMessages({
|
|
@@ -26,10 +25,8 @@ const messages = defineMessages({
|
|
|
26
25
|
* @returns {string} Markup of the component
|
|
27
26
|
*/
|
|
28
27
|
const Footer = ({ intl }) => {
|
|
29
|
-
const {
|
|
30
|
-
const { lang, siteActions = [] } = useSelector(
|
|
28
|
+
const { siteActions = [] } = useSelector(
|
|
31
29
|
(state) => ({
|
|
32
|
-
lang: state.intl.locale,
|
|
33
30
|
siteActions: state.actions?.actions?.site_actions,
|
|
34
31
|
}),
|
|
35
32
|
shallowEqual,
|
|
@@ -97,15 +94,7 @@ const Footer = ({ intl }) => {
|
|
|
97
94
|
<UniversalLink
|
|
98
95
|
className="item"
|
|
99
96
|
href={
|
|
100
|
-
|
|
101
|
-
? `/${lang}/${
|
|
102
|
-
item.url
|
|
103
|
-
? flattenToAppURL(item.url)
|
|
104
|
-
: addAppURL(item.id)
|
|
105
|
-
}`
|
|
106
|
-
: item.url
|
|
107
|
-
? flattenToAppURL(item.url)
|
|
108
|
-
: addAppURL(item.id)
|
|
97
|
+
item.url ? flattenToAppURL(item.url) : addAppURL(item.id)
|
|
109
98
|
}
|
|
110
99
|
>
|
|
111
100
|
{item?.title}
|
|
@@ -44,8 +44,8 @@ const Icon = ({
|
|
|
44
44
|
ariaHidden,
|
|
45
45
|
}) => (
|
|
46
46
|
<svg
|
|
47
|
-
xmlns={name
|
|
48
|
-
viewBox={name
|
|
47
|
+
xmlns={name?.attributes?.xmlns}
|
|
48
|
+
viewBox={name?.attributes?.viewBox}
|
|
49
49
|
style={{
|
|
50
50
|
height: size,
|
|
51
51
|
width: 'auto',
|
|
@@ -11,7 +11,12 @@ import { useSelector } from 'react-redux';
|
|
|
11
11
|
import cx from 'classnames';
|
|
12
12
|
import { find, map } from 'lodash';
|
|
13
13
|
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
Helmet,
|
|
16
|
+
langmap,
|
|
17
|
+
flattenToAppURL,
|
|
18
|
+
toReactIntlLang,
|
|
19
|
+
} from '@plone/volto/helpers';
|
|
15
20
|
|
|
16
21
|
import config from '@plone/volto/registry';
|
|
17
22
|
|
|
@@ -42,7 +47,7 @@ const LanguageSelector = (props) => {
|
|
|
42
47
|
aria-label={`${intl.formatMessage(
|
|
43
48
|
messages.switchLanguageTo,
|
|
44
49
|
)} ${langmap[lang].nativeName.toLowerCase()}`}
|
|
45
|
-
className={cx({ selected: lang === currentLang })}
|
|
50
|
+
className={cx({ selected: toReactIntlLang(lang) === currentLang })}
|
|
46
51
|
to={translation ? flattenToAppURL(translation['@id']) : `/${lang}`}
|
|
47
52
|
title={langmap[lang].nativeName}
|
|
48
53
|
onClick={() => {
|
|
@@ -57,7 +62,7 @@ const LanguageSelector = (props) => {
|
|
|
57
62
|
</div>
|
|
58
63
|
) : (
|
|
59
64
|
<Helmet>
|
|
60
|
-
<html lang={settings.defaultLanguage} />
|
|
65
|
+
<html lang={toReactIntlLang(settings.defaultLanguage)} />
|
|
61
66
|
</Helmet>
|
|
62
67
|
);
|
|
63
68
|
};
|
|
@@ -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
|
package/src/config/index.js
CHANGED
|
@@ -28,9 +28,24 @@ export const generateRobots = (req) =>
|
|
|
28
28
|
if (error) {
|
|
29
29
|
resolve(text || error);
|
|
30
30
|
} else {
|
|
31
|
+
// It appears that express does not take the x-forwarded headers into
|
|
32
|
+
// consideration, so we do it ourselves.
|
|
33
|
+
const {
|
|
34
|
+
'x-forwarded-proto': forwardedProto,
|
|
35
|
+
'x-forwarded-host': forwardedHost,
|
|
36
|
+
'x-forwarded-port': forwardedPort,
|
|
37
|
+
} = req.headers;
|
|
38
|
+
const proto = forwardedProto ?? req.protocol;
|
|
39
|
+
const host = forwardedHost ?? req.get('Host');
|
|
40
|
+
const portNum = forwardedPort ?? req.get('Port');
|
|
41
|
+
const port =
|
|
42
|
+
(proto === 'https' && '' + portNum === '443') ||
|
|
43
|
+
(proto === 'http' && '' + portNum === '80')
|
|
44
|
+
? ''
|
|
45
|
+
: `:${portNum}`;
|
|
31
46
|
// Plone has probably returned the sitemap link with the internal url.
|
|
32
47
|
// If so, let's replace it with the current one.
|
|
33
|
-
const url = `${
|
|
48
|
+
const url = `${proto}://${host}${port}`;
|
|
34
49
|
text = text.replace(internalUrl, url);
|
|
35
50
|
// Replace the sitemap with the sitemap index.
|
|
36
51
|
text = text.replace('sitemap.xml.gz', 'sitemap-index.xml');
|
package/src/helpers/Url/Url.js
CHANGED
|
@@ -280,14 +280,14 @@ export function isTelephone(text) {
|
|
|
280
280
|
}
|
|
281
281
|
|
|
282
282
|
export function normaliseMail(email) {
|
|
283
|
-
if (email
|
|
283
|
+
if (email?.toLowerCase()?.startsWith('mailto:')) {
|
|
284
284
|
return email;
|
|
285
285
|
}
|
|
286
286
|
return `mailto:${email}`;
|
|
287
287
|
}
|
|
288
288
|
|
|
289
289
|
export function normalizeTelephone(tel) {
|
|
290
|
-
if (tel
|
|
290
|
+
if (tel?.toLowerCase()?.startsWith('tel:')) {
|
|
291
291
|
return tel;
|
|
292
292
|
}
|
|
293
293
|
return `tel:${tel}`;
|
|
@@ -310,12 +310,17 @@ export function checkAndNormalizeUrl(url) {
|
|
|
310
310
|
res.url = URLUtils.normalizeTelephone(url);
|
|
311
311
|
} else {
|
|
312
312
|
//url
|
|
313
|
-
if (
|
|
313
|
+
if (
|
|
314
|
+
res.url?.length >= 0 &&
|
|
315
|
+
!res.url.startsWith('/') &&
|
|
316
|
+
!res.url.startsWith('#')
|
|
317
|
+
) {
|
|
314
318
|
res.url = URLUtils.normalizeUrl(url);
|
|
315
319
|
if (!URLUtils.isUrl(res.url)) {
|
|
316
320
|
res.isValid = false;
|
|
317
321
|
}
|
|
318
322
|
}
|
|
323
|
+
if (res.url === undefined || res.url === null) res.isValid = false;
|
|
319
324
|
}
|
|
320
325
|
return res;
|
|
321
326
|
}
|
|
@@ -14,6 +14,9 @@ import {
|
|
|
14
14
|
removeProtocol,
|
|
15
15
|
addAppURL,
|
|
16
16
|
expandToBackendURL,
|
|
17
|
+
checkAndNormalizeUrl,
|
|
18
|
+
normaliseMail,
|
|
19
|
+
normalizeTelephone,
|
|
17
20
|
} from './Url';
|
|
18
21
|
|
|
19
22
|
beforeEach(() => {
|
|
@@ -61,6 +64,17 @@ describe('Url', () => {
|
|
|
61
64
|
it('return empty string if no url is empty string', () => {
|
|
62
65
|
expect(getBaseUrl('')).toBe('');
|
|
63
66
|
});
|
|
67
|
+
it('return a null/undefined mailto adress ', () => {
|
|
68
|
+
expect(normaliseMail(null)).toBe('mailto:null');
|
|
69
|
+
expect(normaliseMail(undefined)).toBe('mailto:undefined');
|
|
70
|
+
});
|
|
71
|
+
it('return a null/undefined telephone number', () => {
|
|
72
|
+
expect(normalizeTelephone(null)).toBe('tel:null');
|
|
73
|
+
expect(normalizeTelephone(undefined)).toBe('tel:undefined');
|
|
74
|
+
});
|
|
75
|
+
it('null returns an invalid link', () => {
|
|
76
|
+
expect(checkAndNormalizeUrl(null).isValid).toBe(false);
|
|
77
|
+
});
|
|
64
78
|
});
|
|
65
79
|
|
|
66
80
|
describe('getView', () => {
|
|
@@ -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
|
|
@@ -258,11 +270,11 @@ export const removeFromArray = (array, index) => {
|
|
|
258
270
|
};
|
|
259
271
|
|
|
260
272
|
/**
|
|
261
|
-
*
|
|
273
|
+
* Moves an item from origin to target inside an array in an immutable way
|
|
262
274
|
* @param {Array} array Array with data
|
|
263
|
-
* @param {number} origin Index of item to be
|
|
264
|
-
* @param {number} target Index of item to be
|
|
265
|
-
* @returns {Array}
|
|
275
|
+
* @param {number} origin Index of item to be moved from
|
|
276
|
+
* @param {number} target Index of item to be moved to
|
|
277
|
+
* @returns {Array} Resultant array
|
|
266
278
|
*/
|
|
267
279
|
export const reorderArray = (array, origin, target) => {
|
|
268
280
|
const result = Array.from(array);
|
|
@@ -299,3 +311,16 @@ export const cloneDeepSchema = (object) => {
|
|
|
299
311
|
}
|
|
300
312
|
});
|
|
301
313
|
};
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Creates an array given a range of numbers
|
|
317
|
+
* @param {number} start start number from
|
|
318
|
+
* @param {number} stop stop number at
|
|
319
|
+
* @param {number} step step every each number in the sequence
|
|
320
|
+
* @returns {array} The result, eg. [0, 1, 2, 3, 4]
|
|
321
|
+
*/
|
|
322
|
+
export const arrayRange = (start, stop, step) =>
|
|
323
|
+
Array.from(
|
|
324
|
+
{ length: (stop - start) / step + 1 },
|
|
325
|
+
(value, index) => start + index * step,
|
|
326
|
+
);
|