@plone/volto 16.20.4 → 16.20.6
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/.changelog.draft +2 -6
- package/.yarn/install-state.gz +0 -0
- package/CHANGELOG.md +39 -13
- package/CONTRIBUTING.md +1 -1
- package/README.md +4 -4
- package/package.json +1 -1
- 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/Search/components/DateRangeFacet.jsx +4 -1
- 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/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/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/helpers/Url/Url.js +8 -3
- package/src/helpers/Url/Url.test.js +14 -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/server.jsx +28 -23
- package/theme/themes/pastanaga/extras/sidebar.less +4 -0
package/.changelog.draft
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
## 16.20.
|
|
1
|
+
## 16.20.6 (2023-05-12)
|
|
2
2
|
|
|
3
3
|
### Bugfix
|
|
4
4
|
|
|
5
|
-
- Fix
|
|
6
|
-
|
|
7
|
-
### Internal
|
|
8
|
-
|
|
9
|
-
- Security upgrade for momentjs [#4716](https://github.com/plone/volto/issues/4716)
|
|
5
|
+
- Fix language negotiation for language codes that include a region (e.g. `pt-br`). @davisagli [#4644](https://github.com/plone/volto/issues/4644)
|
|
10
6
|
|
package/.yarn/install-state.gz
CHANGED
|
Binary file
|
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,32 @@
|
|
|
8
8
|
|
|
9
9
|
<!-- towncrier release notes start -->
|
|
10
10
|
|
|
11
|
+
## 16.20.6 (2023-05-12)
|
|
12
|
+
|
|
13
|
+
### Bugfix
|
|
14
|
+
|
|
15
|
+
- Fix language negotiation for language codes that include a region (e.g. `pt-br`). @davisagli [#4644](https://github.com/plone/volto/issues/4644)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
## 16.20.5 (2023-05-12)
|
|
19
|
+
|
|
20
|
+
### Bugfix
|
|
21
|
+
|
|
22
|
+
- Apply suggestion from browser for password field @lord2anil [#3990](https://github.com/plone/volto/issues/3990)
|
|
23
|
+
- The tabs for the add page was unresponsive on mobile devices. Fixed this by changing flex-wrap property. @sudhanshu1309 [#4506](https://github.com/plone/volto/issues/4506)
|
|
24
|
+
- (fix):Object.normaliseMail: Cannot read properties of null @dobri1408 [#4558](https://github.com/plone/volto/issues/4558)
|
|
25
|
+
|
|
26
|
+
### Internal
|
|
27
|
+
|
|
28
|
+
- Upgrade to Plone 6.0.4 @sneridagh [#4743](https://github.com/plone/volto/issues/4743)
|
|
29
|
+
|
|
30
|
+
### Documentation
|
|
31
|
+
|
|
32
|
+
- Added documentation regarding the static middleware. @BhardwajAditya-github [#4518](https://github.com/plone/volto/issues/4518)
|
|
33
|
+
- Backport most documentation differences from `master` to `16.x.x`. @stevepiercy [#4727](https://github.com/plone/volto/issues/4727)
|
|
34
|
+
- Fix link in Volto, remove from linkcheck ignore in Documentation. @stevepiercy [#4742](https://github.com/plone/volto/issues/4742)
|
|
35
|
+
|
|
36
|
+
|
|
11
37
|
## 16.20.4 (2023-04-20)
|
|
12
38
|
|
|
13
39
|
### Bugfix
|
|
@@ -274,7 +300,7 @@
|
|
|
274
300
|
|
|
275
301
|
### Documentation
|
|
276
302
|
|
|
277
|
-
- Complete teaser docs, add new section in `Blocks`: `Core Blocks developers notes` @sneridagh [#4461](https://github.com/plone/volto/
|
|
303
|
+
- Complete teaser docs, add new section in `Blocks`: `Core Blocks developers notes` @sneridagh [#4461](https://github.com/plone/volto/pull/4461)
|
|
278
304
|
|
|
279
305
|
|
|
280
306
|
## 16.14.0 (2023-03-03)
|
|
@@ -604,7 +630,7 @@
|
|
|
604
630
|
- Enable the use of yarn 3 in the build by default @sneridagh
|
|
605
631
|
- The `ContentsBreadcrumbs` component now renders the whole language name of the language root folder (if any) instead of just the `id` (before: `de`, now: `Deutsch`) @sneridagh
|
|
606
632
|
|
|
607
|
-
See https://6.
|
|
633
|
+
See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information.
|
|
608
634
|
|
|
609
635
|
### Feature
|
|
610
636
|
|
|
@@ -1099,7 +1125,7 @@ See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more informa
|
|
|
1099
1125
|
- Moved all sentry-related code from Volto to the `@plone-collective/volto-sentry` package. @tiberiuichim
|
|
1100
1126
|
- The listing block icon has been improved to avoid confusion with the normal text list. @sneridagh
|
|
1101
1127
|
|
|
1102
|
-
See https://6.
|
|
1128
|
+
See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information.
|
|
1103
1129
|
|
|
1104
1130
|
### Feature
|
|
1105
1131
|
|
|
@@ -1209,7 +1235,7 @@ See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more informa
|
|
|
1209
1235
|
|
|
1210
1236
|
- Sentry integration is now lazy-loaded. The `sentryOptions` key from the `settings` registry becomes a callable that passes resolved sentry libraries. @tiberiuichim
|
|
1211
1237
|
|
|
1212
|
-
See https://6.
|
|
1238
|
+
See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information.
|
|
1213
1239
|
|
|
1214
1240
|
### Feature
|
|
1215
1241
|
|
|
@@ -1273,7 +1299,7 @@ See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more informa
|
|
|
1273
1299
|
- Upgrade to Razzle 4 @davisagli
|
|
1274
1300
|
- Jest downgraded from 27 to 26 @davisagli
|
|
1275
1301
|
|
|
1276
|
-
See https://6.
|
|
1302
|
+
See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information.
|
|
1277
1303
|
|
|
1278
1304
|
### Internal
|
|
1279
1305
|
|
|
@@ -1313,7 +1339,7 @@ See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more informa
|
|
|
1313
1339
|
### Breaking
|
|
1314
1340
|
|
|
1315
1341
|
- `react-window` no longer a Volto dependency @sneridagh
|
|
1316
|
-
See https://6.
|
|
1342
|
+
See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information.
|
|
1317
1343
|
|
|
1318
1344
|
### Bugfix
|
|
1319
1345
|
|
|
@@ -1352,7 +1378,7 @@ See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more informa
|
|
|
1352
1378
|
### Breaking
|
|
1353
1379
|
|
|
1354
1380
|
- Move Layout constants to `config.views.layoutViewsNamesMapping`. Complete the list. i18n the list. Improve Display component. @sneridagh
|
|
1355
|
-
See https://6.
|
|
1381
|
+
See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information.
|
|
1356
1382
|
|
|
1357
1383
|
### Feature
|
|
1358
1384
|
|
|
@@ -1398,7 +1424,7 @@ Undo html_static_path configuration in `plone/documentation`, and restore image
|
|
|
1398
1424
|
### Breaking
|
|
1399
1425
|
|
|
1400
1426
|
- Main workflow change menu changed from Pastanaga UI simplification to classic Plone implementation. @sneridagh
|
|
1401
|
-
See https://6.
|
|
1427
|
+
See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information.
|
|
1402
1428
|
|
|
1403
1429
|
### Feature
|
|
1404
1430
|
|
|
@@ -1494,7 +1520,7 @@ Undo html_static_path configuration in `plone/documentation`, and restore image
|
|
|
1494
1520
|
- change password-reset url to be consistent with Plone configuration @erral
|
|
1495
1521
|
- Simplify over the existing Component Registry API. The `component` key has been flattened for simplification and now it's mapped directly to the `component` argument of `registerComponent`. @sneridagh
|
|
1496
1522
|
|
|
1497
|
-
See https://6.
|
|
1523
|
+
See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information.
|
|
1498
1524
|
|
|
1499
1525
|
### Feature
|
|
1500
1526
|
|
|
@@ -2072,14 +2098,14 @@ Use next release instead: https://github.com/plone/volto/releases/tag/16.0.0-alp
|
|
|
2072
2098
|
### Breaking
|
|
2073
2099
|
|
|
2074
2100
|
- Upgrade `react-cookie` to the latest version. @sneridagh @robgietema
|
|
2075
|
-
See https://6.
|
|
2101
|
+
See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information.
|
|
2076
2102
|
- Language Switcher no longer takes care of the change of the language on the Redux Store. This responsibility has been unified in the API Redux middleware @sneridagh
|
|
2077
2103
|
- Markup change in `LinkView` component.
|
|
2078
2104
|
- Rename `core-sandbox` to `coresandbox` for sake of consistency @sneridagh
|
|
2079
2105
|
- Extend the original intent and rename `RAZZLE_TESTING_ADDONS` to `ADDONS`. @sneridagh
|
|
2080
|
-
See https://6.
|
|
2106
|
+
See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information.
|
|
2081
2107
|
- Lazyload Draft.js library. See the upgrade guide on how that impacts you, in case you have extended the rich text editor configuration @tiberiuichim @kreafox
|
|
2082
|
-
See https://6.
|
|
2108
|
+
See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information.
|
|
2083
2109
|
- Deprecating `lang` cookie in favor of Plone official one `I18N_LANGUAGE` @sneridagh
|
|
2084
2110
|
|
|
2085
2111
|
### Feature
|
|
@@ -5025,7 +5051,7 @@ https://6.docs.plone.org/volto/upgrade-guide/index.html
|
|
|
5025
5051
|
- Added item type as a tooltip in contents @nzambello
|
|
5026
5052
|
- Added Italian translations and translated array, token and select widget. @giuliaghisini
|
|
5027
5053
|
- Added uploading image preview in FileWidget @iFlameing
|
|
5028
|
-
- Allow custom express middleware declared with `settings.expressMiddleware`. See [Custom Express middleware](https://6.
|
|
5054
|
+
- Allow custom express middleware declared with `settings.expressMiddleware`. See [Custom Express middleware](https://6.docs.plone.org/volto/recipes/express.html) @tiberiuichim
|
|
5029
5055
|
|
|
5030
5056
|
### Bugfix
|
|
5031
5057
|
|
package/CONTRIBUTING.md
CHANGED
package/README.md
CHANGED
|
@@ -181,7 +181,7 @@ Please create a new [issue](https://github.com/plone/volto/issues/new) or [pull
|
|
|
181
181
|
|
|
182
182
|
## Documentation
|
|
183
183
|
|
|
184
|
-
You can find the latest
|
|
184
|
+
You can find the latest documentation in [https://6.docs.plone.org/](https://6.docs.plone.org/volto/index.html)
|
|
185
185
|
|
|
186
186
|
## Training
|
|
187
187
|
|
|
@@ -243,7 +243,7 @@ We do not guarantee that deprecated browsers (e.g., Internet Explorer 11) are su
|
|
|
243
243
|
|
|
244
244
|
## Upgrades
|
|
245
245
|
|
|
246
|
-
You can find the upgrade guide here: https://6.
|
|
246
|
+
You can find the upgrade guide here: https://6.docs.plone.org/volto/upgrade-guide/index.html
|
|
247
247
|
|
|
248
248
|
## Volto Development
|
|
249
249
|
|
|
@@ -318,11 +318,11 @@ yarn test
|
|
|
318
318
|
|
|
319
319
|
Here you can find a guide on how acceptance testing is done in Volto:
|
|
320
320
|
|
|
321
|
-
https://6.
|
|
321
|
+
https://6.docs.plone.org/volto/developer-guidelines/acceptance-tests.html
|
|
322
322
|
|
|
323
323
|
## Translations
|
|
324
324
|
|
|
325
|
-
If you would like contribute to translate Volto into several languages, please, read the [Internationalization (i18n) guide](https://6.
|
|
325
|
+
If you would like contribute to translate Volto into several languages, please, read the [Internationalization (i18n) guide](https://6.docs.plone.org/volto/recipes/i18n.html).
|
|
326
326
|
|
|
327
327
|
## Contributors
|
|
328
328
|
|
package/package.json
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { updateIntl } from 'react-intl-redux';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
toGettextLang,
|
|
4
|
+
toReactIntlLang,
|
|
5
|
+
getCookieOptions,
|
|
6
|
+
} from '@plone/volto/helpers';
|
|
3
7
|
import Cookies from 'universal-cookie';
|
|
4
8
|
|
|
5
9
|
export function changeLanguageCookies(language, req) {
|
|
@@ -11,15 +15,11 @@ export function changeLanguageCookies(language, req) {
|
|
|
11
15
|
});
|
|
12
16
|
|
|
13
17
|
if (!req) {
|
|
14
|
-
cookies.set(
|
|
15
|
-
'I18N_LANGUAGE',
|
|
16
|
-
normalizeLanguageName(language) || '',
|
|
17
|
-
cookieOptions,
|
|
18
|
-
);
|
|
18
|
+
cookies.set('I18N_LANGUAGE', toGettextLang(language) || '', cookieOptions);
|
|
19
19
|
} else {
|
|
20
20
|
req.universalCookies.set(
|
|
21
21
|
'I18N_LANGUAGE',
|
|
22
|
-
|
|
22
|
+
toGettextLang(language) || '',
|
|
23
23
|
cookieOptions,
|
|
24
24
|
);
|
|
25
25
|
}
|
|
@@ -36,7 +36,7 @@ export function changeLanguage(language, locale, req) {
|
|
|
36
36
|
changeLanguageCookies(language, req);
|
|
37
37
|
|
|
38
38
|
return updateIntl({
|
|
39
|
-
locale: language,
|
|
39
|
+
locale: toReactIntlLang(language),
|
|
40
40
|
messages: locale,
|
|
41
41
|
});
|
|
42
42
|
}
|
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
getBlocksLayoutFieldname,
|
|
34
34
|
getLanguageIndependentFields,
|
|
35
35
|
langmap,
|
|
36
|
-
|
|
36
|
+
toGettextLang,
|
|
37
37
|
} from '@plone/volto/helpers';
|
|
38
38
|
|
|
39
39
|
import { preloadLazyLibs } from '@plone/volto/helpers/Loadable';
|
|
@@ -219,7 +219,7 @@ class Add extends Component {
|
|
|
219
219
|
onCancel() {
|
|
220
220
|
if (this.props.location?.state?.translationOf) {
|
|
221
221
|
const language = this.props.location.state.languageFrom;
|
|
222
|
-
const langFileName =
|
|
222
|
+
const langFileName = toGettextLang(language);
|
|
223
223
|
import('@root/../locales/' + langFileName + '.json').then((locale) => {
|
|
224
224
|
this.props.changeLanguage(language, locale.default);
|
|
225
225
|
});
|
|
@@ -4,6 +4,7 @@ import { defineMessages, injectIntl } from 'react-intl';
|
|
|
4
4
|
import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
|
|
5
5
|
import { compose } from 'redux';
|
|
6
6
|
import { Icon } from '@plone/volto/components';
|
|
7
|
+
import { toBackendLang } from '@plone/volto/helpers/Utils/Utils';
|
|
7
8
|
import { connect } from 'react-redux';
|
|
8
9
|
|
|
9
10
|
import leftKey from '@plone/volto/icons/left-key.svg';
|
|
@@ -82,7 +83,9 @@ const DateRangeFacet = (props) => {
|
|
|
82
83
|
noBorder
|
|
83
84
|
showClearDates
|
|
84
85
|
customCloseIcon={<CloseIcon />}
|
|
85
|
-
displayFormat={moment
|
|
86
|
+
displayFormat={moment
|
|
87
|
+
.localeData(toBackendLang(lang))
|
|
88
|
+
.longDateFormat('L')}
|
|
86
89
|
focusedInput={focused}
|
|
87
90
|
onFocusChange={(focusedInput) => setFocused(focusedInput)}
|
|
88
91
|
onDatesChange={({ startDate, endDate }) => {
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
getTranslationLocator,
|
|
7
7
|
getContent,
|
|
8
8
|
} from '@plone/volto/actions';
|
|
9
|
-
import { flattenToAppURL,
|
|
9
|
+
import { flattenToAppURL, toGettextLang } from '@plone/volto/helpers';
|
|
10
10
|
import config from '@plone/volto/registry';
|
|
11
11
|
|
|
12
12
|
const CreateTranslation = (props) => {
|
|
@@ -33,7 +33,7 @@ const CreateTranslation = (props) => {
|
|
|
33
33
|
return () => {
|
|
34
34
|
// We change the interface language
|
|
35
35
|
if (config.settings.supportedLanguages.includes(language)) {
|
|
36
|
-
const langFileName =
|
|
36
|
+
const langFileName = toGettextLang(language);
|
|
37
37
|
import('@root/../locales/' + langFileName + '.json').then((locale) => {
|
|
38
38
|
dispatch(changeLanguage(language, locale.default));
|
|
39
39
|
});
|
|
@@ -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"
|
|
@@ -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}
|
|
@@ -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/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
|
|
@@ -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
|
@@ -81,8 +81,11 @@ export {
|
|
|
81
81
|
applyConfig,
|
|
82
82
|
withServerErrorCode,
|
|
83
83
|
parseDateTime,
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
toGettextLang,
|
|
85
|
+
normalizeLanguageName, // old name for toGettextLang
|
|
86
|
+
toReactIntlLang,
|
|
87
|
+
toLangUnderscoreRegion, // old name for toReactIntlLang
|
|
88
|
+
toBackendLang,
|
|
86
89
|
hasApiExpander,
|
|
87
90
|
replaceItemOfArray,
|
|
88
91
|
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/server.jsx
CHANGED
|
@@ -26,8 +26,9 @@ import {
|
|
|
26
26
|
Html,
|
|
27
27
|
Api,
|
|
28
28
|
persistAuthToken,
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
toBackendLang,
|
|
30
|
+
toGettextLang,
|
|
31
|
+
toReactIntlLang,
|
|
31
32
|
} from '@plone/volto/helpers';
|
|
32
33
|
import { changeLanguage } from '@plone/volto/actions';
|
|
33
34
|
|
|
@@ -44,9 +45,9 @@ let locales = {};
|
|
|
44
45
|
|
|
45
46
|
if (config.settings) {
|
|
46
47
|
config.settings.supportedLanguages.forEach((lang) => {
|
|
47
|
-
const langFileName =
|
|
48
|
+
const langFileName = toGettextLang(lang);
|
|
48
49
|
import('@root/../locales/' + langFileName + '.json').then((locale) => {
|
|
49
|
-
locales = { ...locales, [lang]: locale.default };
|
|
50
|
+
locales = { ...locales, [toReactIntlLang(lang)]: locale.default };
|
|
50
51
|
});
|
|
51
52
|
});
|
|
52
53
|
}
|
|
@@ -101,13 +102,15 @@ server.use(function (err, req, res, next) {
|
|
|
101
102
|
function setupServer(req, res, next) {
|
|
102
103
|
const api = new Api(req);
|
|
103
104
|
|
|
104
|
-
const lang =
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
105
|
+
const lang = toReactIntlLang(
|
|
106
|
+
new locale.Locales(
|
|
107
|
+
req.universalCookies.get('I18N_LANGUAGE') ||
|
|
108
|
+
config.settings.defaultLanguage ||
|
|
109
|
+
req.headers['accept-language'],
|
|
110
|
+
)
|
|
111
|
+
.best(supported)
|
|
112
|
+
.toString(),
|
|
113
|
+
);
|
|
111
114
|
|
|
112
115
|
// Minimum initial state for the fake Redux store instance
|
|
113
116
|
const initialState = {
|
|
@@ -176,13 +179,15 @@ server.get('/*', (req, res) => {
|
|
|
176
179
|
|
|
177
180
|
const browserdetect = detect(req.headers['user-agent']);
|
|
178
181
|
|
|
179
|
-
const lang =
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
182
|
+
const lang = toReactIntlLang(
|
|
183
|
+
new locale.Locales(
|
|
184
|
+
req.universalCookies.get('I18N_LANGUAGE') ||
|
|
185
|
+
config.settings.defaultLanguage ||
|
|
186
|
+
req.headers['accept-language'],
|
|
187
|
+
)
|
|
188
|
+
.best(supported)
|
|
189
|
+
.toString(),
|
|
190
|
+
);
|
|
186
191
|
|
|
187
192
|
const authToken = req.universalCookies.get('auth_token');
|
|
188
193
|
const initialState = {
|
|
@@ -217,7 +222,7 @@ server.get('/*', (req, res) => {
|
|
|
217
222
|
|
|
218
223
|
loadOnServer({ store, location, routes, api })
|
|
219
224
|
.then(() => {
|
|
220
|
-
const
|
|
225
|
+
const initialLang =
|
|
221
226
|
req.universalCookies.get('I18N_LANGUAGE') ||
|
|
222
227
|
config.settings.defaultLanguage ||
|
|
223
228
|
req.headers['accept-language'];
|
|
@@ -230,15 +235,15 @@ server.get('/*', (req, res) => {
|
|
|
230
235
|
// present the language token field, for some reason. In this case, we
|
|
231
236
|
// should follow the cookie rather then switching the language
|
|
232
237
|
const contentLang = store.getState().content.get?.error
|
|
233
|
-
?
|
|
238
|
+
? initialLang
|
|
234
239
|
: store.getState().content.data?.language?.token ||
|
|
235
240
|
config.settings.defaultLanguage;
|
|
236
241
|
|
|
237
|
-
if (
|
|
238
|
-
const
|
|
242
|
+
if (toBackendLang(initialLang) !== contentLang) {
|
|
243
|
+
const newLang = toReactIntlLang(
|
|
239
244
|
new locale.Locales(contentLang).best(supported).toString(),
|
|
240
245
|
);
|
|
241
|
-
store.dispatch(changeLanguage(
|
|
246
|
+
store.dispatch(changeLanguage(newLang, locales[newLang], req));
|
|
242
247
|
}
|
|
243
248
|
|
|
244
249
|
const context = {};
|