@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.
- package/LICENSE +22 -0
- package/README.md +19 -0
- package/admin/src/assets/images/logo.svg +1 -0
- package/admin/src/components/CMEditViewCopyLocale/index.js +183 -0
- package/admin/src/components/CMEditViewCopyLocale/utils/cleanData.js +36 -0
- package/admin/src/components/CMEditViewCopyLocale/utils/generateOptions.js +22 -0
- package/admin/src/components/CMEditViewCopyLocale/utils/index.js +2 -0
- package/admin/src/components/CMEditViewCopyLocale/utils/removePasswordAndRelationsFieldFromData.js +54 -0
- package/admin/src/components/CMEditViewCopyLocale/utils/tests/cleanData.test.js +83 -0
- package/admin/src/components/CMEditViewCopyLocale/utils/tests/data.js +219 -0
- package/admin/src/components/CMEditViewCopyLocale/utils/tests/generateOptions.test.js +79 -0
- package/admin/src/components/CMEditViewCopyLocale/utils/tests/removePasswordAndRelationsFieldFromData.test.js +40 -0
- package/admin/src/components/CMEditViewInjectedComponents/index.js +58 -0
- package/admin/src/components/CMEditViewLocalePicker/Option.js +66 -0
- package/admin/src/components/CMEditViewLocalePicker/Wrapper.js +8 -0
- package/admin/src/components/CMEditViewLocalePicker/index.js +160 -0
- package/admin/src/components/CMEditViewLocalePicker/utils/addStatusColorToLocale.js +24 -0
- package/admin/src/components/CMEditViewLocalePicker/utils/createLocalesOption.js +20 -0
- package/admin/src/components/CMEditViewLocalePicker/utils/index.js +2 -0
- package/admin/src/components/CheckboxConfirmation/Wrapper.js +12 -0
- package/admin/src/components/CheckboxConfirmation/index.js +70 -0
- package/admin/src/components/DeleteModalAdditionalInfos/index.js +25 -0
- package/admin/src/components/LocaleList/index.js +101 -0
- package/admin/src/components/LocaleListCell/LocaleListCell.js +90 -0
- package/admin/src/components/LocaleListCell/tests/LocaleListCell.test.js +128 -0
- package/admin/src/components/LocalePicker/index.js +126 -0
- package/admin/src/components/LocaleRow/index.js +77 -0
- package/admin/src/components/ModalCreate/AdvancedForm.js +45 -0
- package/admin/src/components/ModalCreate/BaseForm.js +103 -0
- package/admin/src/components/ModalCreate/index.js +136 -0
- package/admin/src/components/ModalDelete/index.js +49 -0
- package/admin/src/components/ModalEdit/AdvancedForm.js +51 -0
- package/admin/src/components/ModalEdit/BaseForm.js +91 -0
- package/admin/src/components/ModalEdit/index.js +122 -0
- package/admin/src/components/SettingsModal.js +66 -0
- package/admin/src/components/index.js +2 -0
- package/admin/src/containers/Initializer.js +31 -0
- package/admin/src/containers/SettingsPage/LocaleSettingsPage.js +69 -0
- package/admin/src/containers/SettingsPage/index.js +33 -0
- package/admin/src/containers/SettingsPage/tests/SettingsPage.test.js +744 -0
- package/admin/src/containers/SettingsPage/tests/__snapshots__/SettingsPage.test.js.snap +241 -0
- package/admin/src/hooks/constants.js +6 -0
- package/admin/src/hooks/reducers.js +63 -0
- package/admin/src/hooks/tests/reducers.test.js +203 -0
- package/admin/src/hooks/useAddLocale/index.js +60 -0
- package/admin/src/hooks/useContentTypePermissions/index.js +16 -0
- package/admin/src/hooks/useDefaultLocales/index.js +27 -0
- package/admin/src/hooks/useDeleteLocale/index.js +45 -0
- package/admin/src/hooks/useEditLocale/index.js +46 -0
- package/admin/src/hooks/useHasI18n/index.js +13 -0
- package/admin/src/hooks/useLocales/index.js +35 -0
- package/admin/src/index.js +169 -0
- package/admin/src/middlewares/addCommonFieldsToInitialDataMiddleware.js +83 -0
- package/admin/src/middlewares/addLocaleColumnToListViewMiddleware.js +32 -0
- package/admin/src/middlewares/addLocaleToCollectionTypesMiddleware.js +25 -0
- package/admin/src/middlewares/addLocaleToSingleTypesMiddleware.js +25 -0
- package/admin/src/middlewares/extendCMEditViewLayoutMiddleware.js +159 -0
- package/admin/src/middlewares/extendCTBAttributeInitialDataMiddleware.js +58 -0
- package/admin/src/middlewares/extendCTBInitialDataMiddleware.js +33 -0
- package/admin/src/middlewares/index.js +21 -0
- package/admin/src/middlewares/localePermissionMiddleware.js +39 -0
- package/admin/src/middlewares/tests/addCommonFieldsToInitialDataMiddleware.test.js +97 -0
- package/admin/src/middlewares/tests/addLocaleColumnToListViewMiddleware.test.js +68 -0
- package/admin/src/middlewares/tests/addLocaleToCollectionTypesMiddleware.test.js +200 -0
- package/admin/src/middlewares/tests/addLocaleToSingleTypesMiddleware.test.js +193 -0
- package/admin/src/middlewares/tests/extendCMEditViewLayoutMiddleware.test.js +556 -0
- package/admin/src/middlewares/tests/extendCTBAttrributeInitialDataMiddleware.test.js +124 -0
- package/admin/src/middlewares/tests/extendCTBInitialDataMiddleware.test.js +92 -0
- package/admin/src/middlewares/tests/localePermissionMiddleware.test.js +150 -0
- package/admin/src/middlewares/utils/addLocaleToLinksSearch.js +56 -0
- package/admin/src/middlewares/utils/tests/addLocaleToLinksSearch.test.js +137 -0
- package/admin/src/permissions.js +9 -0
- package/admin/src/pluginId.js +5 -0
- package/admin/src/schemas.js +7 -0
- package/admin/src/selectors/selectCollectionTypesRelatedPermissions.js +4 -0
- package/admin/src/selectors/selectI18nLocales.js +3 -0
- package/admin/src/translations/en.json +60 -0
- package/admin/src/translations/fr.json +9 -0
- package/admin/src/translations/index.js +11 -0
- package/admin/src/translations/zh-Hans.json +60 -0
- package/admin/src/utils/getDefaultLocale.js +60 -0
- package/admin/src/utils/getInitialLocale.js +14 -0
- package/admin/src/utils/getLocaleFromQuery.js +7 -0
- package/admin/src/utils/getTrad.js +5 -0
- package/admin/src/utils/index.js +2 -0
- package/admin/src/utils/localizedFields.js +23 -0
- package/admin/src/utils/mutateCTBContentTypeSchema.js +66 -0
- package/admin/src/utils/tests/getDefaultLocale.test.js +337 -0
- package/admin/src/utils/tests/getInitialLocale.test.js +106 -0
- package/admin/src/utils/tests/mutateCTBContentTypeSchema.test.js +205 -0
- package/config/functions/bootstrap.js +57 -0
- package/config/functions/migrations/__tests__/content-type.test.js +255 -0
- package/config/functions/migrations/__tests__/field.test.js +150 -0
- package/config/functions/migrations/content-type/disable/index.js +34 -0
- package/config/functions/migrations/content-type/disable/migrate-for-bookshelf.js +58 -0
- package/config/functions/migrations/content-type/disable/migrate-for-mongoose.js +39 -0
- package/config/functions/migrations/content-type/enable/index.js +40 -0
- package/config/functions/migrations/content-type/utils/index.js +27 -0
- package/config/functions/migrations/field/__tests__/utils.test.js +53 -0
- package/config/functions/migrations/field/index.js +37 -0
- package/config/functions/migrations/field/migrate-for-bookshelf.js +72 -0
- package/config/functions/migrations/field/migrate-for-mongoose.js +24 -0
- package/config/functions/migrations/field/migrate.js +55 -0
- package/config/functions/migrations/field/utils.js +58 -0
- package/config/functions/register.js +46 -0
- package/config/policies/validateLocaleCreation.js +68 -0
- package/config/routes.json +64 -0
- package/constants/__tests__/index.test.js +27 -0
- package/constants/index.js +36 -0
- package/constants/iso-locales.json +2002 -0
- package/controllers/__tests__/content-types.test.js +113 -0
- package/controllers/__tests__/iso-locales.test.js +26 -0
- package/controllers/__tests__/locales.test.js +308 -0
- package/controllers/content-types.js +64 -0
- package/controllers/iso-locales.js +11 -0
- package/controllers/locales.js +104 -0
- package/domain/locale.js +10 -0
- package/middlewares/i18n/defaults.json +5 -0
- package/middlewares/i18n/index.js +28 -0
- package/models/Locale.settings.json +31 -0
- package/oas.yml +195 -0
- package/package.json +31 -0
- package/services/__tests__/__snapshots__/iso-locales.test.js.snap +2006 -0
- package/services/__tests__/content-types.test.js +545 -0
- package/services/__tests__/core-api.test.js +106 -0
- package/services/__tests__/entity-service-decorator.test.js +280 -0
- package/services/__tests__/iso-locales.test.js +11 -0
- package/services/__tests__/locales.test.js +237 -0
- package/services/__tests__/localizations.test.js +187 -0
- package/services/__tests__/metrics.test.js +90 -0
- package/services/content-types.js +200 -0
- package/services/core-api.js +296 -0
- package/services/entity-service-decorator.js +155 -0
- package/services/iso-locales.js +9 -0
- package/services/locales.js +97 -0
- package/services/localizations.js +65 -0
- package/services/metrics.js +24 -0
- package/services/permissions/actions.js +124 -0
- package/services/permissions/engine.js +63 -0
- package/services/permissions/sections-builder.js +48 -0
- package/services/permissions.js +11 -0
- package/tests/content-manager/list-relation.test.e2e.js +122 -0
- package/tests/graphql.test.e2e.js +120 -0
- package/tests/locales.test.e2e.js +414 -0
- package/utils/index.js +20 -0
- package/validation/content-types.js +30 -0
- package/validation/locales.js +39 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
jest.mock('../localizations', () => {
|
|
4
|
+
return {
|
|
5
|
+
syncLocalizations: jest.fn(async () => {}),
|
|
6
|
+
syncNonLocalizedAttributes: jest.fn(async () => {}),
|
|
7
|
+
};
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const { decorator } = require('../entity-service-decorator');
|
|
11
|
+
const { syncLocalizations, syncNonLocalizedAttributes } = require('../localizations');
|
|
12
|
+
const locales = require('../locales');
|
|
13
|
+
const contentTypes = require('../content-types');
|
|
14
|
+
|
|
15
|
+
const model = {
|
|
16
|
+
pluginOptions: {
|
|
17
|
+
i18n: {
|
|
18
|
+
localized: true,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const nonLocalizedModel = {
|
|
24
|
+
pluginOptions: {
|
|
25
|
+
i18n: {
|
|
26
|
+
localized: false,
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const models = {
|
|
32
|
+
'test-model': model,
|
|
33
|
+
'non-localized-model': nonLocalizedModel,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
describe('Entity service decorator', () => {
|
|
37
|
+
beforeAll(() => {
|
|
38
|
+
global.strapi = {
|
|
39
|
+
plugins: {
|
|
40
|
+
i18n: {
|
|
41
|
+
services: {
|
|
42
|
+
locales,
|
|
43
|
+
'content-types': contentTypes,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
query() {
|
|
48
|
+
return {
|
|
49
|
+
create() {},
|
|
50
|
+
update() {},
|
|
51
|
+
};
|
|
52
|
+
},
|
|
53
|
+
db: {
|
|
54
|
+
getModel(uid) {
|
|
55
|
+
return models[uid || 'test-model'];
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
store: () => ({ get: () => 'en' }),
|
|
59
|
+
};
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
beforeEach(() => {
|
|
63
|
+
syncLocalizations.mockClear();
|
|
64
|
+
syncNonLocalizedAttributes.mockClear();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe('wrapOptions', () => {
|
|
68
|
+
test('Calls original wrapOptions', async () => {
|
|
69
|
+
const defaultService = {
|
|
70
|
+
wrapOptions: jest.fn(() => Promise.resolve('li')),
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const service = decorator(defaultService);
|
|
74
|
+
|
|
75
|
+
const input = { populate: ['test'] };
|
|
76
|
+
await service.wrapOptions(input, { model: 'test-model' });
|
|
77
|
+
|
|
78
|
+
expect(defaultService.wrapOptions).toHaveBeenCalledWith(input, { model: 'test-model' });
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test('Does not wrap options if model is not localized', async () => {
|
|
82
|
+
const defaultService = {
|
|
83
|
+
wrapOptions: jest.fn(opts => Promise.resolve(opts)),
|
|
84
|
+
};
|
|
85
|
+
const service = decorator(defaultService);
|
|
86
|
+
|
|
87
|
+
const input = { populate: ['test'] };
|
|
88
|
+
const output = await service.wrapOptions(input, { model: 'non-localized-model' });
|
|
89
|
+
|
|
90
|
+
expect(output).toStrictEqual(input);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test('does not change non params options', async () => {
|
|
94
|
+
const defaultService = {
|
|
95
|
+
wrapOptions: jest.fn(opts => Promise.resolve(opts)),
|
|
96
|
+
};
|
|
97
|
+
const service = decorator(defaultService);
|
|
98
|
+
|
|
99
|
+
const input = { populate: ['test'] };
|
|
100
|
+
const output = await service.wrapOptions(input, { model: 'test-model' });
|
|
101
|
+
|
|
102
|
+
expect(output.populate).toStrictEqual(input.populate);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test('Adds locale param', async () => {
|
|
106
|
+
const defaultService = {
|
|
107
|
+
wrapOptions: jest.fn(opts => Promise.resolve(opts)),
|
|
108
|
+
};
|
|
109
|
+
const service = decorator(defaultService);
|
|
110
|
+
|
|
111
|
+
const input = { populate: ['test'] };
|
|
112
|
+
const output = await service.wrapOptions(input, { model: 'test-model' });
|
|
113
|
+
|
|
114
|
+
expect(output).toMatchObject({ params: { locale: 'en' } });
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
const testData = [
|
|
118
|
+
['findOne', { id: 1 }],
|
|
119
|
+
['update', { id: 1 }],
|
|
120
|
+
['delete', { id: 1 }],
|
|
121
|
+
['delete', { id_in: [1] }],
|
|
122
|
+
['findOne', { _where: { id: 1 } }],
|
|
123
|
+
['update', { _where: { id: 1 } }],
|
|
124
|
+
['delete', { _where: { id: 1 } }],
|
|
125
|
+
['delete', { _where: { id_in: [1] } }],
|
|
126
|
+
['findOne', { _where: [{ id: 1 }] }],
|
|
127
|
+
['update', { _where: [{ id: 1 }] }],
|
|
128
|
+
['delete', { _where: [{ id: 1 }] }],
|
|
129
|
+
['delete', { _where: [{ id_in: [1] }] }],
|
|
130
|
+
];
|
|
131
|
+
|
|
132
|
+
test.each(testData)(
|
|
133
|
+
"Doesn't add locale param when the params contain id or id_in - %s",
|
|
134
|
+
async (action, params) => {
|
|
135
|
+
const defaultService = {
|
|
136
|
+
wrapOptions: jest.fn(opts => Promise.resolve(opts)),
|
|
137
|
+
};
|
|
138
|
+
const service = decorator(defaultService);
|
|
139
|
+
|
|
140
|
+
const input = Object.assign({ populate: ['test'], params });
|
|
141
|
+
const output = await service.wrapOptions(input, { model: 'test-model', action });
|
|
142
|
+
|
|
143
|
+
expect(output).toEqual({ populate: ['test'], params });
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
test('Replaces _locale param', async () => {
|
|
148
|
+
const defaultService = {
|
|
149
|
+
wrapOptions: jest.fn(opts => Promise.resolve(opts)),
|
|
150
|
+
};
|
|
151
|
+
const service = decorator(defaultService);
|
|
152
|
+
|
|
153
|
+
const input = {
|
|
154
|
+
params: {
|
|
155
|
+
_locale: 'fr',
|
|
156
|
+
},
|
|
157
|
+
populate: ['test'],
|
|
158
|
+
};
|
|
159
|
+
const output = await service.wrapOptions(input, { model: 'test-model' });
|
|
160
|
+
|
|
161
|
+
expect(output).toMatchObject({ params: { locale: 'fr' } });
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
describe('create', () => {
|
|
166
|
+
test('Calls original create', async () => {
|
|
167
|
+
const entry = {
|
|
168
|
+
id: 1,
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const defaultService = {
|
|
172
|
+
create: jest.fn(() => Promise.resolve(entry)),
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const service = decorator(defaultService);
|
|
176
|
+
|
|
177
|
+
const input = { data: { title: 'title ' } };
|
|
178
|
+
await service.create(input, { model: 'test-model' });
|
|
179
|
+
|
|
180
|
+
expect(defaultService.create).toHaveBeenCalledWith(input, { model: 'test-model' });
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
test('Calls syncLocalizations if model is localized', async () => {
|
|
184
|
+
const entry = {
|
|
185
|
+
id: 1,
|
|
186
|
+
localizations: [{ id: 2 }],
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const defaultService = {
|
|
190
|
+
create: jest.fn(() => Promise.resolve(entry)),
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
const service = decorator(defaultService);
|
|
194
|
+
|
|
195
|
+
const input = { data: { title: 'title ' } };
|
|
196
|
+
await service.create(input, { model: 'test-model' });
|
|
197
|
+
|
|
198
|
+
expect(defaultService.create).toHaveBeenCalledWith(input, { model: 'test-model' });
|
|
199
|
+
expect(syncLocalizations).toHaveBeenCalledWith(entry, { model });
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
test('Skip processing if model is not localized', async () => {
|
|
203
|
+
const entry = {
|
|
204
|
+
id: 1,
|
|
205
|
+
localizations: [{ id: 2 }],
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
const defaultService = {
|
|
209
|
+
create: jest.fn(() => Promise.resolve(entry)),
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
const service = decorator(defaultService);
|
|
213
|
+
|
|
214
|
+
const input = { data: { title: 'title ' } };
|
|
215
|
+
const output = await service.create(input, { model: 'non-localized-model' });
|
|
216
|
+
|
|
217
|
+
expect(defaultService.create).toHaveBeenCalledWith(input, { model: 'non-localized-model' });
|
|
218
|
+
expect(syncLocalizations).not.toHaveBeenCalled();
|
|
219
|
+
expect(output).toStrictEqual(entry);
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
describe('update', () => {
|
|
224
|
+
test('Calls original update', async () => {
|
|
225
|
+
const entry = {
|
|
226
|
+
id: 1,
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
const defaultService = {
|
|
230
|
+
update: jest.fn(() => Promise.resolve(entry)),
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
const service = decorator(defaultService);
|
|
234
|
+
|
|
235
|
+
const input = { params: { id: 1 }, data: { title: 'title ' } };
|
|
236
|
+
await service.update(input, { model: 'test-model' });
|
|
237
|
+
|
|
238
|
+
expect(defaultService.update).toHaveBeenCalledWith(input, { model: 'test-model' });
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
test('Calls syncNonLocalizedAttributes if model is localized', async () => {
|
|
242
|
+
const entry = {
|
|
243
|
+
id: 1,
|
|
244
|
+
localizations: [{ id: 2 }],
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
const defaultService = {
|
|
248
|
+
update: jest.fn(() => Promise.resolve(entry)),
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
const service = decorator(defaultService);
|
|
252
|
+
|
|
253
|
+
const input = { params: { id: 1 }, data: { title: 'title ' } };
|
|
254
|
+
const output = await service.update(input, { model: 'test-model' });
|
|
255
|
+
|
|
256
|
+
expect(defaultService.update).toHaveBeenCalledWith(input, { model: 'test-model' });
|
|
257
|
+
expect(syncNonLocalizedAttributes).toHaveBeenCalledWith(entry, { model });
|
|
258
|
+
expect(output).toStrictEqual(entry);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
test('Skip processing if model is not localized', async () => {
|
|
262
|
+
const entry = {
|
|
263
|
+
id: 1,
|
|
264
|
+
localizations: [{ id: 2 }],
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
const defaultService = {
|
|
268
|
+
update: jest.fn(() => Promise.resolve(entry)),
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
const service = decorator(defaultService);
|
|
272
|
+
|
|
273
|
+
const input = { params: { id: 1 }, data: { title: 'title ' } };
|
|
274
|
+
await service.update(input, { model: 'non-localized-model' });
|
|
275
|
+
|
|
276
|
+
expect(defaultService.update).toHaveBeenCalledWith(input, { model: 'non-localized-model' });
|
|
277
|
+
expect(syncNonLocalizedAttributes).not.toHaveBeenCalled();
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
});
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const localesService = require('../locales');
|
|
4
|
+
|
|
5
|
+
const fakeMetricsService = {
|
|
6
|
+
sendDidInitializeEvent() {},
|
|
7
|
+
sendDidUpdateI18nLocalesEvent() {},
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
describe('Locales', () => {
|
|
11
|
+
describe('setIsDefault', () => {
|
|
12
|
+
test('Set isDefault to false', async () => {
|
|
13
|
+
const get = jest.fn(() => Promise.resolve('en'));
|
|
14
|
+
global.strapi = { store: () => ({ get }) };
|
|
15
|
+
|
|
16
|
+
const locale = {
|
|
17
|
+
code: 'fr',
|
|
18
|
+
name: 'French',
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const enrichedLocale = await localesService.setIsDefault(locale);
|
|
22
|
+
expect(enrichedLocale).toMatchObject({
|
|
23
|
+
...locale,
|
|
24
|
+
isDefault: false,
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('Set isDefault to true', async () => {
|
|
29
|
+
const get = jest.fn(() => Promise.resolve('en'));
|
|
30
|
+
global.strapi = { store: () => ({ get }) };
|
|
31
|
+
|
|
32
|
+
const locale = {
|
|
33
|
+
code: 'en',
|
|
34
|
+
name: 'English',
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const enrichedLocale = await localesService.setIsDefault(locale);
|
|
38
|
+
expect(enrichedLocale).toMatchObject({
|
|
39
|
+
...locale,
|
|
40
|
+
isDefault: true,
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe('getDefaultLocale', () => {
|
|
46
|
+
test('get default locale', async () => {
|
|
47
|
+
const get = jest.fn(() => Promise.resolve('en'));
|
|
48
|
+
global.strapi = { store: () => ({ get }) };
|
|
49
|
+
|
|
50
|
+
const defaultLocaleCode = await localesService.getDefaultLocale();
|
|
51
|
+
expect(defaultLocaleCode).toBe('en');
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('setDefaultLocale', () => {
|
|
56
|
+
test('set default locale', async () => {
|
|
57
|
+
const set = jest.fn(() => Promise.resolve());
|
|
58
|
+
global.strapi = { store: () => ({ set }) };
|
|
59
|
+
|
|
60
|
+
await localesService.setDefaultLocale({ code: 'fr-CA' });
|
|
61
|
+
expect(set).toHaveBeenCalledWith({ key: 'default_locale', value: 'fr-CA' });
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe('CRUD', () => {
|
|
66
|
+
test('find', async () => {
|
|
67
|
+
const locales = [{ name: 'French', code: 'fr' }];
|
|
68
|
+
const find = jest.fn(() => Promise.resolve(locales));
|
|
69
|
+
const query = jest.fn(() => ({ find }));
|
|
70
|
+
global.strapi = { query };
|
|
71
|
+
const params = { name_contains: 'en' };
|
|
72
|
+
|
|
73
|
+
const localesFound = await localesService.find(params);
|
|
74
|
+
expect(query).toHaveBeenCalledWith('locale', 'i18n');
|
|
75
|
+
expect(find).toHaveBeenCalledWith(params);
|
|
76
|
+
expect(localesFound).toMatchObject(locales);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test('findById', async () => {
|
|
80
|
+
const locale = { name: 'French', code: 'fr' };
|
|
81
|
+
const findOne = jest.fn(() => Promise.resolve(locale));
|
|
82
|
+
const query = jest.fn(() => ({ findOne }));
|
|
83
|
+
global.strapi = { query };
|
|
84
|
+
|
|
85
|
+
const localeFound = await localesService.findById(1);
|
|
86
|
+
expect(query).toHaveBeenCalledWith('locale', 'i18n');
|
|
87
|
+
expect(findOne).toHaveBeenCalledWith({ id: 1 });
|
|
88
|
+
expect(localeFound).toMatchObject(locale);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test('findByCode', async () => {
|
|
92
|
+
const locale = { name: 'French', code: 'fr' };
|
|
93
|
+
const findOne = jest.fn(() => Promise.resolve(locale));
|
|
94
|
+
const query = jest.fn(() => ({ findOne }));
|
|
95
|
+
global.strapi = { query };
|
|
96
|
+
|
|
97
|
+
const localeFound = await localesService.findByCode('fr');
|
|
98
|
+
expect(query).toHaveBeenCalledWith('locale', 'i18n');
|
|
99
|
+
expect(findOne).toHaveBeenCalledWith({ code: 'fr' });
|
|
100
|
+
expect(localeFound).toMatchObject(locale);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test('create', async () => {
|
|
104
|
+
const locale = { name: 'French', code: 'fr' };
|
|
105
|
+
const create = jest.fn(() => locale);
|
|
106
|
+
const query = jest.fn(() => ({ create }));
|
|
107
|
+
global.strapi = {
|
|
108
|
+
query,
|
|
109
|
+
plugins: {
|
|
110
|
+
i18n: {
|
|
111
|
+
services: { metrics: fakeMetricsService },
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const createdLocale = await localesService.create(locale);
|
|
117
|
+
expect(query).toHaveBeenCalledWith('locale', 'i18n');
|
|
118
|
+
expect(create).toHaveBeenCalledWith(locale);
|
|
119
|
+
expect(createdLocale).toMatchObject(locale);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test('update', async () => {
|
|
123
|
+
const locale = { name: 'French', code: 'fr' };
|
|
124
|
+
const update = jest.fn(() => locale);
|
|
125
|
+
const query = jest.fn(() => ({ update }));
|
|
126
|
+
global.strapi = {
|
|
127
|
+
query,
|
|
128
|
+
plugins: {
|
|
129
|
+
i18n: {
|
|
130
|
+
services: { metrics: fakeMetricsService },
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const updatedLocale = await localesService.update({ code: 'fr' }, { name: 'French' });
|
|
136
|
+
expect(query).toHaveBeenCalledWith('locale', 'i18n');
|
|
137
|
+
expect(update).toHaveBeenCalledWith({ code: 'fr' }, { name: 'French' });
|
|
138
|
+
expect(updatedLocale).toMatchObject(locale);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test('delete', async () => {
|
|
142
|
+
const locale = { name: 'French', code: 'fr' };
|
|
143
|
+
const deleteFn = jest.fn(() => locale);
|
|
144
|
+
const findOne = jest.fn(() => locale);
|
|
145
|
+
const isLocalizedContentType = jest.fn(() => true);
|
|
146
|
+
const query = jest.fn(() => ({ delete: deleteFn, findOne }));
|
|
147
|
+
global.strapi = {
|
|
148
|
+
query,
|
|
149
|
+
plugins: {
|
|
150
|
+
i18n: {
|
|
151
|
+
services: { metrics: fakeMetricsService, 'content-types': { isLocalizedContentType } },
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
contentTypes: { 'application::country.country': {} },
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const deletedLocale = await localesService.delete({ id: 1 });
|
|
158
|
+
expect(query).toHaveBeenCalledWith('locale', 'i18n');
|
|
159
|
+
expect(deleteFn).toHaveBeenCalledWith({ id: 1 });
|
|
160
|
+
expect(deletedLocale).toMatchObject(locale);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
test('delete - not found', async () => {
|
|
164
|
+
const locale = { name: 'French', code: 'fr' };
|
|
165
|
+
const deleteFn = jest.fn(() => locale);
|
|
166
|
+
const findOne = jest.fn(() => undefined);
|
|
167
|
+
const query = jest.fn(() => ({ delete: deleteFn, findOne }));
|
|
168
|
+
global.strapi = {
|
|
169
|
+
query,
|
|
170
|
+
plugins: {
|
|
171
|
+
i18n: {
|
|
172
|
+
services: { metrics: fakeMetricsService },
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
const deletedLocale = await localesService.delete({ id: 1 });
|
|
178
|
+
expect(query).toHaveBeenCalledWith('locale', 'i18n');
|
|
179
|
+
expect(deleteFn).not.toHaveBeenCalled();
|
|
180
|
+
expect(deletedLocale).toBeUndefined();
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
describe('initDefaultLocale', () => {
|
|
185
|
+
test('create default local if none exists', async () => {
|
|
186
|
+
const count = jest.fn(() => Promise.resolve(0));
|
|
187
|
+
const create = jest.fn(() => Promise.resolve());
|
|
188
|
+
const set = jest.fn(() => Promise.resolve());
|
|
189
|
+
|
|
190
|
+
global.strapi = {
|
|
191
|
+
query: () => ({
|
|
192
|
+
count,
|
|
193
|
+
create,
|
|
194
|
+
}),
|
|
195
|
+
store: () => ({
|
|
196
|
+
set,
|
|
197
|
+
}),
|
|
198
|
+
plugins: {
|
|
199
|
+
i18n: {
|
|
200
|
+
services: {
|
|
201
|
+
metrics: fakeMetricsService,
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
await localesService.initDefaultLocale();
|
|
208
|
+
expect(count).toHaveBeenCalledWith();
|
|
209
|
+
expect(create).toHaveBeenCalledWith({
|
|
210
|
+
name: 'English (en)',
|
|
211
|
+
code: 'en',
|
|
212
|
+
});
|
|
213
|
+
expect(set).toHaveBeenCalledWith({ key: 'default_locale', value: 'en' });
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
test('does not create default local if one already exists', async () => {
|
|
217
|
+
const count = jest.fn(() => Promise.resolve(1));
|
|
218
|
+
const create = jest.fn(() => Promise.resolve());
|
|
219
|
+
const set = jest.fn(() => Promise.resolve());
|
|
220
|
+
|
|
221
|
+
global.strapi = {
|
|
222
|
+
query: () => ({
|
|
223
|
+
count,
|
|
224
|
+
create,
|
|
225
|
+
}),
|
|
226
|
+
store: () => ({
|
|
227
|
+
set,
|
|
228
|
+
}),
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
await localesService.initDefaultLocale();
|
|
232
|
+
expect(count).toHaveBeenCalledWith();
|
|
233
|
+
expect(create).not.toHaveBeenCalled();
|
|
234
|
+
expect(set).not.toHaveBeenCalled();
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
});
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
assignDefaultLocale,
|
|
5
|
+
syncLocalizations,
|
|
6
|
+
syncNonLocalizedAttributes,
|
|
7
|
+
} = require('../localizations');
|
|
8
|
+
|
|
9
|
+
const locales = require('../locales');
|
|
10
|
+
const contentTypes = require('../content-types');
|
|
11
|
+
|
|
12
|
+
const model = {
|
|
13
|
+
uid: 'test-model',
|
|
14
|
+
pluginOptions: {
|
|
15
|
+
i18n: {
|
|
16
|
+
localized: true,
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
attributes: {
|
|
20
|
+
title: {
|
|
21
|
+
type: 'string',
|
|
22
|
+
pluginOptions: {
|
|
23
|
+
i18n: {
|
|
24
|
+
localized: true,
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
stars: {
|
|
29
|
+
type: 'integer',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const allLocalizedModel = {
|
|
35
|
+
uid: 'test-model',
|
|
36
|
+
pluginOptions: {
|
|
37
|
+
i18n: {
|
|
38
|
+
localized: true,
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
attributes: {
|
|
42
|
+
title: {
|
|
43
|
+
type: 'string',
|
|
44
|
+
pluginOptions: {
|
|
45
|
+
i18n: {
|
|
46
|
+
localized: true,
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
stars: {
|
|
51
|
+
type: 'integer',
|
|
52
|
+
pluginOptions: {
|
|
53
|
+
i18n: {
|
|
54
|
+
localized: true,
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const setGlobalStrapi = () => {
|
|
62
|
+
global.strapi = {
|
|
63
|
+
plugins: {
|
|
64
|
+
i18n: {
|
|
65
|
+
services: {
|
|
66
|
+
locales,
|
|
67
|
+
'content-types': contentTypes,
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
describe('localizations service', () => {
|
|
75
|
+
describe('assignDefaultLocale', () => {
|
|
76
|
+
test('Does not change the input if locale is already defined', async () => {
|
|
77
|
+
setGlobalStrapi();
|
|
78
|
+
const input = { locale: 'myLocale' };
|
|
79
|
+
await assignDefaultLocale(input);
|
|
80
|
+
|
|
81
|
+
expect(input).toStrictEqual({ locale: 'myLocale' });
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test('Use default locale to set the locale on the input data', async () => {
|
|
85
|
+
setGlobalStrapi();
|
|
86
|
+
|
|
87
|
+
const getDefaultLocaleMock = jest.fn(() => 'defaultLocale');
|
|
88
|
+
|
|
89
|
+
global.strapi.plugins.i18n.services.locales.getDefaultLocale = getDefaultLocaleMock;
|
|
90
|
+
|
|
91
|
+
const input = {};
|
|
92
|
+
await assignDefaultLocale(input);
|
|
93
|
+
|
|
94
|
+
expect(input).toStrictEqual({ locale: 'defaultLocale' });
|
|
95
|
+
expect(getDefaultLocaleMock).toHaveBeenCalled();
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
describe('syncLocalizations', () => {
|
|
100
|
+
test('Updates every other localizations with correct ids', async () => {
|
|
101
|
+
setGlobalStrapi();
|
|
102
|
+
|
|
103
|
+
const update = jest.fn();
|
|
104
|
+
global.strapi.query = () => {
|
|
105
|
+
return { update };
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const localizations = [{ id: 2 }, { id: 3 }];
|
|
109
|
+
const entry = { id: 1, locale: 'test', localizations };
|
|
110
|
+
|
|
111
|
+
await syncLocalizations(entry, { model });
|
|
112
|
+
|
|
113
|
+
expect(update).toHaveBeenCalledTimes(localizations.length);
|
|
114
|
+
expect(update).toHaveBeenNthCalledWith(1, { id: 2 }, { localizations: [1, 3] });
|
|
115
|
+
expect(update).toHaveBeenNthCalledWith(2, { id: 3 }, { localizations: [1, 2] });
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe('syncNonLocalizedAttributes', () => {
|
|
120
|
+
test('Does nothing if no localizations set', async () => {
|
|
121
|
+
setGlobalStrapi();
|
|
122
|
+
|
|
123
|
+
const update = jest.fn();
|
|
124
|
+
global.strapi.query = () => {
|
|
125
|
+
return { update };
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const entry = { id: 1, locale: 'test' };
|
|
129
|
+
|
|
130
|
+
await syncNonLocalizedAttributes(entry, { model });
|
|
131
|
+
|
|
132
|
+
expect(update).not.toHaveBeenCalled();
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test('Does not update the current locale', async () => {
|
|
136
|
+
setGlobalStrapi();
|
|
137
|
+
|
|
138
|
+
const update = jest.fn();
|
|
139
|
+
global.strapi.query = () => {
|
|
140
|
+
return { update };
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const entry = { id: 1, locale: 'test', localizations: [] };
|
|
144
|
+
|
|
145
|
+
await syncNonLocalizedAttributes(entry, { model });
|
|
146
|
+
|
|
147
|
+
expect(update).not.toHaveBeenCalled();
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test('Does not update if all the fields are localized', async () => {
|
|
151
|
+
setGlobalStrapi();
|
|
152
|
+
|
|
153
|
+
const update = jest.fn();
|
|
154
|
+
global.strapi.query = () => {
|
|
155
|
+
return { update };
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const entry = { id: 1, locale: 'test', localizations: [] };
|
|
159
|
+
|
|
160
|
+
await syncNonLocalizedAttributes(entry, { model: allLocalizedModel });
|
|
161
|
+
|
|
162
|
+
expect(update).not.toHaveBeenCalled();
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
test('Updates locales with non localized fields only', async () => {
|
|
166
|
+
setGlobalStrapi();
|
|
167
|
+
|
|
168
|
+
const update = jest.fn();
|
|
169
|
+
global.strapi.query = () => {
|
|
170
|
+
return { update };
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
const entry = {
|
|
174
|
+
id: 1,
|
|
175
|
+
locale: 'test',
|
|
176
|
+
title: 'Localized',
|
|
177
|
+
stars: 1,
|
|
178
|
+
localizations: [{ id: 2, locale: 'fr' }],
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
await syncNonLocalizedAttributes(entry, { model });
|
|
182
|
+
|
|
183
|
+
expect(update).toHaveBeenCalledTimes(1);
|
|
184
|
+
expect(update).toHaveBeenCalledWith({ id: 2 }, { stars: 1 });
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
});
|