@strapi/i18n 0.0.0-experimental.e60ec1829240dae21c1e1d29076681c322288813 → 0.0.0-experimental.e8d8fc824d0f6a695b2a9ebaa4680ed21c3645ca

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 (64) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/{SettingsPage-CeqfDjsb.mjs → SettingsPage-B6QDUmu9.mjs} +117 -128
  3. package/dist/_chunks/SettingsPage-B6QDUmu9.mjs.map +1 -0
  4. package/dist/_chunks/{SettingsPage-Djqsdrzs.js → SettingsPage-BsHtr3lV.js} +118 -130
  5. package/dist/_chunks/SettingsPage-BsHtr3lV.js.map +1 -0
  6. package/dist/_chunks/{en-BuBc6LKZ.js → en-BKBz3tro.js} +14 -2
  7. package/dist/_chunks/en-BKBz3tro.js.map +1 -0
  8. package/dist/_chunks/{en-CnrTsjWS.mjs → en-DlXfy6Gy.mjs} +14 -2
  9. package/dist/_chunks/en-DlXfy6Gy.mjs.map +1 -0
  10. package/dist/_chunks/index-3XgwXL6T.js +1628 -0
  11. package/dist/_chunks/index-3XgwXL6T.js.map +1 -0
  12. package/dist/_chunks/index-iEQ79W05.mjs +1607 -0
  13. package/dist/_chunks/index-iEQ79W05.mjs.map +1 -0
  14. package/dist/admin/index.js +1 -1
  15. package/dist/admin/index.mjs +2 -2
  16. package/dist/admin/src/components/BulkLocaleActionModal.d.ts +16 -0
  17. package/dist/admin/src/components/CMHeaderActions.d.ts +35 -3
  18. package/dist/admin/src/components/CreateLocale.d.ts +6 -6
  19. package/dist/admin/src/components/EditLocale.d.ts +5 -4
  20. package/dist/admin/src/components/LocaleListCell.d.ts +4 -4
  21. package/dist/admin/src/contentReleasesHooks/releaseDetailsView.d.ts +9 -5
  22. package/dist/admin/src/services/api.d.ts +2 -3
  23. package/dist/admin/src/services/locales.d.ts +1 -1
  24. package/dist/admin/src/services/relations.d.ts +7 -0
  25. package/dist/admin/src/utils/baseQuery.d.ts +4 -19
  26. package/dist/admin/src/utils/clean.d.ts +4 -0
  27. package/dist/admin/src/utils/schemas.d.ts +1 -0
  28. package/dist/server/index.js +418 -478
  29. package/dist/server/index.js.map +1 -1
  30. package/dist/server/index.mjs +419 -478
  31. package/dist/server/index.mjs.map +1 -1
  32. package/dist/server/src/bootstrap.d.ts +1 -4
  33. package/dist/server/src/bootstrap.d.ts.map +1 -1
  34. package/dist/server/src/index.d.ts +21 -13
  35. package/dist/server/src/index.d.ts.map +1 -1
  36. package/dist/server/src/register.d.ts.map +1 -1
  37. package/dist/server/src/services/index.d.ts +20 -10
  38. package/dist/server/src/services/index.d.ts.map +1 -1
  39. package/dist/server/src/services/permissions/actions.d.ts +14 -2
  40. package/dist/server/src/services/permissions/actions.d.ts.map +1 -1
  41. package/dist/server/src/services/permissions.d.ts +14 -2
  42. package/dist/server/src/services/permissions.d.ts.map +1 -1
  43. package/dist/server/src/services/sanitize/index.d.ts +11 -0
  44. package/dist/server/src/services/sanitize/index.d.ts.map +1 -0
  45. package/dist/server/src/utils/index.d.ts +2 -2
  46. package/dist/server/src/utils/index.d.ts.map +1 -1
  47. package/dist/shared/contracts/content-manager.d.ts +20 -1
  48. package/package.json +19 -20
  49. package/dist/_chunks/SettingsPage-CeqfDjsb.mjs.map +0 -1
  50. package/dist/_chunks/SettingsPage-Djqsdrzs.js.map +0 -1
  51. package/dist/_chunks/en-BuBc6LKZ.js.map +0 -1
  52. package/dist/_chunks/en-CnrTsjWS.mjs.map +0 -1
  53. package/dist/_chunks/index-BDU1w_fd.mjs +0 -1058
  54. package/dist/_chunks/index-BDU1w_fd.mjs.map +0 -1
  55. package/dist/_chunks/index-DMXJeGjN.js +0 -1082
  56. package/dist/_chunks/index-DMXJeGjN.js.map +0 -1
  57. package/dist/admin/src/components/Initializer.d.ts +0 -5
  58. package/dist/server/src/migrations/content-type/disable/index.d.ts +0 -3
  59. package/dist/server/src/migrations/content-type/disable/index.d.ts.map +0 -1
  60. package/dist/server/src/migrations/content-type/enable/index.d.ts +0 -3
  61. package/dist/server/src/migrations/content-type/enable/index.d.ts.map +0 -1
  62. package/dist/server/src/services/entity-service-decorator.d.ts +0 -29
  63. package/dist/server/src/services/entity-service-decorator.d.ts.map +0 -1
  64. package/strapi-server.js +0 -3
@@ -4,8 +4,7 @@ const fp = require("lodash/fp");
4
4
  const utils = require("@strapi/utils");
5
5
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
6
6
  function _interopNamespace(e) {
7
- if (e && e.__esModule)
8
- return e;
7
+ if (e && e.__esModule) return e;
9
8
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
10
9
  if (e) {
11
10
  for (const k in e) {
@@ -51,7 +50,7 @@ const registerModelsHooks = () => {
51
50
  const attributesToPopulate = getNestedPopulateOfNonLocalizedAttributes2(schema2.uid);
52
51
  const result = await next();
53
52
  let resultID;
54
- if (Array.isArray(result?.entries)) {
53
+ if (Array.isArray(result?.entries) && result.entries[0]?.id) {
55
54
  resultID = result.entries[0].id;
56
55
  } else if (result?.id) {
57
56
  resultID = result.id;
@@ -65,12 +64,10 @@ const registerModelsHooks = () => {
65
64
  return result;
66
65
  });
67
66
  };
68
- const bootstrap = async ({ strapi: strapi2 }) => {
67
+ const bootstrap = async () => {
69
68
  const { sendDidInitializeEvent: sendDidInitializeEvent2 } = getService("metrics");
70
- const { decorator: decorator2 } = getService("entity-service-decorator");
71
69
  const { initDefaultLocale: initDefaultLocale2 } = getService("locales");
72
70
  const { sectionsBuilder, actions: actions2, engine } = getService("permissions");
73
- strapi2.entityService.decorate(decorator2);
74
71
  await initDefaultLocale2();
75
72
  sectionsBuilder.registerLocalesPropertyHandler();
76
73
  await actions2.registerI18nActions();
@@ -197,6 +194,352 @@ const getI18nLocaleArgPlugin = ({ nexus, typeRegistry }) => {
197
194
  }
198
195
  });
199
196
  };
197
+ const register = ({ strapi: strapi2 }) => {
198
+ extendContentTypes(strapi2);
199
+ addContentManagerLocaleMiddleware(strapi2);
200
+ };
201
+ const addContentManagerLocaleMiddleware = (strapi2) => {
202
+ strapi2.server.router.use("/content-manager/collection-types/:model", (ctx, next) => {
203
+ if (ctx.method === "POST" || ctx.method === "PUT") {
204
+ return validateLocaleCreation(ctx, next);
205
+ }
206
+ return next();
207
+ });
208
+ strapi2.server.router.use("/content-manager/single-types/:model", (ctx, next) => {
209
+ if (ctx.method === "POST" || ctx.method === "PUT") {
210
+ return validateLocaleCreation(ctx, next);
211
+ }
212
+ return next();
213
+ });
214
+ };
215
+ const extendContentTypes = (strapi2) => {
216
+ const { isLocalizedContentType: isLocalizedContentType2 } = getService("content-types");
217
+ Object.values(strapi2.contentTypes).forEach((contentType) => {
218
+ const { attributes: attributes2 } = contentType;
219
+ const isLocalized = isLocalizedContentType2(contentType);
220
+ ___default.default.set(attributes2, "locale", {
221
+ writable: true,
222
+ private: !isLocalized,
223
+ configurable: false,
224
+ visible: false,
225
+ type: "string"
226
+ });
227
+ ___default.default.set(attributes2, "localizations", {
228
+ type: "relation",
229
+ relation: "oneToMany",
230
+ target: contentType.uid,
231
+ writable: false,
232
+ private: !isLocalized,
233
+ configurable: false,
234
+ visible: false,
235
+ unstable_virtual: true,
236
+ joinColumn: {
237
+ name: "document_id",
238
+ referencedColumn: "document_id",
239
+ referencedTable: strapi2.db.metadata.identifiers.getTableName(contentType.collectionName),
240
+ // ensure the population will not include the results we already loaded
241
+ on({ results }) {
242
+ return {
243
+ id: {
244
+ $notIn: results.map((r) => r.id)
245
+ }
246
+ };
247
+ }
248
+ }
249
+ });
250
+ });
251
+ if (strapi2.plugin("graphql")) {
252
+ graphqlProvider({ strapi: strapi2 }).register();
253
+ }
254
+ };
255
+ const info = {
256
+ singularName: "locale",
257
+ pluralName: "locales",
258
+ collectionName: "locales",
259
+ displayName: "Locale",
260
+ description: ""
261
+ };
262
+ const options = {};
263
+ const pluginOptions = {
264
+ "content-manager": {
265
+ visible: false
266
+ },
267
+ "content-type-builder": {
268
+ visible: false
269
+ }
270
+ };
271
+ const attributes = {
272
+ name: {
273
+ type: "string",
274
+ min: 1,
275
+ max: 50,
276
+ configurable: false
277
+ },
278
+ code: {
279
+ type: "string",
280
+ unique: true,
281
+ configurable: false
282
+ }
283
+ };
284
+ const schema = {
285
+ info,
286
+ options,
287
+ pluginOptions,
288
+ attributes
289
+ };
290
+ const locale = {
291
+ schema
292
+ };
293
+ const contentTypes$1 = {
294
+ locale
295
+ };
296
+ const actions = [
297
+ {
298
+ section: "settings",
299
+ category: "Internationalization",
300
+ subCategory: "Locales",
301
+ pluginName: "i18n",
302
+ displayName: "Create",
303
+ uid: "locale.create"
304
+ },
305
+ {
306
+ section: "settings",
307
+ category: "Internationalization",
308
+ subCategory: "Locales",
309
+ pluginName: "i18n",
310
+ displayName: "Read",
311
+ uid: "locale.read",
312
+ aliases: [
313
+ { actionId: "plugin::content-manager.explorer.read", subjects: ["plugin::i18n.locale"] }
314
+ ]
315
+ },
316
+ {
317
+ section: "settings",
318
+ category: "Internationalization",
319
+ subCategory: "Locales",
320
+ pluginName: "i18n",
321
+ displayName: "Update",
322
+ uid: "locale.update"
323
+ },
324
+ {
325
+ section: "settings",
326
+ category: "Internationalization",
327
+ subCategory: "Locales",
328
+ pluginName: "i18n",
329
+ displayName: "Delete",
330
+ uid: "locale.delete"
331
+ }
332
+ ];
333
+ const addLocalesPropertyIfNeeded = ({ value: action }) => {
334
+ const {
335
+ section,
336
+ options: { applyToProperties }
337
+ } = action;
338
+ if (section !== "contentTypes") {
339
+ return;
340
+ }
341
+ if (fp.isArray(applyToProperties) && applyToProperties.includes("locales")) {
342
+ return;
343
+ }
344
+ action.options.applyToProperties = fp.isArray(applyToProperties) ? applyToProperties.concat("locales") : ["locales"];
345
+ };
346
+ const shouldApplyLocalesPropertyToSubject = ({ property, subject }) => {
347
+ if (property === "locales") {
348
+ const model = strapi.getModel(subject);
349
+ return getService("content-types").isLocalizedContentType(model);
350
+ }
351
+ return true;
352
+ };
353
+ const addAllLocalesToPermissions = async (permissions2) => {
354
+ const { actionProvider } = strapi.service("admin::permission");
355
+ const { find: findAllLocales } = getService("locales");
356
+ const allLocales = await findAllLocales();
357
+ const allLocalesCode = allLocales.map(fp.prop("code"));
358
+ return Promise.all(
359
+ permissions2.map(async (permission) => {
360
+ const { action, subject } = permission;
361
+ const appliesToLocalesProperty = await actionProvider.appliesToProperty(
362
+ "locales",
363
+ action,
364
+ subject
365
+ );
366
+ if (!appliesToLocalesProperty) {
367
+ return permission;
368
+ }
369
+ const oldPermissionProperties = fp.getOr({}, "properties", permission);
370
+ return { ...permission, properties: { ...oldPermissionProperties, locales: allLocalesCode } };
371
+ })
372
+ );
373
+ };
374
+ const syncSuperAdminPermissionsWithLocales = async () => {
375
+ const roleService = strapi.service("admin::role");
376
+ const permissionService = strapi.service("admin::permission");
377
+ const superAdminRole = await roleService.getSuperAdmin();
378
+ if (!superAdminRole) {
379
+ return;
380
+ }
381
+ const superAdminPermissions = await permissionService.findMany({
382
+ where: {
383
+ role: {
384
+ id: superAdminRole.id
385
+ }
386
+ }
387
+ });
388
+ const newSuperAdminPermissions = await addAllLocalesToPermissions(superAdminPermissions);
389
+ await roleService.assignPermissions(superAdminRole.id, newSuperAdminPermissions);
390
+ };
391
+ const registerI18nActions = async () => {
392
+ const { actionProvider } = strapi.service("admin::permission");
393
+ await actionProvider.registerMany(actions);
394
+ };
395
+ const registerI18nActionsHooks = () => {
396
+ const { actionProvider } = strapi.service("admin::permission");
397
+ const { hooks } = strapi.service("admin::role");
398
+ actionProvider.hooks.appliesPropertyToSubject.register(shouldApplyLocalesPropertyToSubject);
399
+ hooks.willResetSuperAdminPermissions.register(addAllLocalesToPermissions);
400
+ };
401
+ const updateActionsProperties = () => {
402
+ const { actionProvider } = strapi.service("admin::permission");
403
+ actionProvider.hooks.willRegister.register(addLocalesPropertyIfNeeded);
404
+ actionProvider.values().forEach((action) => addLocalesPropertyIfNeeded({ value: action }));
405
+ };
406
+ const i18nActionsService = {
407
+ actions,
408
+ registerI18nActions,
409
+ registerI18nActionsHooks,
410
+ updateActionsProperties,
411
+ syncSuperAdminPermissionsWithLocales
412
+ };
413
+ const localesPropertyHandler = async ({ action, section }) => {
414
+ const { actionProvider } = strapi.service("admin::permission");
415
+ const locales2 = await getService("locales").find();
416
+ if (fp.isEmpty(locales2)) {
417
+ return;
418
+ }
419
+ for (const subject of section.subjects) {
420
+ const applies = await actionProvider.appliesToProperty("locales", action.actionId, subject.uid);
421
+ const hasLocalesProperty = subject.properties.find(
422
+ (property) => property.value === "locales"
423
+ );
424
+ if (applies && !hasLocalesProperty) {
425
+ subject.properties.push({
426
+ label: "Locales",
427
+ value: "locales",
428
+ children: locales2.map(({ name, code }) => ({ label: name || code, value: code }))
429
+ });
430
+ }
431
+ }
432
+ };
433
+ const registerLocalesPropertyHandler = () => {
434
+ const { sectionsBuilder } = strapi.service("admin::permission");
435
+ sectionsBuilder.addHandler("singleTypes", localesPropertyHandler);
436
+ sectionsBuilder.addHandler("collectionTypes", localesPropertyHandler);
437
+ };
438
+ const sectionsBuilderService = {
439
+ localesPropertyHandler,
440
+ registerLocalesPropertyHandler
441
+ };
442
+ const willRegisterPermission = (context) => {
443
+ const { permission, condition, user } = context;
444
+ const { subject, properties } = permission;
445
+ const isSuperAdmin = strapi.service("admin::role").hasSuperAdminRole(user);
446
+ if (isSuperAdmin) {
447
+ return;
448
+ }
449
+ const { locales: locales2 } = properties || {};
450
+ const { isLocalizedContentType: isLocalizedContentType2 } = getService("content-types");
451
+ if (!subject) {
452
+ return;
453
+ }
454
+ const ct = strapi.contentTypes[subject];
455
+ if (!isLocalizedContentType2(ct)) {
456
+ return;
457
+ }
458
+ if (locales2 === null) {
459
+ return;
460
+ }
461
+ condition.and({
462
+ locale: {
463
+ $in: locales2 || []
464
+ }
465
+ });
466
+ };
467
+ const registerI18nPermissionsHandlers = () => {
468
+ const { engine } = strapi.service("admin::permission");
469
+ engine.hooks["before-register.permission"].register(willRegisterPermission);
470
+ };
471
+ const engineService = {
472
+ willRegisterPermission,
473
+ registerI18nPermissionsHandlers
474
+ };
475
+ const permissions = () => ({
476
+ actions: i18nActionsService,
477
+ sectionsBuilder: sectionsBuilderService,
478
+ engine: engineService
479
+ });
480
+ const sendDidInitializeEvent = async () => {
481
+ const { isLocalizedContentType: isLocalizedContentType2 } = getService("content-types");
482
+ const numberOfContentTypes = fp.reduce(
483
+ (sum, contentType) => isLocalizedContentType2(contentType) ? sum + 1 : sum,
484
+ 0
485
+ )(strapi.contentTypes);
486
+ await strapi.telemetry.send("didInitializeI18n", { groupProperties: { numberOfContentTypes } });
487
+ };
488
+ const sendDidUpdateI18nLocalesEvent = async () => {
489
+ const numberOfLocales = await getService("locales").count();
490
+ await strapi.telemetry.send("didUpdateI18nLocales", {
491
+ groupProperties: { numberOfLocales }
492
+ });
493
+ };
494
+ const metrics = () => ({
495
+ sendDidInitializeEvent,
496
+ sendDidUpdateI18nLocalesEvent
497
+ });
498
+ const syncNonLocalizedAttributes = async (sourceEntry, model) => {
499
+ const { copyNonLocalizedAttributes: copyNonLocalizedAttributes2 } = getService("content-types");
500
+ const nonLocalizedAttributes = copyNonLocalizedAttributes2(model, sourceEntry);
501
+ if (fp.isEmpty(nonLocalizedAttributes)) {
502
+ return;
503
+ }
504
+ const uid = model.uid;
505
+ const documentId = sourceEntry.documentId;
506
+ const locale2 = sourceEntry.locale;
507
+ const status = sourceEntry?.publishedAt ? "published" : "draft";
508
+ const localeEntriesToUpdate = await strapi.db.query(uid).findMany({
509
+ where: {
510
+ documentId,
511
+ publishedAt: status === "published" ? { $ne: null } : null,
512
+ locale: { $ne: locale2 }
513
+ },
514
+ select: ["locale", "id"]
515
+ });
516
+ const entryData = await strapi.documents(uid).omitComponentData(nonLocalizedAttributes);
517
+ await utils.async.map(localeEntriesToUpdate, async (entry) => {
518
+ const transformedData = await strapi.documents.utils.transformData(
519
+ fp.cloneDeep(nonLocalizedAttributes),
520
+ {
521
+ uid,
522
+ status,
523
+ locale: entry.locale,
524
+ allowMissingId: true
525
+ }
526
+ );
527
+ const componentData = await strapi.documents(uid).updateComponents(entry, transformedData);
528
+ await strapi.db.query(uid).update({
529
+ where: {
530
+ documentId,
531
+ publishedAt: status === "published" ? { $ne: null } : null,
532
+ locale: { $eq: entry.locale }
533
+ },
534
+ // The data we send to the update function is the entry data merged with
535
+ // the updated component data
536
+ data: Object.assign(fp.cloneDeep(entryData), componentData)
537
+ });
538
+ });
539
+ };
540
+ const localizations = () => ({
541
+ syncNonLocalizedAttributes
542
+ });
200
543
  const isoLocales = [
201
544
  {
202
545
  code: "af",
@@ -2575,401 +2918,63 @@ const isoLocales = [
2575
2918
  name: "Welsh (United Kingdom) (cy-GB)"
2576
2919
  },
2577
2920
  {
2578
- code: "yav",
2579
- name: "Yangben (yav)"
2580
- },
2581
- {
2582
- code: "yav-CM",
2583
- name: "Yangben (Cameroon) (yav-CM)"
2584
- },
2585
- {
2586
- code: "yo",
2587
- name: "Yoruba (yo)"
2921
+ code: "wo",
2922
+ name: "Wolof (wo)"
2588
2923
  },
2589
2924
  {
2590
- code: "yo-NG",
2591
- name: "Yoruba (Nigeria) (yo-NG)"
2925
+ code: "xh",
2926
+ name: "Xhosa (xh)"
2592
2927
  },
2593
2928
  {
2594
- code: "dje",
2595
- name: "Zarma (dje)"
2596
- },
2597
- {
2598
- code: "dje-NE",
2599
- name: "Zarma (Niger) (dje-NE)"
2600
- },
2601
- {
2602
- code: "zu",
2603
- name: "Zulu (zu)"
2604
- },
2605
- {
2606
- code: "zu-ZA",
2607
- name: "Zulu (South Africa) (zu-ZA)"
2608
- }
2609
- ];
2610
- const getInitLocale = () => {
2611
- const envLocaleCode = process.env.STRAPI_PLUGIN_I18N_INIT_LOCALE_CODE;
2612
- if (envLocaleCode) {
2613
- const matchingLocale = isoLocales.find(({ code }) => code === envLocaleCode);
2614
- if (!matchingLocale) {
2615
- throw new Error(
2616
- "Unknown locale code provided in the environment variable STRAPI_PLUGIN_I18N_INIT_LOCALE_CODE"
2617
- );
2618
- }
2619
- return { ...matchingLocale };
2620
- }
2621
- return {
2622
- code: "en",
2623
- name: "English (en)"
2624
- };
2625
- };
2626
- const DEFAULT_LOCALE = getInitLocale();
2627
- const enableContentType = 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 strapi.db.query(uid).updateMany({
2642
- where: { locale: null },
2643
- data: { locale: defaultLocale }
2644
- });
2645
- }
2646
- }
2647
- };
2648
- const disableContentType = async ({ oldContentTypes, contentTypes: contentTypes2 }) => {
2649
- const { isLocalizedContentType: isLocalizedContentType2 } = getService("content-types");
2650
- const { getDefaultLocale: getDefaultLocale2 } = getService("locales");
2651
- if (!oldContentTypes) {
2652
- return;
2653
- }
2654
- for (const uid in contentTypes2) {
2655
- if (!oldContentTypes[uid]) {
2656
- continue;
2657
- }
2658
- const oldContentType = oldContentTypes[uid];
2659
- const contentType = contentTypes2[uid];
2660
- if (isLocalizedContentType2(oldContentType) && !isLocalizedContentType2(contentType)) {
2661
- const defaultLocale = await getDefaultLocale2() || DEFAULT_LOCALE.code;
2662
- await Promise.all([
2663
- // Delete all entities that are not in the default locale
2664
- strapi.db.query(uid).deleteMany({
2665
- where: { locale: { $ne: defaultLocale } }
2666
- }),
2667
- // Set locale to null for the rest
2668
- strapi.db.query(uid).updateMany({
2669
- where: { locale: { $eq: defaultLocale } },
2670
- data: { locale: null }
2671
- })
2672
- ]);
2673
- }
2674
- }
2675
- };
2676
- const register = ({ strapi: strapi2 }) => {
2677
- extendContentTypes(strapi2);
2678
- addContentManagerLocaleMiddleware(strapi2);
2679
- addContentTypeSyncHooks(strapi2);
2680
- };
2681
- const addContentManagerLocaleMiddleware = (strapi2) => {
2682
- strapi2.server.router.use("/content-manager/collection-types/:model", (ctx, next) => {
2683
- if (ctx.method === "POST" || ctx.method === "PUT") {
2684
- return validateLocaleCreation(ctx, next);
2685
- }
2686
- return next();
2687
- });
2688
- strapi2.server.router.use("/content-manager/single-types/:model", (ctx, next) => {
2689
- if (ctx.method === "POST" || ctx.method === "PUT") {
2690
- return validateLocaleCreation(ctx, next);
2691
- }
2692
- return next();
2693
- });
2694
- };
2695
- const addContentTypeSyncHooks = (strapi2) => {
2696
- strapi2.hook("strapi::content-types.beforeSync").register(disableContentType);
2697
- strapi2.hook("strapi::content-types.afterSync").register(enableContentType);
2698
- };
2699
- const extendContentTypes = (strapi2) => {
2700
- Object.values(strapi2.contentTypes).forEach((contentType) => {
2701
- const { attributes: attributes2 } = contentType;
2702
- ___default.default.set(attributes2, "locale", {
2703
- writable: true,
2704
- private: false,
2705
- configurable: false,
2706
- visible: false,
2707
- type: "string"
2708
- });
2709
- });
2710
- if (strapi2.plugin("graphql")) {
2711
- graphqlProvider({ strapi: strapi2 }).register();
2712
- }
2713
- };
2714
- const info = {
2715
- singularName: "locale",
2716
- pluralName: "locales",
2717
- collectionName: "locales",
2718
- displayName: "Locale",
2719
- description: ""
2720
- };
2721
- const options = {};
2722
- const pluginOptions = {
2723
- "content-manager": {
2724
- visible: false
2725
- },
2726
- "content-type-builder": {
2727
- visible: false
2728
- }
2729
- };
2730
- const attributes = {
2731
- name: {
2732
- type: "string",
2733
- min: 1,
2734
- max: 50,
2735
- configurable: false
2736
- },
2737
- code: {
2738
- type: "string",
2739
- unique: true,
2740
- configurable: false
2741
- }
2742
- };
2743
- const schema = {
2744
- info,
2745
- options,
2746
- pluginOptions,
2747
- attributes
2748
- };
2749
- const locale = {
2750
- schema
2751
- };
2752
- const contentTypes$1 = {
2753
- locale
2754
- };
2755
- const actions = ["create", "read", "update", "delete"].map((uid) => ({
2756
- section: "settings",
2757
- category: "Internationalization",
2758
- subCategory: "Locales",
2759
- pluginName: "i18n",
2760
- displayName: fp.capitalize(uid),
2761
- uid: `locale.${uid}`
2762
- }));
2763
- const addLocalesPropertyIfNeeded = ({ value: action }) => {
2764
- const {
2765
- section,
2766
- options: { applyToProperties }
2767
- } = action;
2768
- if (section !== "contentTypes") {
2769
- return;
2770
- }
2771
- if (fp.isArray(applyToProperties) && applyToProperties.includes("locales")) {
2772
- return;
2773
- }
2774
- action.options.applyToProperties = fp.isArray(applyToProperties) ? applyToProperties.concat("locales") : ["locales"];
2775
- };
2776
- const shouldApplyLocalesPropertyToSubject = ({ property, subject }) => {
2777
- if (property === "locales") {
2778
- const model = strapi.getModel(subject);
2779
- return getService("content-types").isLocalizedContentType(model);
2929
+ code: "yav",
2930
+ name: "Yangben (yav)"
2931
+ },
2932
+ {
2933
+ code: "yav-CM",
2934
+ name: "Yangben (Cameroon) (yav-CM)"
2935
+ },
2936
+ {
2937
+ code: "yo",
2938
+ name: "Yoruba (yo)"
2939
+ },
2940
+ {
2941
+ code: "yo-NG",
2942
+ name: "Yoruba (Nigeria) (yo-NG)"
2943
+ },
2944
+ {
2945
+ code: "dje",
2946
+ name: "Zarma (dje)"
2947
+ },
2948
+ {
2949
+ code: "dje-NE",
2950
+ name: "Zarma (Niger) (dje-NE)"
2951
+ },
2952
+ {
2953
+ code: "zu",
2954
+ name: "Zulu (zu)"
2955
+ },
2956
+ {
2957
+ code: "zu-ZA",
2958
+ name: "Zulu (South Africa) (zu-ZA)"
2780
2959
  }
2781
- return true;
2782
- };
2783
- const addAllLocalesToPermissions = async (permissions2) => {
2784
- const { actionProvider } = strapi.service("admin::permission");
2785
- const { find: findAllLocales } = getService("locales");
2786
- const allLocales = await findAllLocales();
2787
- const allLocalesCode = allLocales.map(fp.prop("code"));
2788
- return Promise.all(
2789
- permissions2.map(async (permission) => {
2790
- const { action, subject } = permission;
2791
- const appliesToLocalesProperty = await actionProvider.appliesToProperty(
2792
- "locales",
2793
- action,
2794
- subject
2960
+ ];
2961
+ const getInitLocale = () => {
2962
+ const envLocaleCode = process.env.STRAPI_PLUGIN_I18N_INIT_LOCALE_CODE;
2963
+ if (envLocaleCode) {
2964
+ const matchingLocale = isoLocales.find(({ code }) => code === envLocaleCode);
2965
+ if (!matchingLocale) {
2966
+ throw new Error(
2967
+ "Unknown locale code provided in the environment variable STRAPI_PLUGIN_I18N_INIT_LOCALE_CODE"
2795
2968
  );
2796
- if (!appliesToLocalesProperty) {
2797
- return permission;
2798
- }
2799
- const oldPermissionProperties = fp.getOr({}, "properties", permission);
2800
- return { ...permission, properties: { ...oldPermissionProperties, locales: allLocalesCode } };
2801
- })
2802
- );
2803
- };
2804
- const syncSuperAdminPermissionsWithLocales = async () => {
2805
- const roleService = strapi.service("admin::role");
2806
- const permissionService = strapi.service("admin::permission");
2807
- const superAdminRole = await roleService.getSuperAdmin();
2808
- if (!superAdminRole) {
2809
- return;
2810
- }
2811
- const superAdminPermissions = await permissionService.findMany({
2812
- where: {
2813
- role: {
2814
- id: superAdminRole.id
2815
- }
2816
- }
2817
- });
2818
- const newSuperAdminPermissions = await addAllLocalesToPermissions(superAdminPermissions);
2819
- await roleService.assignPermissions(superAdminRole.id, newSuperAdminPermissions);
2820
- };
2821
- const registerI18nActions = async () => {
2822
- const { actionProvider } = strapi.service("admin::permission");
2823
- await actionProvider.registerMany(actions);
2824
- };
2825
- const registerI18nActionsHooks = () => {
2826
- const { actionProvider } = strapi.service("admin::permission");
2827
- const { hooks } = strapi.service("admin::role");
2828
- actionProvider.hooks.appliesPropertyToSubject.register(shouldApplyLocalesPropertyToSubject);
2829
- hooks.willResetSuperAdminPermissions.register(addAllLocalesToPermissions);
2830
- };
2831
- const updateActionsProperties = () => {
2832
- const { actionProvider } = strapi.service("admin::permission");
2833
- actionProvider.hooks.willRegister.register(addLocalesPropertyIfNeeded);
2834
- actionProvider.values().forEach((action) => addLocalesPropertyIfNeeded({ value: action }));
2835
- };
2836
- const i18nActionsService = {
2837
- actions,
2838
- registerI18nActions,
2839
- registerI18nActionsHooks,
2840
- updateActionsProperties,
2841
- syncSuperAdminPermissionsWithLocales
2842
- };
2843
- const localesPropertyHandler = async ({ action, section }) => {
2844
- const { actionProvider } = strapi.service("admin::permission");
2845
- const locales2 = await getService("locales").find();
2846
- if (fp.isEmpty(locales2)) {
2847
- return;
2848
- }
2849
- for (const subject of section.subjects) {
2850
- const applies = await actionProvider.appliesToProperty("locales", action.actionId, subject.uid);
2851
- const hasLocalesProperty = subject.properties.find(
2852
- (property) => property.value === "locales"
2853
- );
2854
- if (applies && !hasLocalesProperty) {
2855
- subject.properties.push({
2856
- label: "Locales",
2857
- value: "locales",
2858
- children: locales2.map(({ name, code }) => ({ label: name || code, value: code }))
2859
- });
2860
- }
2861
- }
2862
- };
2863
- const registerLocalesPropertyHandler = () => {
2864
- const { sectionsBuilder } = strapi.service("admin::permission");
2865
- sectionsBuilder.addHandler("singleTypes", localesPropertyHandler);
2866
- sectionsBuilder.addHandler("collectionTypes", localesPropertyHandler);
2867
- };
2868
- const sectionsBuilderService = {
2869
- localesPropertyHandler,
2870
- registerLocalesPropertyHandler
2871
- };
2872
- const willRegisterPermission = (context) => {
2873
- const { permission, condition, user } = context;
2874
- const { subject, properties } = permission;
2875
- const isSuperAdmin = strapi.service("admin::role").hasSuperAdminRole(user);
2876
- if (isSuperAdmin) {
2877
- return;
2878
- }
2879
- const { locales: locales2 } = properties || {};
2880
- const { isLocalizedContentType: isLocalizedContentType2 } = getService("content-types");
2881
- if (!subject) {
2882
- return;
2883
- }
2884
- const ct = strapi.contentTypes[subject];
2885
- if (!isLocalizedContentType2(ct)) {
2886
- return;
2887
- }
2888
- if (locales2 === null) {
2889
- return;
2890
- }
2891
- condition.and({
2892
- locale: {
2893
- $in: locales2 || []
2894
2969
  }
2895
- });
2896
- };
2897
- const registerI18nPermissionsHandlers = () => {
2898
- const { engine } = strapi.service("admin::permission");
2899
- engine.hooks["before-register.permission"].register(willRegisterPermission);
2900
- };
2901
- const engineService = {
2902
- willRegisterPermission,
2903
- registerI18nPermissionsHandlers
2904
- };
2905
- const permissions = () => ({
2906
- actions: i18nActionsService,
2907
- sectionsBuilder: sectionsBuilderService,
2908
- engine: engineService
2909
- });
2910
- const sendDidInitializeEvent = async () => {
2911
- const { isLocalizedContentType: isLocalizedContentType2 } = getService("content-types");
2912
- const numberOfContentTypes = fp.reduce(
2913
- (sum, contentType) => isLocalizedContentType2(contentType) ? sum + 1 : sum,
2914
- 0
2915
- )(strapi.contentTypes);
2916
- await strapi.telemetry.send("didInitializeI18n", { groupProperties: { numberOfContentTypes } });
2917
- };
2918
- const sendDidUpdateI18nLocalesEvent = async () => {
2919
- const numberOfLocales = await getService("locales").count();
2920
- await strapi.telemetry.send("didUpdateI18nLocales", {
2921
- groupProperties: { numberOfLocales }
2922
- });
2923
- };
2924
- const metrics = () => ({
2925
- sendDidInitializeEvent,
2926
- sendDidUpdateI18nLocalesEvent
2927
- });
2928
- const syncNonLocalizedAttributes = async (sourceEntry, model) => {
2929
- const { copyNonLocalizedAttributes: copyNonLocalizedAttributes2 } = getService("content-types");
2930
- const nonLocalizedAttributes = copyNonLocalizedAttributes2(model, sourceEntry);
2931
- if (fp.isEmpty(nonLocalizedAttributes)) {
2932
- return;
2970
+ return { ...matchingLocale };
2933
2971
  }
2934
- const uid = model.uid;
2935
- const documentId = sourceEntry.documentId;
2936
- const locale2 = sourceEntry.locale;
2937
- const status = sourceEntry?.publishedAt ? "published" : "draft";
2938
- const localeEntriesToUpdate = await strapi.db.query(uid).findMany({
2939
- where: {
2940
- documentId,
2941
- publishedAt: status === "published" ? { $ne: null } : null,
2942
- locale: { $ne: locale2 }
2943
- },
2944
- select: ["locale", "id"]
2945
- });
2946
- const entryData = await strapi.documents(uid).omitComponentData(nonLocalizedAttributes);
2947
- await utils.async.map(localeEntriesToUpdate, async (entry) => {
2948
- const transformedData = await strapi.documents.utils.transformData(
2949
- fp.cloneDeep(nonLocalizedAttributes),
2950
- {
2951
- uid,
2952
- status,
2953
- locale: entry.locale,
2954
- allowMissingId: true
2955
- }
2956
- );
2957
- const componentData = await strapi.documents(uid).updateComponents(entry, transformedData);
2958
- await strapi.db.query(uid).update({
2959
- where: {
2960
- documentId,
2961
- publishedAt: status === "published" ? { $ne: null } : null,
2962
- locale: { $eq: entry.locale }
2963
- },
2964
- // The data we send to the update function is the entry data merged with
2965
- // the updated component data
2966
- data: Object.assign(fp.cloneDeep(entryData), componentData)
2967
- });
2968
- });
2972
+ return {
2973
+ code: "en",
2974
+ name: "English (en)"
2975
+ };
2969
2976
  };
2970
- const localizations = () => ({
2971
- syncNonLocalizedAttributes
2972
- });
2977
+ const DEFAULT_LOCALE = getInitLocale();
2973
2978
  const find = (params = {}) => strapi.db.query("plugin::i18n.locale").findMany({ where: params });
2974
2979
  const findById = (id) => strapi.db.query("plugin::i18n.locale").findOne({ where: { id } });
2975
2980
  const findByCode = (code) => strapi.db.query("plugin::i18n.locale").findOne({ where: { code } });
@@ -3037,91 +3042,6 @@ const getIsoLocales = () => isoLocales;
3037
3042
  const isoLocalesService = () => ({
3038
3043
  getIsoLocales
3039
3044
  });
3040
- const LOCALE_QUERY_FILTER = "locale";
3041
- const SINGLE_ENTRY_ACTIONS = ["findOne", "update", "delete"];
3042
- const BULK_ACTIONS = ["delete"];
3043
- const paramsContain = (key, params) => {
3044
- return fp.has(key, params.filters) || fp.isArray(params.filters) && params.filters.some((clause) => fp.has(key, clause)) || fp.isArray(fp.get("$and", params.filters)) && params.filters.$and.some((clause) => fp.has(key, clause));
3045
- };
3046
- const wrapParams = async (params = {}, ctx = {}) => {
3047
- const { action } = ctx;
3048
- if (fp.has(LOCALE_QUERY_FILTER, params)) {
3049
- if (params[LOCALE_QUERY_FILTER] === "all") {
3050
- return fp.omit(LOCALE_QUERY_FILTER, params);
3051
- }
3052
- return {
3053
- ...fp.omit(LOCALE_QUERY_FILTER, params),
3054
- filters: {
3055
- $and: [{ locale: params[LOCALE_QUERY_FILTER] }].concat(params.filters || [])
3056
- }
3057
- };
3058
- }
3059
- const entityDefinedById = paramsContain("id", params) && SINGLE_ENTRY_ACTIONS.includes(action);
3060
- const entitiesDefinedByIds = paramsContain("id.$in", params) && BULK_ACTIONS.includes(action);
3061
- if (entityDefinedById || entitiesDefinedByIds) {
3062
- return params;
3063
- }
3064
- const { getDefaultLocale: getDefaultLocale2 } = getService("locales");
3065
- return {
3066
- ...params,
3067
- filters: {
3068
- $and: [{ locale: await getDefaultLocale2() }].concat(params.filters || [])
3069
- }
3070
- };
3071
- };
3072
- const decorator = (service) => ({
3073
- /**
3074
- * Wraps result
3075
- * @param {object} result - result object of query
3076
- * @param {object} ctx - Query context
3077
- * @param {object} ctx.model - Model that is being used
3078
- */
3079
- async wrapResult(result = {}, ctx = {}) {
3080
- return service.wrapResult.call(this, result, ctx);
3081
- },
3082
- /**
3083
- * Wraps query options. In particular will add default locale to query params
3084
- * @param {object} params - Query options object (params, data, files, populate)
3085
- * @param {object} ctx - Query context
3086
- * @param {object} ctx.model - Model that is being used
3087
- */
3088
- async wrapParams(params = {}, ctx = {}) {
3089
- const wrappedParams = await service.wrapParams.call(this, params, ctx);
3090
- const model = strapi.getModel(ctx.uid);
3091
- const { isLocalizedContentType: isLocalizedContentType2 } = getService("content-types");
3092
- if (!isLocalizedContentType2(model)) {
3093
- return wrappedParams;
3094
- }
3095
- return wrapParams(wrappedParams, ctx);
3096
- },
3097
- /**
3098
- * Find an entry or several if fetching all locales
3099
- * @param {string} uid - Model uid
3100
- * @param {object} opts - Query options object (params, data, files, populate)
3101
- */
3102
- async findMany(uid, opts) {
3103
- const model = strapi.getModel(uid);
3104
- const { isLocalizedContentType: isLocalizedContentType2 } = getService("content-types");
3105
- if (!isLocalizedContentType2(model)) {
3106
- return service.findMany.call(this, uid, opts);
3107
- }
3108
- const { kind } = model;
3109
- if (kind === "singleType") {
3110
- if (opts[LOCALE_QUERY_FILTER] === "all") {
3111
- const wrappedParams = await this.wrapParams(opts, { uid, action: "findMany" });
3112
- const query = strapi.get("query-params").transform(uid, wrappedParams);
3113
- const entities = await strapi.db.query(uid).findMany(query);
3114
- return this.wrapResult(entities, { uid, action: "findMany" });
3115
- }
3116
- return service.findMany.call(this, uid, opts);
3117
- }
3118
- return service.findMany.call(this, uid, opts);
3119
- }
3120
- });
3121
- const entityServiceDecorator = () => ({
3122
- decorator,
3123
- wrapParams
3124
- });
3125
3045
  const {
3126
3046
  isRelationalAttribute,
3127
3047
  getVisibleAttributes,
@@ -3246,13 +3166,33 @@ const contentTypes = () => ({
3246
3166
  fillNonLocalizedAttributes,
3247
3167
  getNestedPopulateOfNonLocalizedAttributes
3248
3168
  });
3169
+ const LOCALIZATION_FIELDS = ["locale", "localizations"];
3170
+ const sanitize = ({ strapi: strapi2 }) => {
3171
+ const { isLocalizedContentType: isLocalizedContentType2 } = getService("content-types");
3172
+ const sanitizeLocalizationFields = fp.curry(
3173
+ (schema2, entity) => utils.traverseEntity(
3174
+ ({ key, schema: schema22 }, { remove }) => {
3175
+ const isLocalized = isLocalizedContentType2(schema22);
3176
+ const isLocalizationField = LOCALIZATION_FIELDS.includes(key);
3177
+ if (!isLocalized && isLocalizationField) {
3178
+ remove(key);
3179
+ }
3180
+ },
3181
+ { schema: schema2, getModel: strapi2.getModel.bind(strapi2) },
3182
+ entity
3183
+ )
3184
+ );
3185
+ return {
3186
+ sanitizeLocalizationFields
3187
+ };
3188
+ };
3249
3189
  const services = {
3250
3190
  permissions,
3251
3191
  metrics,
3252
3192
  localizations,
3253
3193
  locales,
3194
+ sanitize,
3254
3195
  "iso-locales": isoLocalesService,
3255
- "entity-service-decorator": entityServiceDecorator,
3256
3196
  "content-types": contentTypes
3257
3197
  };
3258
3198
  const admin = {