@strapi/i18n 0.0.0-experimental.f31889311d753b5f7d95198ae84d8fce1d156cd6 → 0.0.0-experimental.f49f46a1c17445a39e8af3f63124bcccf73842e6

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 (51) hide show
  1. package/dist/_chunks/{SettingsPage-DA9haizZ.js → SettingsPage-D0hqaut-.js} +8 -8
  2. package/dist/_chunks/SettingsPage-D0hqaut-.js.map +1 -0
  3. package/dist/_chunks/{SettingsPage-CsGvujny.mjs → SettingsPage-D67CaQAB.mjs} +8 -8
  4. package/dist/_chunks/SettingsPage-D67CaQAB.mjs.map +1 -0
  5. package/dist/_chunks/{en-BsOU9o5z.js → en-BKBz3tro.js} +10 -3
  6. package/dist/_chunks/en-BKBz3tro.js.map +1 -0
  7. package/dist/_chunks/{en-CM6Pjfyv.mjs → en-DlXfy6Gy.mjs} +10 -3
  8. package/dist/_chunks/en-DlXfy6Gy.mjs.map +1 -0
  9. package/dist/_chunks/{index-DIzVXZoE.js → index-46DNtLCn.js} +387 -141
  10. package/dist/_chunks/index-46DNtLCn.js.map +1 -0
  11. package/dist/_chunks/{index-CCZJF_EJ.mjs → index-CNR8i3KM.mjs} +394 -148
  12. package/dist/_chunks/index-CNR8i3KM.mjs.map +1 -0
  13. package/dist/admin/index.js +1 -1
  14. package/dist/admin/index.mjs +1 -1
  15. package/dist/admin/src/components/BulkLocaleActionModal.d.ts +2 -1
  16. package/dist/admin/src/components/CMHeaderActions.d.ts +29 -3
  17. package/dist/admin/src/components/CreateLocale.d.ts +6 -6
  18. package/dist/admin/src/utils/clean.d.ts +4 -0
  19. package/dist/server/index.js +413 -480
  20. package/dist/server/index.js.map +1 -1
  21. package/dist/server/index.mjs +415 -482
  22. package/dist/server/index.mjs.map +1 -1
  23. package/dist/server/src/bootstrap.d.ts +1 -4
  24. package/dist/server/src/bootstrap.d.ts.map +1 -1
  25. package/dist/server/src/index.d.ts +21 -13
  26. package/dist/server/src/index.d.ts.map +1 -1
  27. package/dist/server/src/register.d.ts.map +1 -1
  28. package/dist/server/src/services/index.d.ts +20 -10
  29. package/dist/server/src/services/index.d.ts.map +1 -1
  30. package/dist/server/src/services/permissions/actions.d.ts +14 -2
  31. package/dist/server/src/services/permissions/actions.d.ts.map +1 -1
  32. package/dist/server/src/services/permissions.d.ts +14 -2
  33. package/dist/server/src/services/permissions.d.ts.map +1 -1
  34. package/dist/server/src/services/sanitize/index.d.ts +11 -0
  35. package/dist/server/src/services/sanitize/index.d.ts.map +1 -0
  36. package/dist/server/src/utils/index.d.ts +2 -2
  37. package/dist/server/src/utils/index.d.ts.map +1 -1
  38. package/package.json +12 -12
  39. package/dist/_chunks/SettingsPage-CsGvujny.mjs.map +0 -1
  40. package/dist/_chunks/SettingsPage-DA9haizZ.js.map +0 -1
  41. package/dist/_chunks/en-BsOU9o5z.js.map +0 -1
  42. package/dist/_chunks/en-CM6Pjfyv.mjs.map +0 -1
  43. package/dist/_chunks/index-CCZJF_EJ.mjs.map +0 -1
  44. package/dist/_chunks/index-DIzVXZoE.js.map +0 -1
  45. package/dist/server/src/migrations/content-type/disable/index.d.ts +0 -3
  46. package/dist/server/src/migrations/content-type/disable/index.d.ts.map +0 -1
  47. package/dist/server/src/migrations/content-type/enable/index.d.ts +0 -3
  48. package/dist/server/src/migrations/content-type/enable/index.d.ts.map +0 -1
  49. package/dist/server/src/services/entity-service-decorator.d.ts +0 -29
  50. package/dist/server/src/services/entity-service-decorator.d.ts.map +0 -1
  51. package/strapi-server.js +0 -3
@@ -1,7 +1,7 @@
1
1
  import _ from "lodash";
2
- import { get, identity, propEq, capitalize, isArray, prop, getOr, isEmpty, reduce, cloneDeep, isNil, has, omit, pipe, pick, map, flatten, uniq } from "lodash/fp";
2
+ import { get, identity, propEq, isArray, prop, getOr, isEmpty, reduce, cloneDeep, isNil, pipe, pick, has, curry, map, flatten, uniq } from "lodash/fp";
3
3
  import * as utils from "@strapi/utils";
4
- import { errors, async, contentTypes as contentTypes$2, yup, validateYupSchema } from "@strapi/utils";
4
+ import { errors, async, contentTypes as contentTypes$2, traverseEntity, yup, validateYupSchema } from "@strapi/utils";
5
5
  const getCoreStore = () => {
6
6
  return strapi.store({ type: "plugin", name: "i18n" });
7
7
  };
@@ -30,7 +30,7 @@ const registerModelsHooks = () => {
30
30
  const attributesToPopulate = getNestedPopulateOfNonLocalizedAttributes2(schema2.uid);
31
31
  const result = await next();
32
32
  let resultID;
33
- if (Array.isArray(result?.entries)) {
33
+ if (Array.isArray(result?.entries) && result.entries[0]?.id) {
34
34
  resultID = result.entries[0].id;
35
35
  } else if (result?.id) {
36
36
  resultID = result.id;
@@ -44,12 +44,10 @@ const registerModelsHooks = () => {
44
44
  return result;
45
45
  });
46
46
  };
47
- const bootstrap = async ({ strapi: strapi2 }) => {
47
+ const bootstrap = async () => {
48
48
  const { sendDidInitializeEvent: sendDidInitializeEvent2 } = getService("metrics");
49
- const { decorator: decorator2 } = getService("entity-service-decorator");
50
49
  const { initDefaultLocale: initDefaultLocale2 } = getService("locales");
51
50
  const { sectionsBuilder, actions: actions2, engine } = getService("permissions");
52
- strapi2.entityService.decorate(decorator2);
53
51
  await initDefaultLocale2();
54
52
  sectionsBuilder.registerLocalesPropertyHandler();
55
53
  await actions2.registerI18nActions();
@@ -176,6 +174,352 @@ const getI18nLocaleArgPlugin = ({ nexus, typeRegistry }) => {
176
174
  }
177
175
  });
178
176
  };
177
+ const register = ({ strapi: strapi2 }) => {
178
+ extendContentTypes(strapi2);
179
+ addContentManagerLocaleMiddleware(strapi2);
180
+ };
181
+ const addContentManagerLocaleMiddleware = (strapi2) => {
182
+ strapi2.server.router.use("/content-manager/collection-types/:model", (ctx, next) => {
183
+ if (ctx.method === "POST" || ctx.method === "PUT") {
184
+ return validateLocaleCreation(ctx, next);
185
+ }
186
+ return next();
187
+ });
188
+ strapi2.server.router.use("/content-manager/single-types/:model", (ctx, next) => {
189
+ if (ctx.method === "POST" || ctx.method === "PUT") {
190
+ return validateLocaleCreation(ctx, next);
191
+ }
192
+ return next();
193
+ });
194
+ };
195
+ const extendContentTypes = (strapi2) => {
196
+ const { isLocalizedContentType: isLocalizedContentType2 } = getService("content-types");
197
+ Object.values(strapi2.contentTypes).forEach((contentType) => {
198
+ const { attributes: attributes2 } = contentType;
199
+ const isLocalized = isLocalizedContentType2(contentType);
200
+ _.set(attributes2, "locale", {
201
+ writable: true,
202
+ private: !isLocalized,
203
+ configurable: false,
204
+ visible: false,
205
+ type: "string"
206
+ });
207
+ _.set(attributes2, "localizations", {
208
+ type: "relation",
209
+ relation: "oneToMany",
210
+ target: contentType.uid,
211
+ writable: false,
212
+ private: !isLocalized,
213
+ configurable: false,
214
+ visible: false,
215
+ unstable_virtual: true,
216
+ joinColumn: {
217
+ name: "document_id",
218
+ referencedColumn: "document_id",
219
+ referencedTable: strapi2.db.metadata.identifiers.getTableName(contentType.collectionName),
220
+ // ensure the population will not include the results we already loaded
221
+ on({ results }) {
222
+ return {
223
+ id: {
224
+ $notIn: results.map((r) => r.id)
225
+ }
226
+ };
227
+ }
228
+ }
229
+ });
230
+ });
231
+ if (strapi2.plugin("graphql")) {
232
+ graphqlProvider({ strapi: strapi2 }).register();
233
+ }
234
+ };
235
+ const info = {
236
+ singularName: "locale",
237
+ pluralName: "locales",
238
+ collectionName: "locales",
239
+ displayName: "Locale",
240
+ description: ""
241
+ };
242
+ const options = {};
243
+ const pluginOptions = {
244
+ "content-manager": {
245
+ visible: false
246
+ },
247
+ "content-type-builder": {
248
+ visible: false
249
+ }
250
+ };
251
+ const attributes = {
252
+ name: {
253
+ type: "string",
254
+ min: 1,
255
+ max: 50,
256
+ configurable: false
257
+ },
258
+ code: {
259
+ type: "string",
260
+ unique: true,
261
+ configurable: false
262
+ }
263
+ };
264
+ const schema = {
265
+ info,
266
+ options,
267
+ pluginOptions,
268
+ attributes
269
+ };
270
+ const locale = {
271
+ schema
272
+ };
273
+ const contentTypes$1 = {
274
+ locale
275
+ };
276
+ const actions = [
277
+ {
278
+ section: "settings",
279
+ category: "Internationalization",
280
+ subCategory: "Locales",
281
+ pluginName: "i18n",
282
+ displayName: "Create",
283
+ uid: "locale.create"
284
+ },
285
+ {
286
+ section: "settings",
287
+ category: "Internationalization",
288
+ subCategory: "Locales",
289
+ pluginName: "i18n",
290
+ displayName: "Read",
291
+ uid: "locale.read",
292
+ aliases: [
293
+ { actionId: "plugin::content-manager.explorer.read", subjects: ["plugin::i18n.locale"] }
294
+ ]
295
+ },
296
+ {
297
+ section: "settings",
298
+ category: "Internationalization",
299
+ subCategory: "Locales",
300
+ pluginName: "i18n",
301
+ displayName: "Update",
302
+ uid: "locale.update"
303
+ },
304
+ {
305
+ section: "settings",
306
+ category: "Internationalization",
307
+ subCategory: "Locales",
308
+ pluginName: "i18n",
309
+ displayName: "Delete",
310
+ uid: "locale.delete"
311
+ }
312
+ ];
313
+ const addLocalesPropertyIfNeeded = ({ value: action }) => {
314
+ const {
315
+ section,
316
+ options: { applyToProperties }
317
+ } = action;
318
+ if (section !== "contentTypes") {
319
+ return;
320
+ }
321
+ if (isArray(applyToProperties) && applyToProperties.includes("locales")) {
322
+ return;
323
+ }
324
+ action.options.applyToProperties = isArray(applyToProperties) ? applyToProperties.concat("locales") : ["locales"];
325
+ };
326
+ const shouldApplyLocalesPropertyToSubject = ({ property, subject }) => {
327
+ if (property === "locales") {
328
+ const model = strapi.getModel(subject);
329
+ return getService("content-types").isLocalizedContentType(model);
330
+ }
331
+ return true;
332
+ };
333
+ const addAllLocalesToPermissions = async (permissions2) => {
334
+ const { actionProvider } = strapi.service("admin::permission");
335
+ const { find: findAllLocales } = getService("locales");
336
+ const allLocales = await findAllLocales();
337
+ const allLocalesCode = allLocales.map(prop("code"));
338
+ return Promise.all(
339
+ permissions2.map(async (permission) => {
340
+ const { action, subject } = permission;
341
+ const appliesToLocalesProperty = await actionProvider.appliesToProperty(
342
+ "locales",
343
+ action,
344
+ subject
345
+ );
346
+ if (!appliesToLocalesProperty) {
347
+ return permission;
348
+ }
349
+ const oldPermissionProperties = getOr({}, "properties", permission);
350
+ return { ...permission, properties: { ...oldPermissionProperties, locales: allLocalesCode } };
351
+ })
352
+ );
353
+ };
354
+ const syncSuperAdminPermissionsWithLocales = async () => {
355
+ const roleService = strapi.service("admin::role");
356
+ const permissionService = strapi.service("admin::permission");
357
+ const superAdminRole = await roleService.getSuperAdmin();
358
+ if (!superAdminRole) {
359
+ return;
360
+ }
361
+ const superAdminPermissions = await permissionService.findMany({
362
+ where: {
363
+ role: {
364
+ id: superAdminRole.id
365
+ }
366
+ }
367
+ });
368
+ const newSuperAdminPermissions = await addAllLocalesToPermissions(superAdminPermissions);
369
+ await roleService.assignPermissions(superAdminRole.id, newSuperAdminPermissions);
370
+ };
371
+ const registerI18nActions = async () => {
372
+ const { actionProvider } = strapi.service("admin::permission");
373
+ await actionProvider.registerMany(actions);
374
+ };
375
+ const registerI18nActionsHooks = () => {
376
+ const { actionProvider } = strapi.service("admin::permission");
377
+ const { hooks } = strapi.service("admin::role");
378
+ actionProvider.hooks.appliesPropertyToSubject.register(shouldApplyLocalesPropertyToSubject);
379
+ hooks.willResetSuperAdminPermissions.register(addAllLocalesToPermissions);
380
+ };
381
+ const updateActionsProperties = () => {
382
+ const { actionProvider } = strapi.service("admin::permission");
383
+ actionProvider.hooks.willRegister.register(addLocalesPropertyIfNeeded);
384
+ actionProvider.values().forEach((action) => addLocalesPropertyIfNeeded({ value: action }));
385
+ };
386
+ const i18nActionsService = {
387
+ actions,
388
+ registerI18nActions,
389
+ registerI18nActionsHooks,
390
+ updateActionsProperties,
391
+ syncSuperAdminPermissionsWithLocales
392
+ };
393
+ const localesPropertyHandler = async ({ action, section }) => {
394
+ const { actionProvider } = strapi.service("admin::permission");
395
+ const locales2 = await getService("locales").find();
396
+ if (isEmpty(locales2)) {
397
+ return;
398
+ }
399
+ for (const subject of section.subjects) {
400
+ const applies = await actionProvider.appliesToProperty("locales", action.actionId, subject.uid);
401
+ const hasLocalesProperty = subject.properties.find(
402
+ (property) => property.value === "locales"
403
+ );
404
+ if (applies && !hasLocalesProperty) {
405
+ subject.properties.push({
406
+ label: "Locales",
407
+ value: "locales",
408
+ children: locales2.map(({ name, code }) => ({ label: name || code, value: code }))
409
+ });
410
+ }
411
+ }
412
+ };
413
+ const registerLocalesPropertyHandler = () => {
414
+ const { sectionsBuilder } = strapi.service("admin::permission");
415
+ sectionsBuilder.addHandler("singleTypes", localesPropertyHandler);
416
+ sectionsBuilder.addHandler("collectionTypes", localesPropertyHandler);
417
+ };
418
+ const sectionsBuilderService = {
419
+ localesPropertyHandler,
420
+ registerLocalesPropertyHandler
421
+ };
422
+ const willRegisterPermission = (context) => {
423
+ const { permission, condition, user } = context;
424
+ const { subject, properties } = permission;
425
+ const isSuperAdmin = strapi.service("admin::role").hasSuperAdminRole(user);
426
+ if (isSuperAdmin) {
427
+ return;
428
+ }
429
+ const { locales: locales2 } = properties || {};
430
+ const { isLocalizedContentType: isLocalizedContentType2 } = getService("content-types");
431
+ if (!subject) {
432
+ return;
433
+ }
434
+ const ct = strapi.contentTypes[subject];
435
+ if (!isLocalizedContentType2(ct)) {
436
+ return;
437
+ }
438
+ if (locales2 === null) {
439
+ return;
440
+ }
441
+ condition.and({
442
+ locale: {
443
+ $in: locales2 || []
444
+ }
445
+ });
446
+ };
447
+ const registerI18nPermissionsHandlers = () => {
448
+ const { engine } = strapi.service("admin::permission");
449
+ engine.hooks["before-register.permission"].register(willRegisterPermission);
450
+ };
451
+ const engineService = {
452
+ willRegisterPermission,
453
+ registerI18nPermissionsHandlers
454
+ };
455
+ const permissions = () => ({
456
+ actions: i18nActionsService,
457
+ sectionsBuilder: sectionsBuilderService,
458
+ engine: engineService
459
+ });
460
+ const sendDidInitializeEvent = async () => {
461
+ const { isLocalizedContentType: isLocalizedContentType2 } = getService("content-types");
462
+ const numberOfContentTypes = reduce(
463
+ (sum, contentType) => isLocalizedContentType2(contentType) ? sum + 1 : sum,
464
+ 0
465
+ )(strapi.contentTypes);
466
+ await strapi.telemetry.send("didInitializeI18n", { groupProperties: { numberOfContentTypes } });
467
+ };
468
+ const sendDidUpdateI18nLocalesEvent = async () => {
469
+ const numberOfLocales = await getService("locales").count();
470
+ await strapi.telemetry.send("didUpdateI18nLocales", {
471
+ groupProperties: { numberOfLocales }
472
+ });
473
+ };
474
+ const metrics = () => ({
475
+ sendDidInitializeEvent,
476
+ sendDidUpdateI18nLocalesEvent
477
+ });
478
+ const syncNonLocalizedAttributes = async (sourceEntry, model) => {
479
+ const { copyNonLocalizedAttributes: copyNonLocalizedAttributes2 } = getService("content-types");
480
+ const nonLocalizedAttributes = copyNonLocalizedAttributes2(model, sourceEntry);
481
+ if (isEmpty(nonLocalizedAttributes)) {
482
+ return;
483
+ }
484
+ const uid = model.uid;
485
+ const documentId = sourceEntry.documentId;
486
+ const locale2 = sourceEntry.locale;
487
+ const status = sourceEntry?.publishedAt ? "published" : "draft";
488
+ const localeEntriesToUpdate = await strapi.db.query(uid).findMany({
489
+ where: {
490
+ documentId,
491
+ publishedAt: status === "published" ? { $ne: null } : null,
492
+ locale: { $ne: locale2 }
493
+ },
494
+ select: ["locale", "id"]
495
+ });
496
+ const entryData = await strapi.documents(uid).omitComponentData(nonLocalizedAttributes);
497
+ await async.map(localeEntriesToUpdate, async (entry) => {
498
+ const transformedData = await strapi.documents.utils.transformData(
499
+ cloneDeep(nonLocalizedAttributes),
500
+ {
501
+ uid,
502
+ status,
503
+ locale: entry.locale,
504
+ allowMissingId: true
505
+ }
506
+ );
507
+ const componentData = await strapi.documents(uid).updateComponents(entry, transformedData);
508
+ await strapi.db.query(uid).update({
509
+ where: {
510
+ documentId,
511
+ publishedAt: status === "published" ? { $ne: null } : null,
512
+ locale: { $eq: entry.locale }
513
+ },
514
+ // The data we send to the update function is the entry data merged with
515
+ // the updated component data
516
+ data: Object.assign(cloneDeep(entryData), componentData)
517
+ });
518
+ });
519
+ };
520
+ const localizations = () => ({
521
+ syncNonLocalizedAttributes
522
+ });
179
523
  const isoLocales = [
180
524
  {
181
525
  code: "af",
@@ -2554,401 +2898,55 @@ const isoLocales = [
2554
2898
  name: "Welsh (United Kingdom) (cy-GB)"
2555
2899
  },
2556
2900
  {
2557
- code: "yav",
2558
- name: "Yangben (yav)"
2559
- },
2560
- {
2561
- code: "yav-CM",
2562
- name: "Yangben (Cameroon) (yav-CM)"
2563
- },
2564
- {
2565
- code: "yo",
2566
- name: "Yoruba (yo)"
2567
- },
2568
- {
2569
- code: "yo-NG",
2570
- name: "Yoruba (Nigeria) (yo-NG)"
2571
- },
2572
- {
2573
- code: "dje",
2574
- name: "Zarma (dje)"
2575
- },
2576
- {
2577
- code: "dje-NE",
2578
- name: "Zarma (Niger) (dje-NE)"
2579
- },
2580
- {
2581
- code: "zu",
2582
- name: "Zulu (zu)"
2583
- },
2584
- {
2585
- code: "zu-ZA",
2586
- name: "Zulu (South Africa) (zu-ZA)"
2587
- }
2588
- ];
2589
- const getInitLocale = () => {
2590
- const envLocaleCode = process.env.STRAPI_PLUGIN_I18N_INIT_LOCALE_CODE;
2591
- if (envLocaleCode) {
2592
- const matchingLocale = isoLocales.find(({ code }) => code === envLocaleCode);
2593
- if (!matchingLocale) {
2594
- throw new Error(
2595
- "Unknown locale code provided in the environment variable STRAPI_PLUGIN_I18N_INIT_LOCALE_CODE"
2596
- );
2597
- }
2598
- return { ...matchingLocale };
2599
- }
2600
- return {
2601
- code: "en",
2602
- name: "English (en)"
2603
- };
2604
- };
2605
- const DEFAULT_LOCALE = getInitLocale();
2606
- const enableContentType = async ({ oldContentTypes, contentTypes: contentTypes2 }) => {
2607
- const { isLocalizedContentType: isLocalizedContentType2 } = getService("content-types");
2608
- const { getDefaultLocale: getDefaultLocale2 } = getService("locales");
2609
- if (!oldContentTypes) {
2610
- return;
2611
- }
2612
- for (const uid in contentTypes2) {
2613
- if (!oldContentTypes[uid]) {
2614
- continue;
2615
- }
2616
- const oldContentType = oldContentTypes[uid];
2617
- const contentType = contentTypes2[uid];
2618
- if (!isLocalizedContentType2(oldContentType) && isLocalizedContentType2(contentType)) {
2619
- const defaultLocale = await getDefaultLocale2() || DEFAULT_LOCALE.code;
2620
- await strapi.db.query(uid).updateMany({
2621
- where: { locale: null },
2622
- data: { locale: defaultLocale }
2623
- });
2624
- }
2625
- }
2626
- };
2627
- const disableContentType = async ({ oldContentTypes, contentTypes: contentTypes2 }) => {
2628
- const { isLocalizedContentType: isLocalizedContentType2 } = getService("content-types");
2629
- const { getDefaultLocale: getDefaultLocale2 } = getService("locales");
2630
- if (!oldContentTypes) {
2631
- return;
2632
- }
2633
- for (const uid in contentTypes2) {
2634
- if (!oldContentTypes[uid]) {
2635
- continue;
2636
- }
2637
- const oldContentType = oldContentTypes[uid];
2638
- const contentType = contentTypes2[uid];
2639
- if (isLocalizedContentType2(oldContentType) && !isLocalizedContentType2(contentType)) {
2640
- const defaultLocale = await getDefaultLocale2() || DEFAULT_LOCALE.code;
2641
- await Promise.all([
2642
- // Delete all entities that are not in the default locale
2643
- strapi.db.query(uid).deleteMany({
2644
- where: { locale: { $ne: defaultLocale } }
2645
- }),
2646
- // Set locale to null for the rest
2647
- strapi.db.query(uid).updateMany({
2648
- where: { locale: { $eq: defaultLocale } },
2649
- data: { locale: null }
2650
- })
2651
- ]);
2652
- }
2653
- }
2654
- };
2655
- const register = ({ strapi: strapi2 }) => {
2656
- extendContentTypes(strapi2);
2657
- addContentManagerLocaleMiddleware(strapi2);
2658
- addContentTypeSyncHooks(strapi2);
2659
- };
2660
- const addContentManagerLocaleMiddleware = (strapi2) => {
2661
- strapi2.server.router.use("/content-manager/collection-types/:model", (ctx, next) => {
2662
- if (ctx.method === "POST" || ctx.method === "PUT") {
2663
- return validateLocaleCreation(ctx, next);
2664
- }
2665
- return next();
2666
- });
2667
- strapi2.server.router.use("/content-manager/single-types/:model", (ctx, next) => {
2668
- if (ctx.method === "POST" || ctx.method === "PUT") {
2669
- return validateLocaleCreation(ctx, next);
2670
- }
2671
- return next();
2672
- });
2673
- };
2674
- const addContentTypeSyncHooks = (strapi2) => {
2675
- strapi2.hook("strapi::content-types.beforeSync").register(disableContentType);
2676
- strapi2.hook("strapi::content-types.afterSync").register(enableContentType);
2677
- };
2678
- const extendContentTypes = (strapi2) => {
2679
- Object.values(strapi2.contentTypes).forEach((contentType) => {
2680
- const { attributes: attributes2 } = contentType;
2681
- _.set(attributes2, "locale", {
2682
- writable: true,
2683
- private: false,
2684
- configurable: false,
2685
- visible: false,
2686
- type: "string"
2687
- });
2688
- });
2689
- if (strapi2.plugin("graphql")) {
2690
- graphqlProvider({ strapi: strapi2 }).register();
2691
- }
2692
- };
2693
- const info = {
2694
- singularName: "locale",
2695
- pluralName: "locales",
2696
- collectionName: "locales",
2697
- displayName: "Locale",
2698
- description: ""
2699
- };
2700
- const options = {};
2701
- const pluginOptions = {
2702
- "content-manager": {
2703
- visible: false
2704
- },
2705
- "content-type-builder": {
2706
- visible: false
2707
- }
2708
- };
2709
- const attributes = {
2710
- name: {
2711
- type: "string",
2712
- min: 1,
2713
- max: 50,
2714
- configurable: false
2715
- },
2716
- code: {
2717
- type: "string",
2718
- unique: true,
2719
- configurable: false
2720
- }
2721
- };
2722
- const schema = {
2723
- info,
2724
- options,
2725
- pluginOptions,
2726
- attributes
2727
- };
2728
- const locale = {
2729
- schema
2730
- };
2731
- const contentTypes$1 = {
2732
- locale
2733
- };
2734
- const actions = ["create", "read", "update", "delete"].map((uid) => ({
2735
- section: "settings",
2736
- category: "Internationalization",
2737
- subCategory: "Locales",
2738
- pluginName: "i18n",
2739
- displayName: capitalize(uid),
2740
- uid: `locale.${uid}`
2741
- }));
2742
- const addLocalesPropertyIfNeeded = ({ value: action }) => {
2743
- const {
2744
- section,
2745
- options: { applyToProperties }
2746
- } = action;
2747
- if (section !== "contentTypes") {
2748
- return;
2749
- }
2750
- if (isArray(applyToProperties) && applyToProperties.includes("locales")) {
2751
- return;
2752
- }
2753
- action.options.applyToProperties = isArray(applyToProperties) ? applyToProperties.concat("locales") : ["locales"];
2754
- };
2755
- const shouldApplyLocalesPropertyToSubject = ({ property, subject }) => {
2756
- if (property === "locales") {
2757
- const model = strapi.getModel(subject);
2758
- return getService("content-types").isLocalizedContentType(model);
2901
+ code: "yav",
2902
+ name: "Yangben (yav)"
2903
+ },
2904
+ {
2905
+ code: "yav-CM",
2906
+ name: "Yangben (Cameroon) (yav-CM)"
2907
+ },
2908
+ {
2909
+ code: "yo",
2910
+ name: "Yoruba (yo)"
2911
+ },
2912
+ {
2913
+ code: "yo-NG",
2914
+ name: "Yoruba (Nigeria) (yo-NG)"
2915
+ },
2916
+ {
2917
+ code: "dje",
2918
+ name: "Zarma (dje)"
2919
+ },
2920
+ {
2921
+ code: "dje-NE",
2922
+ name: "Zarma (Niger) (dje-NE)"
2923
+ },
2924
+ {
2925
+ code: "zu",
2926
+ name: "Zulu (zu)"
2927
+ },
2928
+ {
2929
+ code: "zu-ZA",
2930
+ name: "Zulu (South Africa) (zu-ZA)"
2759
2931
  }
2760
- return true;
2761
- };
2762
- const addAllLocalesToPermissions = async (permissions2) => {
2763
- const { actionProvider } = strapi.service("admin::permission");
2764
- const { find: findAllLocales } = getService("locales");
2765
- const allLocales = await findAllLocales();
2766
- const allLocalesCode = allLocales.map(prop("code"));
2767
- return Promise.all(
2768
- permissions2.map(async (permission) => {
2769
- const { action, subject } = permission;
2770
- const appliesToLocalesProperty = await actionProvider.appliesToProperty(
2771
- "locales",
2772
- action,
2773
- subject
2932
+ ];
2933
+ const getInitLocale = () => {
2934
+ const envLocaleCode = process.env.STRAPI_PLUGIN_I18N_INIT_LOCALE_CODE;
2935
+ if (envLocaleCode) {
2936
+ const matchingLocale = isoLocales.find(({ code }) => code === envLocaleCode);
2937
+ if (!matchingLocale) {
2938
+ throw new Error(
2939
+ "Unknown locale code provided in the environment variable STRAPI_PLUGIN_I18N_INIT_LOCALE_CODE"
2774
2940
  );
2775
- if (!appliesToLocalesProperty) {
2776
- return permission;
2777
- }
2778
- const oldPermissionProperties = getOr({}, "properties", permission);
2779
- return { ...permission, properties: { ...oldPermissionProperties, locales: allLocalesCode } };
2780
- })
2781
- );
2782
- };
2783
- const syncSuperAdminPermissionsWithLocales = async () => {
2784
- const roleService = strapi.service("admin::role");
2785
- const permissionService = strapi.service("admin::permission");
2786
- const superAdminRole = await roleService.getSuperAdmin();
2787
- if (!superAdminRole) {
2788
- return;
2789
- }
2790
- const superAdminPermissions = await permissionService.findMany({
2791
- where: {
2792
- role: {
2793
- id: superAdminRole.id
2794
- }
2795
- }
2796
- });
2797
- const newSuperAdminPermissions = await addAllLocalesToPermissions(superAdminPermissions);
2798
- await roleService.assignPermissions(superAdminRole.id, newSuperAdminPermissions);
2799
- };
2800
- const registerI18nActions = async () => {
2801
- const { actionProvider } = strapi.service("admin::permission");
2802
- await actionProvider.registerMany(actions);
2803
- };
2804
- const registerI18nActionsHooks = () => {
2805
- const { actionProvider } = strapi.service("admin::permission");
2806
- const { hooks } = strapi.service("admin::role");
2807
- actionProvider.hooks.appliesPropertyToSubject.register(shouldApplyLocalesPropertyToSubject);
2808
- hooks.willResetSuperAdminPermissions.register(addAllLocalesToPermissions);
2809
- };
2810
- const updateActionsProperties = () => {
2811
- const { actionProvider } = strapi.service("admin::permission");
2812
- actionProvider.hooks.willRegister.register(addLocalesPropertyIfNeeded);
2813
- actionProvider.values().forEach((action) => addLocalesPropertyIfNeeded({ value: action }));
2814
- };
2815
- const i18nActionsService = {
2816
- actions,
2817
- registerI18nActions,
2818
- registerI18nActionsHooks,
2819
- updateActionsProperties,
2820
- syncSuperAdminPermissionsWithLocales
2821
- };
2822
- const localesPropertyHandler = async ({ action, section }) => {
2823
- const { actionProvider } = strapi.service("admin::permission");
2824
- const locales2 = await getService("locales").find();
2825
- if (isEmpty(locales2)) {
2826
- return;
2827
- }
2828
- for (const subject of section.subjects) {
2829
- const applies = await actionProvider.appliesToProperty("locales", action.actionId, subject.uid);
2830
- const hasLocalesProperty = subject.properties.find(
2831
- (property) => property.value === "locales"
2832
- );
2833
- if (applies && !hasLocalesProperty) {
2834
- subject.properties.push({
2835
- label: "Locales",
2836
- value: "locales",
2837
- children: locales2.map(({ name, code }) => ({ label: name || code, value: code }))
2838
- });
2839
- }
2840
- }
2841
- };
2842
- const registerLocalesPropertyHandler = () => {
2843
- const { sectionsBuilder } = strapi.service("admin::permission");
2844
- sectionsBuilder.addHandler("singleTypes", localesPropertyHandler);
2845
- sectionsBuilder.addHandler("collectionTypes", localesPropertyHandler);
2846
- };
2847
- const sectionsBuilderService = {
2848
- localesPropertyHandler,
2849
- registerLocalesPropertyHandler
2850
- };
2851
- const willRegisterPermission = (context) => {
2852
- const { permission, condition, user } = context;
2853
- const { subject, properties } = permission;
2854
- const isSuperAdmin = strapi.service("admin::role").hasSuperAdminRole(user);
2855
- if (isSuperAdmin) {
2856
- return;
2857
- }
2858
- const { locales: locales2 } = properties || {};
2859
- const { isLocalizedContentType: isLocalizedContentType2 } = getService("content-types");
2860
- if (!subject) {
2861
- return;
2862
- }
2863
- const ct = strapi.contentTypes[subject];
2864
- if (!isLocalizedContentType2(ct)) {
2865
- return;
2866
- }
2867
- if (locales2 === null) {
2868
- return;
2869
- }
2870
- condition.and({
2871
- locale: {
2872
- $in: locales2 || []
2873
2941
  }
2874
- });
2875
- };
2876
- const registerI18nPermissionsHandlers = () => {
2877
- const { engine } = strapi.service("admin::permission");
2878
- engine.hooks["before-register.permission"].register(willRegisterPermission);
2879
- };
2880
- const engineService = {
2881
- willRegisterPermission,
2882
- registerI18nPermissionsHandlers
2883
- };
2884
- const permissions = () => ({
2885
- actions: i18nActionsService,
2886
- sectionsBuilder: sectionsBuilderService,
2887
- engine: engineService
2888
- });
2889
- const sendDidInitializeEvent = async () => {
2890
- const { isLocalizedContentType: isLocalizedContentType2 } = getService("content-types");
2891
- const numberOfContentTypes = reduce(
2892
- (sum, contentType) => isLocalizedContentType2(contentType) ? sum + 1 : sum,
2893
- 0
2894
- )(strapi.contentTypes);
2895
- await strapi.telemetry.send("didInitializeI18n", { groupProperties: { numberOfContentTypes } });
2896
- };
2897
- const sendDidUpdateI18nLocalesEvent = async () => {
2898
- const numberOfLocales = await getService("locales").count();
2899
- await strapi.telemetry.send("didUpdateI18nLocales", {
2900
- groupProperties: { numberOfLocales }
2901
- });
2902
- };
2903
- const metrics = () => ({
2904
- sendDidInitializeEvent,
2905
- sendDidUpdateI18nLocalesEvent
2906
- });
2907
- const syncNonLocalizedAttributes = async (sourceEntry, model) => {
2908
- const { copyNonLocalizedAttributes: copyNonLocalizedAttributes2 } = getService("content-types");
2909
- const nonLocalizedAttributes = copyNonLocalizedAttributes2(model, sourceEntry);
2910
- if (isEmpty(nonLocalizedAttributes)) {
2911
- return;
2942
+ return { ...matchingLocale };
2912
2943
  }
2913
- const uid = model.uid;
2914
- const documentId = sourceEntry.documentId;
2915
- const locale2 = sourceEntry.locale;
2916
- const status = sourceEntry?.publishedAt ? "published" : "draft";
2917
- const localeEntriesToUpdate = await strapi.db.query(uid).findMany({
2918
- where: {
2919
- documentId,
2920
- publishedAt: status === "published" ? { $ne: null } : null,
2921
- locale: { $ne: locale2 }
2922
- },
2923
- select: ["locale", "id"]
2924
- });
2925
- const entryData = await strapi.documents(uid).omitComponentData(nonLocalizedAttributes);
2926
- await async.map(localeEntriesToUpdate, async (entry) => {
2927
- const transformedData = await strapi.documents.utils.transformData(
2928
- cloneDeep(nonLocalizedAttributes),
2929
- {
2930
- uid,
2931
- status,
2932
- locale: entry.locale,
2933
- allowMissingId: true
2934
- }
2935
- );
2936
- const componentData = await strapi.documents(uid).updateComponents(entry, transformedData);
2937
- await strapi.db.query(uid).update({
2938
- where: {
2939
- documentId,
2940
- publishedAt: status === "published" ? { $ne: null } : null,
2941
- locale: { $eq: entry.locale }
2942
- },
2943
- // The data we send to the update function is the entry data merged with
2944
- // the updated component data
2945
- data: Object.assign(cloneDeep(entryData), componentData)
2946
- });
2947
- });
2944
+ return {
2945
+ code: "en",
2946
+ name: "English (en)"
2947
+ };
2948
2948
  };
2949
- const localizations = () => ({
2950
- syncNonLocalizedAttributes
2951
- });
2949
+ const DEFAULT_LOCALE = getInitLocale();
2952
2950
  const find = (params = {}) => strapi.db.query("plugin::i18n.locale").findMany({ where: params });
2953
2951
  const findById = (id) => strapi.db.query("plugin::i18n.locale").findOne({ where: { id } });
2954
2952
  const findByCode = (code) => strapi.db.query("plugin::i18n.locale").findOne({ where: { code } });
@@ -3016,91 +3014,6 @@ const getIsoLocales = () => isoLocales;
3016
3014
  const isoLocalesService = () => ({
3017
3015
  getIsoLocales
3018
3016
  });
3019
- const LOCALE_QUERY_FILTER = "locale";
3020
- const SINGLE_ENTRY_ACTIONS = ["findOne", "update", "delete"];
3021
- const BULK_ACTIONS = ["delete"];
3022
- const paramsContain = (key, params) => {
3023
- return has(key, params.filters) || isArray(params.filters) && params.filters.some((clause) => has(key, clause)) || isArray(get("$and", params.filters)) && params.filters.$and.some((clause) => has(key, clause));
3024
- };
3025
- const wrapParams = async (params = {}, ctx = {}) => {
3026
- const { action } = ctx;
3027
- if (has(LOCALE_QUERY_FILTER, params)) {
3028
- if (params[LOCALE_QUERY_FILTER] === "all") {
3029
- return omit(LOCALE_QUERY_FILTER, params);
3030
- }
3031
- return {
3032
- ...omit(LOCALE_QUERY_FILTER, params),
3033
- filters: {
3034
- $and: [{ locale: params[LOCALE_QUERY_FILTER] }].concat(params.filters || [])
3035
- }
3036
- };
3037
- }
3038
- const entityDefinedById = paramsContain("id", params) && SINGLE_ENTRY_ACTIONS.includes(action);
3039
- const entitiesDefinedByIds = paramsContain("id.$in", params) && BULK_ACTIONS.includes(action);
3040
- if (entityDefinedById || entitiesDefinedByIds) {
3041
- return params;
3042
- }
3043
- const { getDefaultLocale: getDefaultLocale2 } = getService("locales");
3044
- return {
3045
- ...params,
3046
- filters: {
3047
- $and: [{ locale: await getDefaultLocale2() }].concat(params.filters || [])
3048
- }
3049
- };
3050
- };
3051
- const decorator = (service) => ({
3052
- /**
3053
- * Wraps result
3054
- * @param {object} result - result object of query
3055
- * @param {object} ctx - Query context
3056
- * @param {object} ctx.model - Model that is being used
3057
- */
3058
- async wrapResult(result = {}, ctx = {}) {
3059
- return service.wrapResult.call(this, result, ctx);
3060
- },
3061
- /**
3062
- * Wraps query options. In particular will add default locale to query params
3063
- * @param {object} params - Query options object (params, data, files, populate)
3064
- * @param {object} ctx - Query context
3065
- * @param {object} ctx.model - Model that is being used
3066
- */
3067
- async wrapParams(params = {}, ctx = {}) {
3068
- const wrappedParams = await service.wrapParams.call(this, params, ctx);
3069
- const model = strapi.getModel(ctx.uid);
3070
- const { isLocalizedContentType: isLocalizedContentType2 } = getService("content-types");
3071
- if (!isLocalizedContentType2(model)) {
3072
- return wrappedParams;
3073
- }
3074
- return wrapParams(wrappedParams, ctx);
3075
- },
3076
- /**
3077
- * Find an entry or several if fetching all locales
3078
- * @param {string} uid - Model uid
3079
- * @param {object} opts - Query options object (params, data, files, populate)
3080
- */
3081
- async findMany(uid, opts) {
3082
- const model = strapi.getModel(uid);
3083
- const { isLocalizedContentType: isLocalizedContentType2 } = getService("content-types");
3084
- if (!isLocalizedContentType2(model)) {
3085
- return service.findMany.call(this, uid, opts);
3086
- }
3087
- const { kind } = model;
3088
- if (kind === "singleType") {
3089
- if (opts[LOCALE_QUERY_FILTER] === "all") {
3090
- const wrappedParams = await this.wrapParams(opts, { uid, action: "findMany" });
3091
- const query = strapi.get("query-params").transform(uid, wrappedParams);
3092
- const entities = await strapi.db.query(uid).findMany(query);
3093
- return this.wrapResult(entities, { uid, action: "findMany" });
3094
- }
3095
- return service.findMany.call(this, uid, opts);
3096
- }
3097
- return service.findMany.call(this, uid, opts);
3098
- }
3099
- });
3100
- const entityServiceDecorator = () => ({
3101
- decorator,
3102
- wrapParams
3103
- });
3104
3017
  const {
3105
3018
  isRelationalAttribute,
3106
3019
  getVisibleAttributes,
@@ -3225,13 +3138,33 @@ const contentTypes = () => ({
3225
3138
  fillNonLocalizedAttributes,
3226
3139
  getNestedPopulateOfNonLocalizedAttributes
3227
3140
  });
3141
+ const LOCALIZATION_FIELDS = ["locale", "localizations"];
3142
+ const sanitize = ({ strapi: strapi2 }) => {
3143
+ const { isLocalizedContentType: isLocalizedContentType2 } = getService("content-types");
3144
+ const sanitizeLocalizationFields = curry(
3145
+ (schema2, entity) => traverseEntity(
3146
+ ({ key, schema: schema22 }, { remove }) => {
3147
+ const isLocalized = isLocalizedContentType2(schema22);
3148
+ const isLocalizationField = LOCALIZATION_FIELDS.includes(key);
3149
+ if (!isLocalized && isLocalizationField) {
3150
+ remove(key);
3151
+ }
3152
+ },
3153
+ { schema: schema2, getModel: strapi2.getModel.bind(strapi2) },
3154
+ entity
3155
+ )
3156
+ );
3157
+ return {
3158
+ sanitizeLocalizationFields
3159
+ };
3160
+ };
3228
3161
  const services = {
3229
3162
  permissions,
3230
3163
  metrics,
3231
3164
  localizations,
3232
3165
  locales,
3166
+ sanitize,
3233
3167
  "iso-locales": isoLocalesService,
3234
- "entity-service-decorator": entityServiceDecorator,
3235
3168
  "content-types": contentTypes
3236
3169
  };
3237
3170
  const admin = {