@akemona-org/strapi-plugin-i18n 3.7.0

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.
Files changed (147) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +19 -0
  3. package/admin/src/assets/images/logo.svg +1 -0
  4. package/admin/src/components/CMEditViewCopyLocale/index.js +183 -0
  5. package/admin/src/components/CMEditViewCopyLocale/utils/cleanData.js +36 -0
  6. package/admin/src/components/CMEditViewCopyLocale/utils/generateOptions.js +22 -0
  7. package/admin/src/components/CMEditViewCopyLocale/utils/index.js +2 -0
  8. package/admin/src/components/CMEditViewCopyLocale/utils/removePasswordAndRelationsFieldFromData.js +54 -0
  9. package/admin/src/components/CMEditViewCopyLocale/utils/tests/cleanData.test.js +83 -0
  10. package/admin/src/components/CMEditViewCopyLocale/utils/tests/data.js +219 -0
  11. package/admin/src/components/CMEditViewCopyLocale/utils/tests/generateOptions.test.js +79 -0
  12. package/admin/src/components/CMEditViewCopyLocale/utils/tests/removePasswordAndRelationsFieldFromData.test.js +40 -0
  13. package/admin/src/components/CMEditViewInjectedComponents/index.js +58 -0
  14. package/admin/src/components/CMEditViewLocalePicker/Option.js +66 -0
  15. package/admin/src/components/CMEditViewLocalePicker/Wrapper.js +8 -0
  16. package/admin/src/components/CMEditViewLocalePicker/index.js +160 -0
  17. package/admin/src/components/CMEditViewLocalePicker/utils/addStatusColorToLocale.js +24 -0
  18. package/admin/src/components/CMEditViewLocalePicker/utils/createLocalesOption.js +20 -0
  19. package/admin/src/components/CMEditViewLocalePicker/utils/index.js +2 -0
  20. package/admin/src/components/CheckboxConfirmation/Wrapper.js +12 -0
  21. package/admin/src/components/CheckboxConfirmation/index.js +70 -0
  22. package/admin/src/components/DeleteModalAdditionalInfos/index.js +25 -0
  23. package/admin/src/components/LocaleList/index.js +101 -0
  24. package/admin/src/components/LocaleListCell/LocaleListCell.js +90 -0
  25. package/admin/src/components/LocaleListCell/tests/LocaleListCell.test.js +128 -0
  26. package/admin/src/components/LocalePicker/index.js +126 -0
  27. package/admin/src/components/LocaleRow/index.js +77 -0
  28. package/admin/src/components/ModalCreate/AdvancedForm.js +45 -0
  29. package/admin/src/components/ModalCreate/BaseForm.js +103 -0
  30. package/admin/src/components/ModalCreate/index.js +136 -0
  31. package/admin/src/components/ModalDelete/index.js +49 -0
  32. package/admin/src/components/ModalEdit/AdvancedForm.js +51 -0
  33. package/admin/src/components/ModalEdit/BaseForm.js +91 -0
  34. package/admin/src/components/ModalEdit/index.js +122 -0
  35. package/admin/src/components/SettingsModal.js +66 -0
  36. package/admin/src/components/index.js +2 -0
  37. package/admin/src/containers/Initializer.js +31 -0
  38. package/admin/src/containers/SettingsPage/LocaleSettingsPage.js +69 -0
  39. package/admin/src/containers/SettingsPage/index.js +33 -0
  40. package/admin/src/containers/SettingsPage/tests/SettingsPage.test.js +744 -0
  41. package/admin/src/containers/SettingsPage/tests/__snapshots__/SettingsPage.test.js.snap +241 -0
  42. package/admin/src/hooks/constants.js +6 -0
  43. package/admin/src/hooks/reducers.js +63 -0
  44. package/admin/src/hooks/tests/reducers.test.js +203 -0
  45. package/admin/src/hooks/useAddLocale/index.js +60 -0
  46. package/admin/src/hooks/useContentTypePermissions/index.js +16 -0
  47. package/admin/src/hooks/useDefaultLocales/index.js +27 -0
  48. package/admin/src/hooks/useDeleteLocale/index.js +45 -0
  49. package/admin/src/hooks/useEditLocale/index.js +46 -0
  50. package/admin/src/hooks/useHasI18n/index.js +13 -0
  51. package/admin/src/hooks/useLocales/index.js +35 -0
  52. package/admin/src/index.js +169 -0
  53. package/admin/src/middlewares/addCommonFieldsToInitialDataMiddleware.js +83 -0
  54. package/admin/src/middlewares/addLocaleColumnToListViewMiddleware.js +32 -0
  55. package/admin/src/middlewares/addLocaleToCollectionTypesMiddleware.js +25 -0
  56. package/admin/src/middlewares/addLocaleToSingleTypesMiddleware.js +25 -0
  57. package/admin/src/middlewares/extendCMEditViewLayoutMiddleware.js +159 -0
  58. package/admin/src/middlewares/extendCTBAttributeInitialDataMiddleware.js +58 -0
  59. package/admin/src/middlewares/extendCTBInitialDataMiddleware.js +33 -0
  60. package/admin/src/middlewares/index.js +21 -0
  61. package/admin/src/middlewares/localePermissionMiddleware.js +39 -0
  62. package/admin/src/middlewares/tests/addCommonFieldsToInitialDataMiddleware.test.js +97 -0
  63. package/admin/src/middlewares/tests/addLocaleColumnToListViewMiddleware.test.js +68 -0
  64. package/admin/src/middlewares/tests/addLocaleToCollectionTypesMiddleware.test.js +200 -0
  65. package/admin/src/middlewares/tests/addLocaleToSingleTypesMiddleware.test.js +193 -0
  66. package/admin/src/middlewares/tests/extendCMEditViewLayoutMiddleware.test.js +556 -0
  67. package/admin/src/middlewares/tests/extendCTBAttrributeInitialDataMiddleware.test.js +124 -0
  68. package/admin/src/middlewares/tests/extendCTBInitialDataMiddleware.test.js +92 -0
  69. package/admin/src/middlewares/tests/localePermissionMiddleware.test.js +150 -0
  70. package/admin/src/middlewares/utils/addLocaleToLinksSearch.js +56 -0
  71. package/admin/src/middlewares/utils/tests/addLocaleToLinksSearch.test.js +137 -0
  72. package/admin/src/permissions.js +9 -0
  73. package/admin/src/pluginId.js +5 -0
  74. package/admin/src/schemas.js +7 -0
  75. package/admin/src/selectors/selectCollectionTypesRelatedPermissions.js +4 -0
  76. package/admin/src/selectors/selectI18nLocales.js +3 -0
  77. package/admin/src/translations/en.json +60 -0
  78. package/admin/src/translations/fr.json +9 -0
  79. package/admin/src/translations/index.js +11 -0
  80. package/admin/src/translations/zh-Hans.json +60 -0
  81. package/admin/src/utils/getDefaultLocale.js +60 -0
  82. package/admin/src/utils/getInitialLocale.js +14 -0
  83. package/admin/src/utils/getLocaleFromQuery.js +7 -0
  84. package/admin/src/utils/getTrad.js +5 -0
  85. package/admin/src/utils/index.js +2 -0
  86. package/admin/src/utils/localizedFields.js +23 -0
  87. package/admin/src/utils/mutateCTBContentTypeSchema.js +66 -0
  88. package/admin/src/utils/tests/getDefaultLocale.test.js +337 -0
  89. package/admin/src/utils/tests/getInitialLocale.test.js +106 -0
  90. package/admin/src/utils/tests/mutateCTBContentTypeSchema.test.js +205 -0
  91. package/config/functions/bootstrap.js +57 -0
  92. package/config/functions/migrations/__tests__/content-type.test.js +255 -0
  93. package/config/functions/migrations/__tests__/field.test.js +150 -0
  94. package/config/functions/migrations/content-type/disable/index.js +34 -0
  95. package/config/functions/migrations/content-type/disable/migrate-for-bookshelf.js +58 -0
  96. package/config/functions/migrations/content-type/disable/migrate-for-mongoose.js +39 -0
  97. package/config/functions/migrations/content-type/enable/index.js +40 -0
  98. package/config/functions/migrations/content-type/utils/index.js +27 -0
  99. package/config/functions/migrations/field/__tests__/utils.test.js +53 -0
  100. package/config/functions/migrations/field/index.js +37 -0
  101. package/config/functions/migrations/field/migrate-for-bookshelf.js +72 -0
  102. package/config/functions/migrations/field/migrate-for-mongoose.js +24 -0
  103. package/config/functions/migrations/field/migrate.js +55 -0
  104. package/config/functions/migrations/field/utils.js +58 -0
  105. package/config/functions/register.js +46 -0
  106. package/config/policies/validateLocaleCreation.js +68 -0
  107. package/config/routes.json +64 -0
  108. package/constants/__tests__/index.test.js +27 -0
  109. package/constants/index.js +36 -0
  110. package/constants/iso-locales.json +2002 -0
  111. package/controllers/__tests__/content-types.test.js +113 -0
  112. package/controllers/__tests__/iso-locales.test.js +26 -0
  113. package/controllers/__tests__/locales.test.js +308 -0
  114. package/controllers/content-types.js +64 -0
  115. package/controllers/iso-locales.js +11 -0
  116. package/controllers/locales.js +104 -0
  117. package/domain/locale.js +10 -0
  118. package/middlewares/i18n/defaults.json +5 -0
  119. package/middlewares/i18n/index.js +28 -0
  120. package/models/Locale.settings.json +31 -0
  121. package/oas.yml +195 -0
  122. package/package.json +31 -0
  123. package/services/__tests__/__snapshots__/iso-locales.test.js.snap +2006 -0
  124. package/services/__tests__/content-types.test.js +545 -0
  125. package/services/__tests__/core-api.test.js +106 -0
  126. package/services/__tests__/entity-service-decorator.test.js +280 -0
  127. package/services/__tests__/iso-locales.test.js +11 -0
  128. package/services/__tests__/locales.test.js +237 -0
  129. package/services/__tests__/localizations.test.js +187 -0
  130. package/services/__tests__/metrics.test.js +90 -0
  131. package/services/content-types.js +200 -0
  132. package/services/core-api.js +296 -0
  133. package/services/entity-service-decorator.js +155 -0
  134. package/services/iso-locales.js +9 -0
  135. package/services/locales.js +97 -0
  136. package/services/localizations.js +65 -0
  137. package/services/metrics.js +24 -0
  138. package/services/permissions/actions.js +124 -0
  139. package/services/permissions/engine.js +63 -0
  140. package/services/permissions/sections-builder.js +48 -0
  141. package/services/permissions.js +11 -0
  142. package/tests/content-manager/list-relation.test.e2e.js +122 -0
  143. package/tests/graphql.test.e2e.js +120 -0
  144. package/tests/locales.test.e2e.js +414 -0
  145. package/utils/index.js +20 -0
  146. package/validation/content-types.js +30 -0
  147. package/validation/locales.js +39 -0
@@ -0,0 +1,13 @@
1
+ import { useSelector } from 'react-redux';
2
+ import get from 'lodash/get';
3
+
4
+ const selectContentManagerListViewPluginOptions = state =>
5
+ state.get('content-manager_listView').contentType.pluginOptions;
6
+
7
+ const useHasI18n = () => {
8
+ const pluginOptions = useSelector(selectContentManagerListViewPluginOptions);
9
+
10
+ return get(pluginOptions, 'i18n.localized', false);
11
+ };
12
+
13
+ export default useHasI18n;
@@ -0,0 +1,35 @@
1
+ import { useEffect } from 'react';
2
+ import { request } from 'strapi-helper-plugin';
3
+ import { useSelector, useDispatch } from 'react-redux';
4
+ import { RESOLVE_LOCALES } from '../constants';
5
+
6
+ const fetchLocalesList = async () => {
7
+ try {
8
+ const data = await request('/i18n/locales', {
9
+ method: 'GET',
10
+ });
11
+
12
+ return data;
13
+ } catch (e) {
14
+ strapi.notification.toggle({
15
+ type: 'warning',
16
+ message: { id: 'notification.error' },
17
+ });
18
+
19
+ return e;
20
+ }
21
+ };
22
+
23
+ const useLocales = () => {
24
+ const dispatch = useDispatch();
25
+ const locales = useSelector(state => state.get('i18n_locales').locales);
26
+ const isLoading = useSelector(state => state.get('i18n_locales').isLoading);
27
+
28
+ useEffect(() => {
29
+ fetchLocalesList().then(locales => dispatch({ type: RESOLVE_LOCALES, locales }));
30
+ }, [dispatch]);
31
+
32
+ return { locales, isLoading };
33
+ };
34
+
35
+ export default useLocales;
@@ -0,0 +1,169 @@
1
+ import React from 'react';
2
+ import get from 'lodash/get';
3
+ import * as yup from 'yup';
4
+ import pluginPkg from '../../package.json';
5
+ import pluginLogo from './assets/images/logo.svg';
6
+ import CheckboxConfirmation from './components/CheckboxConfirmation';
7
+ import CMEditViewInjectedComponents from './components/CMEditViewInjectedComponents';
8
+ import Initializer from './containers/Initializer';
9
+ import SettingsPage from './containers/SettingsPage';
10
+ import LocalePicker from './components/LocalePicker';
11
+ import middlewares from './middlewares';
12
+ import pluginPermissions from './permissions';
13
+ import pluginId from './pluginId';
14
+ import trads from './translations';
15
+ import { getTrad } from './utils';
16
+ import mutateCTBContentTypeSchema from './utils/mutateCTBContentTypeSchema';
17
+ import LOCALIZED_FIELDS from './utils/localizedFields';
18
+ import i18nReducers from './hooks/reducers';
19
+ import DeleteModalAdditionalInfos from './components/DeleteModalAdditionalInfos';
20
+
21
+ export default strapi => {
22
+ const pluginDescription = pluginPkg.strapi.description || pluginPkg.description;
23
+
24
+ middlewares.forEach(middleware => {
25
+ strapi.middlewares.add(middleware);
26
+ });
27
+
28
+ const plugin = {
29
+ description: pluginDescription,
30
+ icon: pluginPkg.strapi.icon,
31
+ id: pluginId,
32
+ isReady: false,
33
+ isRequired: pluginPkg.strapi.required || false,
34
+ mainComponent: null,
35
+ name: pluginPkg.strapi.name,
36
+ pluginLogo,
37
+ preventComponentRendering: false,
38
+ settings: {
39
+ global: {
40
+ links: [
41
+ {
42
+ title: {
43
+ id: getTrad('plugin.name'),
44
+ defaultMessage: 'Internationalization',
45
+ },
46
+ name: 'internationalization',
47
+ to: `${strapi.settingsBaseURL}/internationalization`,
48
+ Component: () => <SettingsPage />,
49
+ permissions: pluginPermissions.accessMain,
50
+ },
51
+ ],
52
+ },
53
+ },
54
+ trads,
55
+ reducers: i18nReducers,
56
+ boot(app) {
57
+ const ctbPlugin = app.getPlugin('content-type-builder');
58
+ const cmPlugin = app.getPlugin('content-manager');
59
+
60
+ if (cmPlugin) {
61
+ cmPlugin.injectComponent('editView', 'informations', {
62
+ name: 'i18n-locale-filter-edit-view',
63
+ Component: CMEditViewInjectedComponents,
64
+ });
65
+ cmPlugin.injectComponent('listView', 'actions', {
66
+ name: 'i18n-locale-filter',
67
+ Component: LocalePicker,
68
+ });
69
+
70
+ cmPlugin.injectComponent('listView', 'deleteModalAdditionalInfos', {
71
+ name: 'i18n-delete-bullets-in-modal',
72
+ Component: DeleteModalAdditionalInfos,
73
+ });
74
+ }
75
+
76
+ if (ctbPlugin) {
77
+ const ctbFormsAPI = ctbPlugin.apis.forms;
78
+ ctbFormsAPI.addContentTypeSchemaMutation(mutateCTBContentTypeSchema);
79
+ ctbFormsAPI.components.add({ id: 'checkboxConfirmation', component: CheckboxConfirmation });
80
+
81
+ ctbFormsAPI.extendContentType({
82
+ validator: () => ({
83
+ i18n: yup.object().shape({
84
+ localized: yup.bool(),
85
+ }),
86
+ }),
87
+ form: {
88
+ advanced() {
89
+ return [
90
+ [
91
+ {
92
+ name: 'pluginOptions.i18n.localized',
93
+ description: {
94
+ id: getTrad('plugin.schema.i18n.localized.description-content-type'),
95
+ },
96
+ type: 'checkboxConfirmation',
97
+ label: { id: getTrad('plugin.schema.i18n.localized.label-content-type') },
98
+ },
99
+ ],
100
+ ];
101
+ },
102
+ },
103
+ });
104
+
105
+ ctbFormsAPI.extendFields(LOCALIZED_FIELDS, {
106
+ validator: args => ({
107
+ i18n: yup.object().shape({
108
+ localized: yup.bool().test({
109
+ name: 'ensure-unique-localization',
110
+ message: getTrad('plugin.schema.i18n.ensure-unique-localization'),
111
+ test(value) {
112
+ if (value === undefined || value) {
113
+ return true;
114
+ }
115
+
116
+ const unique = get(args, ['3', 'modifiedData', 'unique'], null);
117
+
118
+ // Unique fields must be localized
119
+ if (unique && !value) {
120
+ return false;
121
+ }
122
+
123
+ return true;
124
+ },
125
+ }),
126
+ }),
127
+ }),
128
+ form: {
129
+ advanced({ contentTypeSchema, forTarget, type, step }) {
130
+ if (forTarget !== 'contentType') {
131
+ return [];
132
+ }
133
+
134
+ const hasI18nEnabled = get(
135
+ contentTypeSchema,
136
+ ['schema', 'pluginOptions', 'i18n', 'localized'],
137
+ false
138
+ );
139
+
140
+ if (!hasI18nEnabled) {
141
+ return [];
142
+ }
143
+
144
+ if (type === 'component' && step === '1') {
145
+ return [];
146
+ }
147
+
148
+ return [
149
+ [
150
+ {
151
+ name: 'pluginOptions.i18n.localized',
152
+ description: {
153
+ id: getTrad('plugin.schema.i18n.localized.description-field'),
154
+ },
155
+ type: 'checkbox',
156
+ label: { id: getTrad('plugin.schema.i18n.localized.label-field') },
157
+ },
158
+ ],
159
+ ];
160
+ },
161
+ },
162
+ });
163
+ }
164
+ },
165
+ initializer: Initializer,
166
+ };
167
+
168
+ return strapi.registerPlugin(plugin);
169
+ };
@@ -0,0 +1,83 @@
1
+ import get from 'lodash/get';
2
+ import merge from 'lodash/merge';
3
+ import cloneDeep from 'lodash/cloneDeep';
4
+ import { parse } from 'qs';
5
+ import {
6
+ request,
7
+ formatComponentData,
8
+ contentManagementUtilRemoveFieldsFromData,
9
+ } from 'strapi-helper-plugin';
10
+ import pluginId from '../pluginId';
11
+
12
+ const addCommonFieldsToInitialDataMiddleware = () => ({ getState, dispatch }) => next => action => {
13
+ if (action.type !== 'ContentManager/CrudReducer/INIT_FORM') {
14
+ return next(action);
15
+ }
16
+
17
+ if (!action.rawQuery) {
18
+ return next(action);
19
+ }
20
+
21
+ const search = action.rawQuery.substring(1);
22
+ const query = parse(search);
23
+ const relatedEntityId = get(query, 'plugins.i18n.relatedEntityId', null);
24
+ const locale = get(query, 'plugins.i18n.locale', null);
25
+ const isSingleType = action.isSingleType;
26
+
27
+ if (!relatedEntityId && !isSingleType) {
28
+ return next(action);
29
+ }
30
+
31
+ const cmDataStore = getState().get('content-manager_editViewCrudReducer');
32
+ const cmLayoutStore = getState().get('content-manager_editViewLayoutManager');
33
+ const { contentTypeDataStructure } = cmDataStore;
34
+ const { currentLayout } = cmLayoutStore;
35
+
36
+ const getData = async () => {
37
+ // Show a loader
38
+ dispatch({ type: 'ContentManager/CrudReducer/GET_DATA' });
39
+ const defaultDataStructure = cloneDeep(contentTypeDataStructure);
40
+
41
+ try {
42
+ const requestURL = `/${pluginId}/content-manager/actions/get-non-localized-fields`;
43
+ const body = { model: currentLayout.contentType.uid, id: relatedEntityId, locale };
44
+
45
+ const data = await request(requestURL, { method: 'POST', body });
46
+
47
+ const { nonLocalizedFields, localizations } = data;
48
+
49
+ const merged = merge(defaultDataStructure, nonLocalizedFields);
50
+
51
+ const fieldsToRemove = [
52
+ 'created_by',
53
+ 'updated_by',
54
+ 'published_at',
55
+ 'id',
56
+ '_id',
57
+ 'updated_at',
58
+ 'created_at',
59
+ ];
60
+ const cleanedMerged = contentManagementUtilRemoveFieldsFromData(
61
+ merged,
62
+ currentLayout.contentType,
63
+ currentLayout.components,
64
+ fieldsToRemove
65
+ );
66
+ cleanedMerged.localizations = localizations;
67
+
68
+ action.data = formatComponentData(
69
+ cleanedMerged,
70
+ currentLayout.contentType,
71
+ currentLayout.components
72
+ );
73
+ } catch (err) {
74
+ // Silent
75
+ }
76
+
77
+ return next(action);
78
+ };
79
+
80
+ return getData();
81
+ };
82
+
83
+ export default addCommonFieldsToInitialDataMiddleware;
@@ -0,0 +1,32 @@
1
+ import React from 'react';
2
+ import get from 'lodash/get';
3
+ import LocaleListCell from '../components/LocaleListCell/LocaleListCell';
4
+
5
+ const addLocaleColumnToListViewMiddleware = () => ({ getState }) => next => action => {
6
+ if (action.type !== 'ContentManager/ListView/SET_LIST_LAYOUT ') {
7
+ return next(action);
8
+ }
9
+
10
+ const isFieldLocalized = get(action, 'contentType.pluginOptions.i18n.localized', false);
11
+
12
+ if (!isFieldLocalized) {
13
+ return next(action);
14
+ }
15
+
16
+ const store = getState();
17
+ const { locales } = store.get('i18n_locales');
18
+
19
+ const locale = {
20
+ key: '__locale_key__',
21
+ fieldSchema: { type: 'string' },
22
+ metadatas: { label: 'Content available in', searchable: false, sortable: false },
23
+ name: 'locales',
24
+ cellFormatter: props => <LocaleListCell {...props} locales={locales} />,
25
+ };
26
+
27
+ action.displayedHeaders = [...action.displayedHeaders, locale];
28
+
29
+ return next(action);
30
+ };
31
+
32
+ export default addLocaleColumnToListViewMiddleware;
@@ -0,0 +1,25 @@
1
+ import addLocaleToLinksSearch from './utils/addLocaleToLinksSearch';
2
+
3
+ const addLocaleToCollectionTypesMiddleware = () => ({ getState }) => next => action => {
4
+ if (action.type !== 'StrapiAdmin/LeftMenu/SET_CT_OR_ST_LINKS') {
5
+ return next(action);
6
+ }
7
+
8
+ if (action.data.authorizedCtLinks.length) {
9
+ const store = getState();
10
+ const { locales } = store.get('i18n_locales');
11
+ const { collectionTypesRelatedPermissions } = store.get('permissionsManager');
12
+
13
+ action.data.authorizedCtLinks = addLocaleToLinksSearch(
14
+ action.data.authorizedCtLinks,
15
+ 'collectionType',
16
+ action.data.contentTypeSchemas,
17
+ locales,
18
+ collectionTypesRelatedPermissions
19
+ );
20
+ }
21
+
22
+ return next(action);
23
+ };
24
+
25
+ export default addLocaleToCollectionTypesMiddleware;
@@ -0,0 +1,25 @@
1
+ import addLocaleToLinksSearch from './utils/addLocaleToLinksSearch';
2
+
3
+ const addLocaleToSingleTypesMiddleware = () => ({ getState }) => next => action => {
4
+ if (action.type !== 'StrapiAdmin/LeftMenu/SET_CT_OR_ST_LINKS') {
5
+ return next(action);
6
+ }
7
+
8
+ if (action.data.authorizedStLinks.length) {
9
+ const store = getState();
10
+ const { locales } = store.get('i18n_locales');
11
+ const { collectionTypesRelatedPermissions } = store.get('permissionsManager');
12
+
13
+ action.data.authorizedStLinks = addLocaleToLinksSearch(
14
+ action.data.authorizedStLinks,
15
+ 'singleType',
16
+ action.data.contentTypeSchemas,
17
+ locales,
18
+ collectionTypesRelatedPermissions
19
+ );
20
+ }
21
+
22
+ return next(action);
23
+ };
24
+
25
+ export default addLocaleToSingleTypesMiddleware;
@@ -0,0 +1,159 @@
1
+ import React from 'react';
2
+ import get from 'lodash/get';
3
+ import { Globe, GlobeCrossed } from '@buffetjs/icons';
4
+ import { getTrad } from '../utils';
5
+
6
+ const enhanceRelationLayout = (layout, locale) =>
7
+ layout.map(current => {
8
+ const labelIcon = {
9
+ title: {
10
+ id: getTrad('Field.localized'),
11
+ defaultMessage: 'This value is unique for the selected locale',
12
+ },
13
+ icon: <Globe />,
14
+ };
15
+ let queryInfos = current.queryInfos;
16
+
17
+ if (get(current, ['targetModelPluginOptions', 'i18n', 'localized'], false)) {
18
+ queryInfos = {
19
+ ...queryInfos,
20
+ defaultParams: { ...queryInfos.defaultParams, _locale: locale },
21
+ paramsToKeep: ['plugins.i18n.locale'],
22
+ };
23
+ }
24
+
25
+ return { ...current, labelIcon, queryInfos };
26
+ });
27
+
28
+ const enhanceEditLayout = layout =>
29
+ layout.map(row => {
30
+ const enhancedRow = row.reduce((acc, field) => {
31
+ const type = get(field, ['fieldSchema', 'type'], null);
32
+ const hasI18nEnabled = get(
33
+ field,
34
+ ['fieldSchema', 'pluginOptions', 'i18n', 'localized'],
35
+ type === 'uid'
36
+ );
37
+
38
+ const labelIcon = {
39
+ title: {
40
+ id: hasI18nEnabled ? getTrad('Field.localized') : getTrad('Field.not-localized'),
41
+ defaultMessage: hasI18nEnabled
42
+ ? 'This value is unique for the selected locale'
43
+ : 'This value is common to all locales',
44
+ },
45
+ icon: hasI18nEnabled ? <Globe /> : <GlobeCrossed />,
46
+ };
47
+
48
+ acc.push({ ...field, labelIcon });
49
+
50
+ return acc;
51
+ }, []);
52
+
53
+ return enhancedRow;
54
+ });
55
+
56
+ const enhanceComponentsLayout = (components, locale) => {
57
+ return Object.keys(components).reduce((acc, current) => {
58
+ const currentComponentLayout = components[current];
59
+
60
+ const enhancedEditLayout = enhanceComponentLayoutForRelations(
61
+ currentComponentLayout.layouts.edit,
62
+ locale
63
+ );
64
+
65
+ acc[current] = {
66
+ ...currentComponentLayout,
67
+ layouts: { ...currentComponentLayout.layouts, edit: enhancedEditLayout },
68
+ };
69
+
70
+ return acc;
71
+ }, {});
72
+ };
73
+
74
+ const enhanceComponentLayoutForRelations = (layout, locale) =>
75
+ layout.map(row => {
76
+ const enhancedRow = row.reduce((acc, field) => {
77
+ if (
78
+ get(field, ['fieldSchema', 'type']) === 'relation' &&
79
+ get(field, ['targetModelPluginOptions', 'i18n', 'localized'], false)
80
+ ) {
81
+ const queryInfos = {
82
+ ...field.queryInfos,
83
+ defaultParams: { ...field.queryInfos.defaultParams, _locale: locale },
84
+ paramsToKeep: ['plugins.i18n.locale'],
85
+ };
86
+
87
+ acc.push({ ...field, queryInfos });
88
+
89
+ return acc;
90
+ }
91
+
92
+ acc.push({ ...field });
93
+
94
+ return acc;
95
+ }, []);
96
+
97
+ return enhancedRow;
98
+ });
99
+
100
+ const extendCMEditViewLayoutMiddleware = () => () => next => action => {
101
+ if (action.type !== 'ContentManager/EditViewLayoutManager/SET_LAYOUT') {
102
+ return next(action);
103
+ }
104
+
105
+ const hasi18nEnabled = get(
106
+ action,
107
+ getPathToContentType(['pluginOptions', 'i18n', 'localized']),
108
+ false
109
+ );
110
+
111
+ if (!hasi18nEnabled) {
112
+ return next(action);
113
+ }
114
+
115
+ const currentLocale = get(action, ['query', 'plugins', 'i18n', 'locale'], null);
116
+
117
+ // This might break the cm, has the user might be redirected to the homepage
118
+ if (!currentLocale) {
119
+ return next(action);
120
+ }
121
+
122
+ const editLayoutPath = getPathToContentType(['layouts', 'edit']);
123
+ const editRelationsPath = getPathToContentType(['layouts', 'editRelations']);
124
+ const editLayout = get(action, editLayoutPath);
125
+ const editRelationsLayout = get(action, editRelationsPath);
126
+ const nextEditRelationLayout = enhanceRelationLayout(editRelationsLayout, currentLocale);
127
+ const nextEditLayout = enhanceEditLayout(editLayout);
128
+
129
+ const enhancedLayouts = {
130
+ ...action.layout.contentType.layouts,
131
+ editRelations: nextEditRelationLayout,
132
+ edit: nextEditLayout,
133
+ };
134
+ const components = enhanceComponentsLayout(action.layout.components, currentLocale);
135
+
136
+ const enhancedAction = {
137
+ ...action,
138
+ layout: {
139
+ ...action.layout,
140
+ contentType: {
141
+ ...action.layout.contentType,
142
+ layouts: enhancedLayouts,
143
+ },
144
+ components,
145
+ },
146
+ };
147
+
148
+ return next(enhancedAction);
149
+ };
150
+
151
+ const getPathToContentType = pathArray => ['layout', 'contentType', ...pathArray];
152
+
153
+ export default extendCMEditViewLayoutMiddleware;
154
+ export {
155
+ enhanceComponentLayoutForRelations,
156
+ enhanceComponentsLayout,
157
+ enhanceEditLayout,
158
+ enhanceRelationLayout,
159
+ };
@@ -0,0 +1,58 @@
1
+ const extendCTBAttributeInitialDataMiddleware = () => {
2
+ return ({ getState }) => next => action => {
3
+ const enhanceAction = () => {
4
+ // the block here is to catch the error when trying to access the state
5
+ // of the ctb when the plugin is not mounted
6
+ try {
7
+ const hasi18nEnabled = getState().getIn([
8
+ 'content-type-builder_dataManagerProvider',
9
+ 'modifiedData',
10
+ 'contentType',
11
+ 'schema',
12
+ 'pluginOptions',
13
+ 'i18n',
14
+ 'localized',
15
+ ]);
16
+
17
+ if (hasi18nEnabled) {
18
+ const pluginOptions = action.options
19
+ ? { ...action.options.pluginOptions, i18n: { localized: true } }
20
+ : { i18n: { localized: true } };
21
+
22
+ return next({
23
+ ...action,
24
+ options: {
25
+ pluginOptions,
26
+ },
27
+ });
28
+ }
29
+
30
+ return next(action);
31
+ } catch (err) {
32
+ return next(action);
33
+ }
34
+ };
35
+
36
+ if (
37
+ action.type === 'ContentTypeBuilder/FormModal/SET_ATTRIBUTE_DATA_SCHEMA' &&
38
+ action.forTarget === 'contentType' &&
39
+ !['relation', 'component'].includes(action.attributeType) &&
40
+ !action.isEditing
41
+ ) {
42
+ return enhanceAction();
43
+ }
44
+
45
+ if (
46
+ (action.type ===
47
+ 'ContentTypeBuilder/FormModal/RESET_PROPS_AND_SET_FORM_FOR_ADDING_AN_EXISTING_COMPO' ||
48
+ action.type === 'ContentTypeBuilder/FormModal/RESET_PROPS_AND_SAVE_CURRENT_DATA') &&
49
+ action.forTarget === 'contentType'
50
+ ) {
51
+ return enhanceAction();
52
+ }
53
+
54
+ return next(action);
55
+ };
56
+ };
57
+
58
+ export default extendCTBAttributeInitialDataMiddleware;
@@ -0,0 +1,33 @@
1
+ import { has } from 'lodash';
2
+
3
+ const extendCTBInitialDataMiddleware = () => {
4
+ return () => next => action => {
5
+ if (
6
+ action.type === 'ContentTypeBuilder/FormModal/SET_DATA_TO_EDIT' &&
7
+ action.modalType === 'contentType'
8
+ ) {
9
+ const i18n = { localized: false };
10
+
11
+ const pluginOptions = action.data.pluginOptions
12
+ ? { ...action.data.pluginOptions, i18n }
13
+ : { i18n };
14
+
15
+ const data = { ...action.data, pluginOptions };
16
+
17
+ if (action.actionType === 'create') {
18
+ return next({ ...action, data });
19
+ }
20
+
21
+ // Override the action if the pluginOption config does not contain i18n
22
+ // In this case we need to set the proper initialData shape
23
+ if (!has(action.data.pluginOptions, 'i18n.localized')) {
24
+ return next({ ...action, data });
25
+ }
26
+ }
27
+
28
+ // action is not the one we want to override
29
+ return next(action);
30
+ };
31
+ };
32
+
33
+ export default extendCTBInitialDataMiddleware;
@@ -0,0 +1,21 @@
1
+ import addCommonFieldsToInitialDataMiddleware from './addCommonFieldsToInitialDataMiddleware';
2
+ import addLocaleToCollectionTypesMiddleware from './addLocaleToCollectionTypesMiddleware';
3
+ import addLocaleToSingleTypesMiddleware from './addLocaleToSingleTypesMiddleware';
4
+ import extendCMEditViewLayoutMiddleware from './extendCMEditViewLayoutMiddleware';
5
+ import extendCTBInitialDataMiddleware from './extendCTBInitialDataMiddleware';
6
+ import extendCTBAttributeInitialDataMiddleware from './extendCTBAttributeInitialDataMiddleware';
7
+ import addLocaleColumnToListViewMiddleware from './addLocaleColumnToListViewMiddleware';
8
+ import localePermissionMiddleware from './localePermissionMiddleware';
9
+
10
+ const middlewares = [
11
+ addCommonFieldsToInitialDataMiddleware,
12
+ addLocaleToCollectionTypesMiddleware,
13
+ addLocaleToSingleTypesMiddleware,
14
+ extendCMEditViewLayoutMiddleware,
15
+ extendCTBInitialDataMiddleware,
16
+ extendCTBAttributeInitialDataMiddleware,
17
+ addLocaleColumnToListViewMiddleware,
18
+ localePermissionMiddleware,
19
+ ];
20
+
21
+ export default middlewares;