@strapi/i18n 0.0.0-experimental.0581774d9b26d449a40191b96482efca5664a181

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 (161) hide show
  1. package/LICENSE +37 -0
  2. package/README.md +17 -0
  3. package/dist/_chunks/SettingsPage-B-KzAqT3.mjs +554 -0
  4. package/dist/_chunks/SettingsPage-B-KzAqT3.mjs.map +1 -0
  5. package/dist/_chunks/SettingsPage-hyOi94O9.js +573 -0
  6. package/dist/_chunks/SettingsPage-hyOi94O9.js.map +1 -0
  7. package/dist/_chunks/de-BOhNX_-5.js +65 -0
  8. package/dist/_chunks/de-BOhNX_-5.js.map +1 -0
  9. package/dist/_chunks/de-D80IRBP9.mjs +65 -0
  10. package/dist/_chunks/de-D80IRBP9.mjs.map +1 -0
  11. package/dist/_chunks/dk-CJ6Zzz78.mjs +65 -0
  12. package/dist/_chunks/dk-CJ6Zzz78.mjs.map +1 -0
  13. package/dist/_chunks/dk-cjXm0p3m.js +65 -0
  14. package/dist/_chunks/dk-cjXm0p3m.js.map +1 -0
  15. package/dist/_chunks/en-BTyF7WVW.mjs +80 -0
  16. package/dist/_chunks/en-BTyF7WVW.mjs.map +1 -0
  17. package/dist/_chunks/en-UlC0jh2t.js +80 -0
  18. package/dist/_chunks/en-UlC0jh2t.js.map +1 -0
  19. package/dist/_chunks/es-V8WnPN7w.mjs +65 -0
  20. package/dist/_chunks/es-V8WnPN7w.mjs.map +1 -0
  21. package/dist/_chunks/es-hr9b_HLp.js +65 -0
  22. package/dist/_chunks/es-hr9b_HLp.js.map +1 -0
  23. package/dist/_chunks/fr-BFmBbE0H.js +65 -0
  24. package/dist/_chunks/fr-BFmBbE0H.js.map +1 -0
  25. package/dist/_chunks/fr-F94noFiV.mjs +65 -0
  26. package/dist/_chunks/fr-F94noFiV.mjs.map +1 -0
  27. package/dist/_chunks/index-BcYj5jo9.mjs +1589 -0
  28. package/dist/_chunks/index-BcYj5jo9.mjs.map +1 -0
  29. package/dist/_chunks/index-C8NzsAKp.js +1610 -0
  30. package/dist/_chunks/index-C8NzsAKp.js.map +1 -0
  31. package/dist/_chunks/ko-C40pNQ9b.js +64 -0
  32. package/dist/_chunks/ko-C40pNQ9b.js.map +1 -0
  33. package/dist/_chunks/ko-CF-P3Car.mjs +64 -0
  34. package/dist/_chunks/ko-CF-P3Car.mjs.map +1 -0
  35. package/dist/_chunks/pl-Dxr9RUmD.mjs +65 -0
  36. package/dist/_chunks/pl-Dxr9RUmD.mjs.map +1 -0
  37. package/dist/_chunks/pl-JtWBy-JQ.js +65 -0
  38. package/dist/_chunks/pl-JtWBy-JQ.js.map +1 -0
  39. package/dist/_chunks/ru-B-4sVwXN.mjs +67 -0
  40. package/dist/_chunks/ru-B-4sVwXN.mjs.map +1 -0
  41. package/dist/_chunks/ru-COSWt3Nu.js +67 -0
  42. package/dist/_chunks/ru-COSWt3Nu.js.map +1 -0
  43. package/dist/_chunks/tr-BVj1O5ch.js +65 -0
  44. package/dist/_chunks/tr-BVj1O5ch.js.map +1 -0
  45. package/dist/_chunks/tr-Ccu6Yj11.mjs +65 -0
  46. package/dist/_chunks/tr-Ccu6Yj11.mjs.map +1 -0
  47. package/dist/_chunks/zh-BIz395Ms.mjs +65 -0
  48. package/dist/_chunks/zh-BIz395Ms.mjs.map +1 -0
  49. package/dist/_chunks/zh-Hans-Bfo6_TCM.mjs +56 -0
  50. package/dist/_chunks/zh-Hans-Bfo6_TCM.mjs.map +1 -0
  51. package/dist/_chunks/zh-Hans-DIEm_EMC.js +56 -0
  52. package/dist/_chunks/zh-Hans-DIEm_EMC.js.map +1 -0
  53. package/dist/_chunks/zh-wkBPBkhc.js +65 -0
  54. package/dist/_chunks/zh-wkBPBkhc.js.map +1 -0
  55. package/dist/admin/index.js +6 -0
  56. package/dist/admin/index.js.map +1 -0
  57. package/dist/admin/index.mjs +7 -0
  58. package/dist/admin/index.mjs.map +1 -0
  59. package/dist/admin/src/components/BulkLocaleActionModal.d.ts +16 -0
  60. package/dist/admin/src/components/CMHeaderActions.d.ts +36 -0
  61. package/dist/admin/src/components/CMListViewModalsAdditionalInformation.d.ts +4 -0
  62. package/dist/admin/src/components/CheckboxConfirmation.d.ts +20 -0
  63. package/dist/admin/src/components/CreateLocale.d.ts +29 -0
  64. package/dist/admin/src/components/DeleteLocale.d.ts +5 -0
  65. package/dist/admin/src/components/EditLocale.d.ts +14 -0
  66. package/dist/admin/src/components/LocaleListCell.d.ts +9 -0
  67. package/dist/admin/src/components/LocalePicker.d.ts +2 -0
  68. package/dist/admin/src/components/LocaleTable.d.ts +11 -0
  69. package/dist/admin/src/constants.d.ts +22 -0
  70. package/dist/admin/src/contentManagerHooks/editView.d.ts +6 -0
  71. package/dist/admin/src/contentManagerHooks/listView.d.ts +22 -0
  72. package/dist/admin/src/contentReleasesHooks/releaseDetailsView.d.ts +40 -0
  73. package/dist/admin/src/hooks/useI18n.d.ts +16 -0
  74. package/dist/admin/src/index.d.ts +16 -0
  75. package/dist/admin/src/middlewares/extendCTBAttributeInitialData.d.ts +4 -0
  76. package/dist/admin/src/middlewares/extendCTBInitialData.d.ts +4 -0
  77. package/dist/admin/src/middlewares/rbac-middleware.d.ts +3 -0
  78. package/dist/admin/src/pages/SettingsPage.d.ts +3 -0
  79. package/dist/admin/src/pluginId.d.ts +1 -0
  80. package/dist/admin/src/services/api.d.ts +2 -0
  81. package/dist/admin/src/services/locales.d.ts +4 -0
  82. package/dist/admin/src/services/relations.d.ts +7 -0
  83. package/dist/admin/src/types.d.ts +9 -0
  84. package/dist/admin/src/utils/baseQuery.d.ts +5 -0
  85. package/dist/admin/src/utils/clean.d.ts +4 -0
  86. package/dist/admin/src/utils/fields.d.ts +7 -0
  87. package/dist/admin/src/utils/getTranslation.d.ts +2 -0
  88. package/dist/admin/src/utils/prefixPluginTranslations.d.ts +3 -0
  89. package/dist/admin/src/utils/schemas.d.ts +25 -0
  90. package/dist/admin/src/utils/strings.d.ts +2 -0
  91. package/dist/server/index.js +3462 -0
  92. package/dist/server/index.js.map +1 -0
  93. package/dist/server/index.mjs +3444 -0
  94. package/dist/server/index.mjs.map +1 -0
  95. package/dist/server/src/bootstrap.d.ts +3 -0
  96. package/dist/server/src/bootstrap.d.ts.map +1 -0
  97. package/dist/server/src/constants/index.d.ts +15 -0
  98. package/dist/server/src/constants/index.d.ts.map +1 -0
  99. package/dist/server/src/content-types/index.d.ts +37 -0
  100. package/dist/server/src/content-types/index.d.ts.map +1 -0
  101. package/dist/server/src/content-types/locale/index.d.ts +35 -0
  102. package/dist/server/src/content-types/locale/index.d.ts.map +1 -0
  103. package/dist/server/src/controllers/content-types.d.ts +6 -0
  104. package/dist/server/src/controllers/content-types.d.ts.map +1 -0
  105. package/dist/server/src/controllers/index.d.ts +10 -0
  106. package/dist/server/src/controllers/index.d.ts.map +1 -0
  107. package/dist/server/src/controllers/iso-locales.d.ts +4 -0
  108. package/dist/server/src/controllers/iso-locales.d.ts.map +1 -0
  109. package/dist/server/src/controllers/locales.d.ts +4 -0
  110. package/dist/server/src/controllers/locales.d.ts.map +1 -0
  111. package/dist/server/src/controllers/validate-locale-creation.d.ts +4 -0
  112. package/dist/server/src/controllers/validate-locale-creation.d.ts.map +1 -0
  113. package/dist/server/src/domain/locale.d.ts +11 -0
  114. package/dist/server/src/domain/locale.d.ts.map +1 -0
  115. package/dist/server/src/graphql.d.ts +8 -0
  116. package/dist/server/src/graphql.d.ts.map +1 -0
  117. package/dist/server/src/index.d.ts +156 -0
  118. package/dist/server/src/index.d.ts.map +1 -0
  119. package/dist/server/src/register.d.ts +6 -0
  120. package/dist/server/src/register.d.ts.map +1 -0
  121. package/dist/server/src/routes/admin.d.ts +18 -0
  122. package/dist/server/src/routes/admin.d.ts.map +1 -0
  123. package/dist/server/src/routes/content-api.d.ts +10 -0
  124. package/dist/server/src/routes/content-api.d.ts.map +1 -0
  125. package/dist/server/src/routes/index.d.ts +28 -0
  126. package/dist/server/src/routes/index.d.ts.map +1 -0
  127. package/dist/server/src/services/content-types.d.ts +13 -0
  128. package/dist/server/src/services/content-types.d.ts.map +1 -0
  129. package/dist/server/src/services/index.d.ts +81 -0
  130. package/dist/server/src/services/index.d.ts.map +1 -0
  131. package/dist/server/src/services/iso-locales.d.ts +10 -0
  132. package/dist/server/src/services/iso-locales.d.ts.map +1 -0
  133. package/dist/server/src/services/locales.d.ts +17 -0
  134. package/dist/server/src/services/locales.d.ts.map +1 -0
  135. package/dist/server/src/services/localizations.d.ts +8 -0
  136. package/dist/server/src/services/localizations.d.ts.map +1 -0
  137. package/dist/server/src/services/metrics.d.ts +8 -0
  138. package/dist/server/src/services/metrics.d.ts.map +1 -0
  139. package/dist/server/src/services/permissions/actions.d.ts +28 -0
  140. package/dist/server/src/services/permissions/actions.d.ts.map +1 -0
  141. package/dist/server/src/services/permissions/conditions.d.ts +15 -0
  142. package/dist/server/src/services/permissions/conditions.d.ts.map +1 -0
  143. package/dist/server/src/services/permissions/engine.d.ts +6 -0
  144. package/dist/server/src/services/permissions/engine.d.ts.map +1 -0
  145. package/dist/server/src/services/permissions/sections-builder.d.ts +6 -0
  146. package/dist/server/src/services/permissions/sections-builder.d.ts.map +1 -0
  147. package/dist/server/src/services/permissions.d.ts +40 -0
  148. package/dist/server/src/services/permissions.d.ts.map +1 -0
  149. package/dist/server/src/services/sanitize/index.d.ts +11 -0
  150. package/dist/server/src/services/sanitize/index.d.ts.map +1 -0
  151. package/dist/server/src/utils/index.d.ts +43 -0
  152. package/dist/server/src/utils/index.d.ts.map +1 -0
  153. package/dist/server/src/validation/content-types.d.ts +3 -0
  154. package/dist/server/src/validation/content-types.d.ts.map +1 -0
  155. package/dist/server/src/validation/locales.d.ts +12 -0
  156. package/dist/server/src/validation/locales.d.ts.map +1 -0
  157. package/dist/shared/contracts/content-manager.d.ts +46 -0
  158. package/dist/shared/contracts/iso-locales.d.ts +21 -0
  159. package/dist/shared/contracts/locales.d.ts +77 -0
  160. package/dist/shared/contracts/shared.d.ts +6 -0
  161. package/package.json +99 -0
@@ -0,0 +1,3444 @@
1
+ import _ from "lodash";
2
+ import { get, identity, propEq, isArray, prop, getOr, isEmpty, reduce, cloneDeep, isNil, pipe, pick, has, curry, map, flatten, uniq } from "lodash/fp";
3
+ import * as utils from "@strapi/utils";
4
+ import { errors, async, contentTypes as contentTypes$2, traverseEntity, yup, validateYupSchema } from "@strapi/utils";
5
+ const getCoreStore = () => {
6
+ return strapi.store({ type: "plugin", name: "i18n" });
7
+ };
8
+ const getService = (name) => {
9
+ return strapi.plugin("i18n").service(name);
10
+ };
11
+ const registerModelsHooks = () => {
12
+ strapi.db.lifecycles.subscribe({
13
+ models: ["plugin::i18n.locale"],
14
+ async afterCreate() {
15
+ await getService("permissions").actions.syncSuperAdminPermissionsWithLocales();
16
+ },
17
+ async afterDelete() {
18
+ await getService("permissions").actions.syncSuperAdminPermissionsWithLocales();
19
+ }
20
+ });
21
+ strapi.documents.use(async (context, next) => {
22
+ const schema2 = context.contentType;
23
+ if (!["create", "update", "discardDraft", "publish"].includes(context.action)) {
24
+ return next();
25
+ }
26
+ if (!getService("content-types").isLocalizedContentType(schema2)) {
27
+ return next();
28
+ }
29
+ const { getNestedPopulateOfNonLocalizedAttributes: getNestedPopulateOfNonLocalizedAttributes2 } = getService("content-types");
30
+ const attributesToPopulate = getNestedPopulateOfNonLocalizedAttributes2(schema2.uid);
31
+ const result = await next();
32
+ let resultID;
33
+ if (Array.isArray(result?.entries) && result.entries[0]?.id) {
34
+ resultID = result.entries[0].id;
35
+ } else if (result?.id) {
36
+ resultID = result.id;
37
+ } else {
38
+ return result;
39
+ }
40
+ if (attributesToPopulate.length > 0) {
41
+ const populatedResult = await strapi.db.query(schema2.uid).findOne({ where: { id: resultID }, populate: attributesToPopulate });
42
+ await getService("localizations").syncNonLocalizedAttributes(populatedResult, schema2);
43
+ }
44
+ return result;
45
+ });
46
+ };
47
+ const bootstrap = async () => {
48
+ const { sendDidInitializeEvent: sendDidInitializeEvent2 } = getService("metrics");
49
+ const { initDefaultLocale: initDefaultLocale2 } = getService("locales");
50
+ const { sectionsBuilder, actions: actions2, engine } = getService("permissions");
51
+ await initDefaultLocale2();
52
+ sectionsBuilder.registerLocalesPropertyHandler();
53
+ await actions2.registerI18nActions();
54
+ actions2.registerI18nActionsHooks();
55
+ actions2.updateActionsProperties();
56
+ engine.registerI18nPermissionsHandlers();
57
+ registerModelsHooks();
58
+ sendDidInitializeEvent2();
59
+ };
60
+ const { ApplicationError: ApplicationError$3 } = errors;
61
+ const validateLocaleCreation = async (ctx, next) => {
62
+ const { model } = ctx.params;
63
+ const { query } = ctx.request;
64
+ if (!ctx.request.body) {
65
+ ctx.request.body = {};
66
+ }
67
+ const body = ctx.request.body;
68
+ const { getValidLocale: getValidLocale2, isLocalizedContentType: isLocalizedContentType2 } = getService("content-types");
69
+ const modelDef = strapi.getModel(model);
70
+ if (!isLocalizedContentType2(modelDef)) {
71
+ return next();
72
+ }
73
+ const locale2 = get("locale", query) || get("locale", body) || void 0;
74
+ ctx.request.query = {};
75
+ let entityLocale;
76
+ try {
77
+ entityLocale = await getValidLocale2(locale2);
78
+ } catch (e) {
79
+ throw new ApplicationError$3("This locale doesn't exist");
80
+ }
81
+ body.locale = entityLocale;
82
+ if (modelDef.kind === "singleType") {
83
+ const entity = await strapi.entityService.findMany(modelDef.uid, {
84
+ locale: entityLocale
85
+ });
86
+ ctx.request.query.locale = body.locale;
87
+ if (entity) {
88
+ return next();
89
+ }
90
+ }
91
+ return next();
92
+ };
93
+ const { ValidationError } = errors;
94
+ const LOCALE_SCALAR_TYPENAME = "I18NLocaleCode";
95
+ const LOCALE_ARG_PLUGIN_NAME = "I18NLocaleArg";
96
+ const graphqlProvider = ({ strapi: strapi2 }) => ({
97
+ register() {
98
+ const { service: getGraphQLService } = strapi2.plugin("graphql");
99
+ const { service: getI18NService } = strapi2.plugin("i18n");
100
+ const { isLocalizedContentType: isLocalizedContentType2 } = getI18NService("content-types");
101
+ const extensionService = getGraphQLService("extension");
102
+ extensionService.shadowCRUD("plugin::i18n.locale").disableMutations();
103
+ Object.entries(strapi2.contentTypes).forEach(([uid, ct]) => {
104
+ if (isLocalizedContentType2(ct)) {
105
+ extensionService.shadowCRUD(uid).field("locale").disableInput();
106
+ extensionService.shadowCRUD(uid).field("localizations").disableInput();
107
+ }
108
+ });
109
+ extensionService.use(({ nexus, typeRegistry }) => {
110
+ const i18nLocaleArgPlugin = getI18nLocaleArgPlugin({ nexus, typeRegistry });
111
+ const i18nLocaleScalar = getLocaleScalar({ nexus });
112
+ return {
113
+ plugins: [i18nLocaleArgPlugin],
114
+ types: [i18nLocaleScalar],
115
+ resolversConfig: {
116
+ // Modify the default scope associated to find and findOne locale queries to match the actual action name
117
+ "Query.i18NLocale": { auth: { scope: "plugin::i18n.locales.listLocales" } },
118
+ "Query.i18NLocales": { auth: { scope: "plugin::i18n.locales.listLocales" } }
119
+ }
120
+ };
121
+ });
122
+ }
123
+ });
124
+ const getLocaleScalar = ({ nexus }) => {
125
+ const { service: getI18NService } = strapi.plugin("i18n");
126
+ const locales2 = getI18NService("iso-locales").getIsoLocales();
127
+ return nexus.scalarType({
128
+ name: LOCALE_SCALAR_TYPENAME,
129
+ description: "A string used to identify an i18n locale",
130
+ serialize: identity,
131
+ parseValue: identity,
132
+ parseLiteral(ast) {
133
+ if (ast.kind !== "StringValue") {
134
+ throw new ValidationError("Locale cannot represent non string type");
135
+ }
136
+ const isValidLocale = ast.value === "*" || locales2.find(propEq("code", ast.value));
137
+ if (!isValidLocale) {
138
+ throw new ValidationError("Unknown locale supplied");
139
+ }
140
+ return ast.value;
141
+ }
142
+ });
143
+ };
144
+ const getI18nLocaleArgPlugin = ({ nexus, typeRegistry }) => {
145
+ const { service: getI18NService } = strapi.plugin("i18n");
146
+ const { isLocalizedContentType: isLocalizedContentType2 } = getI18NService("content-types");
147
+ return nexus.plugin({
148
+ name: LOCALE_ARG_PLUGIN_NAME,
149
+ onAddOutputField(config) {
150
+ const { parentType } = config;
151
+ if (parentType !== "Query" && parentType !== "Mutation") {
152
+ return;
153
+ }
154
+ let contentType;
155
+ if (config?.extensions?.strapi?.contentType) {
156
+ contentType = config.extensions.strapi.contentType;
157
+ } else {
158
+ const registryType = typeRegistry.get(config.type);
159
+ if (!registryType) {
160
+ return;
161
+ }
162
+ contentType = registryType.config.contentType;
163
+ }
164
+ if (!isLocalizedContentType2(contentType)) {
165
+ return;
166
+ }
167
+ if (!config.args) {
168
+ config.args = {};
169
+ }
170
+ config.args.locale = nexus.arg({
171
+ type: LOCALE_SCALAR_TYPENAME,
172
+ description: "The locale to use for the query"
173
+ });
174
+ }
175
+ });
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
+ });
523
+ const isoLocales = [
524
+ {
525
+ code: "af",
526
+ name: "Afrikaans (af)"
527
+ },
528
+ {
529
+ code: "af-NA",
530
+ name: "Afrikaans (Namibia) (af-NA)"
531
+ },
532
+ {
533
+ code: "af-ZA",
534
+ name: "Afrikaans (South Africa) (af-ZA)"
535
+ },
536
+ {
537
+ code: "agq",
538
+ name: "Aghem (agq)"
539
+ },
540
+ {
541
+ code: "agq-CM",
542
+ name: "Aghem (Cameroon) (agq-CM)"
543
+ },
544
+ {
545
+ code: "ak",
546
+ name: "Akan (ak)"
547
+ },
548
+ {
549
+ code: "ak-GH",
550
+ name: "Akan (Ghana) (ak-GH)"
551
+ },
552
+ {
553
+ code: "sq",
554
+ name: "Albanian (sq)"
555
+ },
556
+ {
557
+ code: "sq-AL",
558
+ name: "Albanian (Albania) (sq-AL)"
559
+ },
560
+ {
561
+ code: "am",
562
+ name: "Amharic (am)"
563
+ },
564
+ {
565
+ code: "am-ET",
566
+ name: "Amharic (Ethiopia) (am-ET)"
567
+ },
568
+ {
569
+ code: "aig",
570
+ name: "Antigua and Barbuda Creole English"
571
+ },
572
+ {
573
+ code: "ar",
574
+ name: "Arabic (ar)"
575
+ },
576
+ {
577
+ code: "ar-DZ",
578
+ name: "Arabic (Algeria) (ar-DZ)"
579
+ },
580
+ {
581
+ code: "ar-BH",
582
+ name: "Arabic (Bahrain) (ar-BH)"
583
+ },
584
+ {
585
+ code: "ar-EG",
586
+ name: "Arabic (Egypt) (ar-EG)"
587
+ },
588
+ {
589
+ code: "ar-IQ",
590
+ name: "Arabic (Iraq) (ar-IQ)"
591
+ },
592
+ {
593
+ code: "ar-JO",
594
+ name: "Arabic (Jordan) (ar-JO)"
595
+ },
596
+ {
597
+ code: "ar-KW",
598
+ name: "Arabic (Kuwait) (ar-KW)"
599
+ },
600
+ {
601
+ code: "ar-LB",
602
+ name: "Arabic (Lebanon) (ar-LB)"
603
+ },
604
+ {
605
+ code: "ar-LY",
606
+ name: "Arabic (Libya) (ar-LY)"
607
+ },
608
+ {
609
+ code: "ar-MA",
610
+ name: "Arabic (Morocco) (ar-MA)"
611
+ },
612
+ {
613
+ code: "ar-OM",
614
+ name: "Arabic (Oman) (ar-OM)"
615
+ },
616
+ {
617
+ code: "ar-QA",
618
+ name: "Arabic (Qatar) (ar-QA)"
619
+ },
620
+ {
621
+ code: "ar-SA",
622
+ name: "Arabic (Saudi Arabia) (ar-SA)"
623
+ },
624
+ {
625
+ code: "ar-SD",
626
+ name: "Arabic (Sudan) (ar-SD)"
627
+ },
628
+ {
629
+ code: "ar-SY",
630
+ name: "Arabic (Syria) (ar-SY)"
631
+ },
632
+ {
633
+ code: "ar-TN",
634
+ name: "Arabic (Tunisia) (ar-TN)"
635
+ },
636
+ {
637
+ code: "ar-AE",
638
+ name: "Arabic (United Arab Emirates) (ar-AE)"
639
+ },
640
+ {
641
+ code: "ar-001",
642
+ name: "Arabic (World) (ar-001)"
643
+ },
644
+ {
645
+ code: "ar-YE",
646
+ name: "Arabic (Yemen) (ar-YE)"
647
+ },
648
+ {
649
+ code: "hy",
650
+ name: "Armenian (hy)"
651
+ },
652
+ {
653
+ code: "hy-AM",
654
+ name: "Armenian (Armenia) (hy-AM)"
655
+ },
656
+ {
657
+ code: "as",
658
+ name: "Assamese (as)"
659
+ },
660
+ {
661
+ code: "as-IN",
662
+ name: "Assamese (India) (as-IN)"
663
+ },
664
+ {
665
+ code: "ast",
666
+ name: "Asturian (ast)"
667
+ },
668
+ {
669
+ code: "ast-ES",
670
+ name: "Asturian (Spain) (ast-ES)"
671
+ },
672
+ {
673
+ code: "asa",
674
+ name: "Asu (asa)"
675
+ },
676
+ {
677
+ code: "asa-TZ",
678
+ name: "Asu (Tanzania) (asa-TZ)"
679
+ },
680
+ {
681
+ code: "az",
682
+ name: "Azerbaijani (az)"
683
+ },
684
+ {
685
+ code: "az-Cyrl",
686
+ name: "Azerbaijani (Cyrillic) (az-Cyrl)"
687
+ },
688
+ {
689
+ code: "az-Cyrl-AZ",
690
+ name: "Azerbaijani (Cyrillic, Azerbaijan) (az-Cyrl-AZ)"
691
+ },
692
+ {
693
+ code: "az-Latn",
694
+ name: "Azerbaijani (Latin) (az-Latn)"
695
+ },
696
+ {
697
+ code: "az-Latn-AZ",
698
+ name: "Azerbaijani (Latin, Azerbaijan) (az-Latn-AZ)"
699
+ },
700
+ {
701
+ code: "ksf",
702
+ name: "Bafia (ksf)"
703
+ },
704
+ {
705
+ code: "ksf-CM",
706
+ name: "Bafia (Cameroon) (ksf-CM)"
707
+ },
708
+ {
709
+ code: "bah",
710
+ name: "Bahamas Creole English"
711
+ },
712
+ {
713
+ code: "bm",
714
+ name: "Bambara (bm)"
715
+ },
716
+ {
717
+ code: "bm-ML",
718
+ name: "Bambara (Mali) (bm-ML)"
719
+ },
720
+ {
721
+ code: "bas",
722
+ name: "Basaa (bas)"
723
+ },
724
+ {
725
+ code: "bas-CM",
726
+ name: "Basaa (Cameroon) (bas-CM)"
727
+ },
728
+ {
729
+ code: "eu",
730
+ name: "Basque (eu)"
731
+ },
732
+ {
733
+ code: "eu-ES",
734
+ name: "Basque (Spain) (eu-ES)"
735
+ },
736
+ {
737
+ code: "be",
738
+ name: "Belarusian (be)"
739
+ },
740
+ {
741
+ code: "be-BY",
742
+ name: "Belarusian (Belarus) (be-BY)"
743
+ },
744
+ {
745
+ code: "bem",
746
+ name: "Bemba (bem)"
747
+ },
748
+ {
749
+ code: "bem-ZM",
750
+ name: "Bemba (Zambia) (bem-ZM)"
751
+ },
752
+ {
753
+ code: "bez",
754
+ name: "Bena (bez)"
755
+ },
756
+ {
757
+ code: "bez-TZ",
758
+ name: "Bena (Tanzania) (bez-TZ)"
759
+ },
760
+ {
761
+ code: "bn",
762
+ name: "Bengali (bn)"
763
+ },
764
+ {
765
+ code: "bn-BD",
766
+ name: "Bengali (Bangladesh) (bn-BD)"
767
+ },
768
+ {
769
+ code: "bn-IN",
770
+ name: "Bengali (India) (bn-IN)"
771
+ },
772
+ {
773
+ code: "brx",
774
+ name: "Bodo (brx)"
775
+ },
776
+ {
777
+ code: "brx-IN",
778
+ name: "Bodo (India) (brx-IN)"
779
+ },
780
+ {
781
+ code: "bs",
782
+ name: "Bosnian (bs)"
783
+ },
784
+ {
785
+ code: "bs-BA",
786
+ name: "Bosnian (Bosnia and Herzegovina) (bs-BA)"
787
+ },
788
+ {
789
+ code: "br",
790
+ name: "Breton (br)"
791
+ },
792
+ {
793
+ code: "br-FR",
794
+ name: "Breton (France) (br-FR)"
795
+ },
796
+ {
797
+ code: "bg",
798
+ name: "Bulgarian (bg)"
799
+ },
800
+ {
801
+ code: "bg-BG",
802
+ name: "Bulgarian (Bulgaria) (bg-BG)"
803
+ },
804
+ {
805
+ code: "my",
806
+ name: "Burmese (my)"
807
+ },
808
+ {
809
+ code: "my-MM",
810
+ name: "Burmese (Myanmar [Burma]) (my-MM)"
811
+ },
812
+ {
813
+ code: "ca",
814
+ name: "Catalan (ca)"
815
+ },
816
+ {
817
+ code: "ca-ES",
818
+ name: "Catalan (Spain) (ca-ES)"
819
+ },
820
+ {
821
+ code: "ckb",
822
+ name: "Central Kurdish (ckb)"
823
+ },
824
+ {
825
+ code: "kmr",
826
+ name: "Northern Kurdish (kmr)"
827
+ },
828
+ {
829
+ code: "sdh",
830
+ name: "Southern Kurdish (sdh)"
831
+ },
832
+ {
833
+ code: "tzm",
834
+ name: "Central Morocco Tamazight (tzm)"
835
+ },
836
+ {
837
+ code: "tzm-Latn",
838
+ name: "Central Morocco Tamazight (Latin) (tzm-Latn)"
839
+ },
840
+ {
841
+ code: "tzm-Latn-MA",
842
+ name: "Central Morocco Tamazight (Latin, Morocco) (tzm-Latn-MA) "
843
+ },
844
+ {
845
+ code: "chr",
846
+ name: "Cherokee (chr)"
847
+ },
848
+ {
849
+ code: "chr-US",
850
+ name: "Cherokee (United States) (chr-US)"
851
+ },
852
+ {
853
+ code: "cgg",
854
+ name: "Chiga (cgg)"
855
+ },
856
+ {
857
+ code: "cgg-UG",
858
+ name: "Chiga (Uganda) (cgg-UG)"
859
+ },
860
+ {
861
+ code: "zh",
862
+ name: "Chinese (zh)"
863
+ },
864
+ {
865
+ code: "zh-Hans",
866
+ name: "Chinese (Simplified) (zh-Hans)"
867
+ },
868
+ {
869
+ code: "zh-CN",
870
+ name: "Chinese (Simplified, China) (zh-CN)"
871
+ },
872
+ {
873
+ code: "zh-Hans-CN",
874
+ name: "Chinese (Simplified, China) (zh-Hans-CN)"
875
+ },
876
+ {
877
+ code: "zh-Hans-HK",
878
+ name: "Chinese (Simplified, Hong Kong SAR China) (zh-Hans-HK)"
879
+ },
880
+ {
881
+ code: "zh-Hans-MO",
882
+ name: "Chinese (Simplified, Macau SAR China) (zh-Hans-MO) "
883
+ },
884
+ {
885
+ code: "zh-Hans-SG",
886
+ name: "Chinese (Simplified, Singapore) (zh-Hans-SG)"
887
+ },
888
+ {
889
+ code: "zh-Hant",
890
+ name: "Chinese (Traditional) (zh-Hant)"
891
+ },
892
+ {
893
+ code: "zh-Hant-HK",
894
+ name: "Chinese (Traditional, Hong Kong SAR China) (zh-Hant-HK) "
895
+ },
896
+ {
897
+ code: "zh-Hant-MO",
898
+ name: "Chinese (Traditional, Macau SAR China) (zh-Hant-MO) "
899
+ },
900
+ {
901
+ code: "zh-Hant-TW",
902
+ name: "Chinese (Traditional, Taiwan) (zh-Hant-TW)"
903
+ },
904
+ {
905
+ code: "swc",
906
+ name: "Congo Swahili (swc)"
907
+ },
908
+ {
909
+ code: "swc-CD",
910
+ name: "Congo Swahili (Congo - Kinshasa) (swc-CD)"
911
+ },
912
+ {
913
+ code: "kw",
914
+ name: "Cornish (kw)"
915
+ },
916
+ {
917
+ code: "kw-GB",
918
+ name: "Cornish (United Kingdom) (kw-GB)"
919
+ },
920
+ {
921
+ code: "hr",
922
+ name: "Croatian (hr)"
923
+ },
924
+ {
925
+ code: "hr-HR",
926
+ name: "Croatian (Croatia) (hr-HR)"
927
+ },
928
+ {
929
+ code: "cs",
930
+ name: "Czech (cs)"
931
+ },
932
+ {
933
+ code: "cs-CZ",
934
+ name: "Czech (Czech Republic) (cs-CZ)"
935
+ },
936
+ {
937
+ code: "da",
938
+ name: "Danish (da)"
939
+ },
940
+ {
941
+ code: "da-DK",
942
+ name: "Danish (Denmark) (da-DK)"
943
+ },
944
+ {
945
+ code: "dua",
946
+ name: "Duala (dua)"
947
+ },
948
+ {
949
+ code: "dua-CM",
950
+ name: "Duala (Cameroon) (dua-CM)"
951
+ },
952
+ {
953
+ code: "dv",
954
+ name: "Dhivehi (Maldives)"
955
+ },
956
+ {
957
+ code: "nl",
958
+ name: "Dutch (nl)"
959
+ },
960
+ {
961
+ code: "nl-AW",
962
+ name: "Dutch (Aruba) (nl-AW)"
963
+ },
964
+ {
965
+ code: "nl-BE",
966
+ name: "Dutch (Belgium) (nl-BE)"
967
+ },
968
+ {
969
+ code: "nl-CW",
970
+ name: "Dutch (Curaçao) (nl-CW)"
971
+ },
972
+ {
973
+ code: "nl-NL",
974
+ name: "Dutch (Netherlands) (nl-NL)"
975
+ },
976
+ {
977
+ code: "nl-SX",
978
+ name: "Dutch (Sint Maarten) (nl-SX)"
979
+ },
980
+ {
981
+ code: "ebu",
982
+ name: "Embu (ebu)"
983
+ },
984
+ {
985
+ code: "ebu-KE",
986
+ name: "Embu (Kenya) (ebu-KE)"
987
+ },
988
+ {
989
+ code: "en",
990
+ name: "English (en)"
991
+ },
992
+ {
993
+ code: "en-AI",
994
+ name: "English (Anguilla) (en-AI)"
995
+ },
996
+ {
997
+ code: "en-AS",
998
+ name: "English (American Samoa) (en-AS)"
999
+ },
1000
+ {
1001
+ code: "en-AU",
1002
+ name: "English (Australia) (en-AU)"
1003
+ },
1004
+ {
1005
+ code: "en-AT",
1006
+ name: "English (Austria) (en-AT)"
1007
+ },
1008
+ {
1009
+ code: "en-BB",
1010
+ name: "English (Barbados) (en-BB)"
1011
+ },
1012
+ {
1013
+ code: "en-BE",
1014
+ name: "English (Belgium) (en-BE)"
1015
+ },
1016
+ {
1017
+ code: "en-BZ",
1018
+ name: "English (Belize) (en-BZ)"
1019
+ },
1020
+ {
1021
+ code: "en-BM",
1022
+ name: "English (Bermuda) (en-BM)"
1023
+ },
1024
+ {
1025
+ code: "en-BW",
1026
+ name: "English (Botswana) (en-BW)"
1027
+ },
1028
+ {
1029
+ code: "en-IO",
1030
+ name: "English (British Indian Ocean Territory) (en-IO)"
1031
+ },
1032
+ {
1033
+ code: "en-BI",
1034
+ name: "English (Burundi) (en-BI)"
1035
+ },
1036
+ {
1037
+ code: "en-CM",
1038
+ name: "English (Cameroon) (en-CM)"
1039
+ },
1040
+ {
1041
+ code: "en-CA",
1042
+ name: "English (Canada) (en-CA)"
1043
+ },
1044
+ {
1045
+ code: "en-KY",
1046
+ name: "English (Cayman Islands) (en-KY)"
1047
+ },
1048
+ {
1049
+ code: "en-CX",
1050
+ name: "English (Christmas Island) (en-CX)"
1051
+ },
1052
+ {
1053
+ code: "en-CC",
1054
+ name: "English (Cocos [Keeling] Islands) (en-CC)"
1055
+ },
1056
+ {
1057
+ code: "en-CK",
1058
+ name: "English (Cook Islands) (en-CK)"
1059
+ },
1060
+ {
1061
+ code: "en-CY",
1062
+ name: "English (Cyprus) (en-CY)"
1063
+ },
1064
+ {
1065
+ code: "en-DK",
1066
+ name: "English (Denmark) (en-DK)"
1067
+ },
1068
+ {
1069
+ code: "en-DG",
1070
+ name: "English (Diego Garcia) (en-DG)"
1071
+ },
1072
+ {
1073
+ code: "en-DM",
1074
+ name: "English (Dominica) (en-DM)"
1075
+ },
1076
+ {
1077
+ code: "en-EG",
1078
+ name: "English (Egypt) (en-EG)"
1079
+ },
1080
+ {
1081
+ code: "en-ER",
1082
+ name: "English (Eritrea) (en-ER)"
1083
+ },
1084
+ {
1085
+ code: "en-EU",
1086
+ name: "English (Europe) (en-EU)"
1087
+ },
1088
+ {
1089
+ code: "en-FK",
1090
+ name: "English (Falkland Islands) (en-FK)"
1091
+ },
1092
+ {
1093
+ code: "en-FJ",
1094
+ name: "English (Fiji) (en-FJ)"
1095
+ },
1096
+ {
1097
+ code: "en-FI",
1098
+ name: "English (Finland) (en-FI)"
1099
+ },
1100
+ {
1101
+ code: "en-GM",
1102
+ name: "English (Gambia) (en-GM)"
1103
+ },
1104
+ {
1105
+ code: "en-DE",
1106
+ name: "English (Germany) (en-DE)"
1107
+ },
1108
+ {
1109
+ code: "en-GH",
1110
+ name: "English (Ghana) (en-GH)"
1111
+ },
1112
+ {
1113
+ code: "en-GI",
1114
+ name: "English (Gibraltar) (en-GI)"
1115
+ },
1116
+ {
1117
+ code: "en-GD",
1118
+ name: "English (Grenada) (en-GD)"
1119
+ },
1120
+ {
1121
+ code: "en-GU",
1122
+ name: "English (Guam) (en-GU)"
1123
+ },
1124
+ {
1125
+ code: "en-GG",
1126
+ name: "English (Guernsey) (en-GG)"
1127
+ },
1128
+ {
1129
+ code: "en-GY",
1130
+ name: "English (Guyana) (en-GY)"
1131
+ },
1132
+ {
1133
+ code: "en-HK",
1134
+ name: "English (Hong Kong SAR China) (en-HK)"
1135
+ },
1136
+ {
1137
+ code: "en-IN",
1138
+ name: "English (India) (en-IN)"
1139
+ },
1140
+ {
1141
+ code: "en-IE",
1142
+ name: "English (Ireland) (en-IE)"
1143
+ },
1144
+ {
1145
+ code: "en-IM",
1146
+ name: "English (Isle of Man) (en-IM)"
1147
+ },
1148
+ {
1149
+ code: "en-IL",
1150
+ name: "English (Israel) (en-IL)"
1151
+ },
1152
+ {
1153
+ code: "en-JM",
1154
+ name: "English (Jamaica) (en-JM)"
1155
+ },
1156
+ {
1157
+ code: "en-JE",
1158
+ name: "English (Jersey) (en-JE)"
1159
+ },
1160
+ {
1161
+ code: "en-KE",
1162
+ name: "English (Kenya) (en-KE)"
1163
+ },
1164
+ {
1165
+ code: "en-KI",
1166
+ name: "English (Kiribati) (en-KI)"
1167
+ },
1168
+ {
1169
+ code: "en-KW",
1170
+ name: "English (Kuwait) (en-KW)"
1171
+ },
1172
+ {
1173
+ code: "en-LS",
1174
+ name: "English (Lesotho) (en-LS)"
1175
+ },
1176
+ {
1177
+ code: "en-MO",
1178
+ name: "English (Macao SAR China) (en-MO)"
1179
+ },
1180
+ {
1181
+ code: "en-MG",
1182
+ name: "English (Madagascar) (en-MG)"
1183
+ },
1184
+ {
1185
+ code: "en-MW",
1186
+ name: "English (Malawi) (en-MW)"
1187
+ },
1188
+ {
1189
+ code: "en-MY",
1190
+ name: "English (Malaysia) (en-MY)"
1191
+ },
1192
+ {
1193
+ code: "en-MT",
1194
+ name: "English (Malta) (en-MT)"
1195
+ },
1196
+ {
1197
+ code: "en-MH",
1198
+ name: "English (Marshall Islands) (en-MH)"
1199
+ },
1200
+ {
1201
+ code: "en-MU",
1202
+ name: "English (Mauritius) (en-MU)"
1203
+ },
1204
+ {
1205
+ code: "en-FM",
1206
+ name: "English (Micronesia) (en-FM)"
1207
+ },
1208
+ {
1209
+ code: "en-MS",
1210
+ name: "English (Montserrat) (en-MS)"
1211
+ },
1212
+ {
1213
+ code: "en-NA",
1214
+ name: "English (Namibia) (en-NA)"
1215
+ },
1216
+ {
1217
+ code: "en-NR",
1218
+ name: "English (Nauru) (en-NR)"
1219
+ },
1220
+ {
1221
+ code: "en-NL",
1222
+ name: "English (Netherlands) (en-NL)"
1223
+ },
1224
+ {
1225
+ code: "en-NZ",
1226
+ name: "English (New Zealand) (en-NZ)"
1227
+ },
1228
+ {
1229
+ code: "en-NG",
1230
+ name: "English (Nigeria) (en-NG)"
1231
+ },
1232
+ {
1233
+ code: "en-NU",
1234
+ name: "English (Niue) (en-NU)"
1235
+ },
1236
+ {
1237
+ code: "en-NF",
1238
+ name: "English (Norfolk Island) (en-NF)"
1239
+ },
1240
+ {
1241
+ code: "en-MP",
1242
+ name: "English (Northern Mariana Islands) (en-MP)"
1243
+ },
1244
+ {
1245
+ code: "en-NO",
1246
+ name: "English (Norway) (en-NO)"
1247
+ },
1248
+ {
1249
+ code: "en-PA",
1250
+ name: "English (Panama) (en-PA)"
1251
+ },
1252
+ {
1253
+ code: "en-PK",
1254
+ name: "English (Pakistan) (en-PK)"
1255
+ },
1256
+ {
1257
+ code: "en-PW",
1258
+ name: "English (Palau) (en-PW)"
1259
+ },
1260
+ {
1261
+ code: "en-PG",
1262
+ name: "English (Papua New Guinea) (en-PG)"
1263
+ },
1264
+ {
1265
+ code: "en-PH",
1266
+ name: "English (Philippines) (en-PH)"
1267
+ },
1268
+ {
1269
+ code: "en-PN",
1270
+ name: "English (Pitcairn Islands) (en-PN)"
1271
+ },
1272
+ {
1273
+ code: "en-PR",
1274
+ name: "English (Puerto Rico) (en-PR)"
1275
+ },
1276
+ {
1277
+ code: "en-RW",
1278
+ name: "English (Rwanda) (en-RW)"
1279
+ },
1280
+ {
1281
+ code: "en-WS",
1282
+ name: "English (Samoa) (en-WS)"
1283
+ },
1284
+ {
1285
+ code: "en-SA",
1286
+ name: "English (Saudi Arabia) (en-SA)"
1287
+ },
1288
+ {
1289
+ code: "en-SC",
1290
+ name: "English (Seychelles) (en-SC)"
1291
+ },
1292
+ {
1293
+ code: "en-SL",
1294
+ name: "English (Sierra Leone) (en-SL)"
1295
+ },
1296
+ {
1297
+ code: "en-SG",
1298
+ name: "English (Singapore) (en-SG)"
1299
+ },
1300
+ {
1301
+ code: "en-SX",
1302
+ name: "English (Sint Maarten) (en-SX)"
1303
+ },
1304
+ {
1305
+ code: "en-SI",
1306
+ name: "English (Slovenia) (en-SI)"
1307
+ },
1308
+ {
1309
+ code: "en-SB",
1310
+ name: "English (Solomon Islands) (en-SB)"
1311
+ },
1312
+ {
1313
+ code: "en-SS",
1314
+ name: "English (South Sudan) (en-SS)"
1315
+ },
1316
+ {
1317
+ code: "en-SH",
1318
+ name: "English (St Helena) (en-SH)"
1319
+ },
1320
+ {
1321
+ code: "en-KN",
1322
+ name: "English (St Kitts & Nevis) (en-KN)"
1323
+ },
1324
+ {
1325
+ code: "en-LC",
1326
+ name: "English (St Lucia) (en-LC)"
1327
+ },
1328
+ {
1329
+ code: "svc",
1330
+ name: "Vincentian Creole English"
1331
+ },
1332
+ {
1333
+ code: "vic",
1334
+ name: "Virgin Islands Creole English"
1335
+ },
1336
+ {
1337
+ code: "en-SD",
1338
+ name: "English (Sudan) (en-SD)"
1339
+ },
1340
+ {
1341
+ code: "en-SZ",
1342
+ name: "English (Swaziland) (en-SZ)"
1343
+ },
1344
+ {
1345
+ code: "en-SE",
1346
+ name: "English (Sweden) (en-SE)"
1347
+ },
1348
+ {
1349
+ code: "en-CH",
1350
+ name: "English (Switzerland) (en-CH)"
1351
+ },
1352
+ {
1353
+ code: "en-TZ",
1354
+ name: "English (Tanzania) (en-TZ)"
1355
+ },
1356
+ {
1357
+ code: "en-TK",
1358
+ name: "English (Tokelau) (en-TK)"
1359
+ },
1360
+ {
1361
+ code: "en-TO",
1362
+ name: "English (Tonga) (en-TO)"
1363
+ },
1364
+ {
1365
+ code: "en-TT",
1366
+ name: "English (Trinidad and Tobago) (en-TT)"
1367
+ },
1368
+ {
1369
+ code: "en-TV",
1370
+ name: "English (Tuvalu) (en-TV)"
1371
+ },
1372
+ {
1373
+ code: "en-ZA",
1374
+ name: "English (South Africa) (en-ZA)"
1375
+ },
1376
+ {
1377
+ code: "en-AE",
1378
+ name: "English (U.A.E.) (en-AE)"
1379
+ },
1380
+ {
1381
+ code: "en-UM",
1382
+ name: "English (U.S. Minor Outlying Islands) (en-UM)"
1383
+ },
1384
+ {
1385
+ code: "en-VI",
1386
+ name: "English (U.S. Virgin Islands) (en-VI)"
1387
+ },
1388
+ {
1389
+ code: "en-US-POSIX",
1390
+ name: "English (U.S., Computer) (en-US-POSIX)"
1391
+ },
1392
+ {
1393
+ code: "en-UG",
1394
+ name: "English (Uganda) (en-UG)"
1395
+ },
1396
+ {
1397
+ code: "en-GB",
1398
+ name: "English (United Kingdom) (en-GB)"
1399
+ },
1400
+ {
1401
+ code: "en-US",
1402
+ name: "English (United States) (en-US)"
1403
+ },
1404
+ {
1405
+ code: "en-VU",
1406
+ name: "English (Vanuatu) (en-VU)"
1407
+ },
1408
+ {
1409
+ code: "en-ZM",
1410
+ name: "English (Zambia) (en-ZM)"
1411
+ },
1412
+ {
1413
+ code: "en-ZW",
1414
+ name: "English (Zimbabwe) (en-ZW)"
1415
+ },
1416
+ {
1417
+ code: "eo",
1418
+ name: "Esperanto (eo)"
1419
+ },
1420
+ {
1421
+ code: "et",
1422
+ name: "Estonian (et)"
1423
+ },
1424
+ {
1425
+ code: "et-EE",
1426
+ name: "Estonian (Estonia) (et-EE)"
1427
+ },
1428
+ {
1429
+ code: "ee",
1430
+ name: "Ewe (ee)"
1431
+ },
1432
+ {
1433
+ code: "ee-GH",
1434
+ name: "Ewe (Ghana) (ee-GH)"
1435
+ },
1436
+ {
1437
+ code: "ee-TG",
1438
+ name: "Ewe (Togo) (ee-TG)"
1439
+ },
1440
+ {
1441
+ code: "ewo",
1442
+ name: "Ewondo (ewo)"
1443
+ },
1444
+ {
1445
+ code: "ewo-CM",
1446
+ name: "Ewondo (Cameroon) (ewo-CM)"
1447
+ },
1448
+ {
1449
+ code: "fo",
1450
+ name: "Faroese (fo)"
1451
+ },
1452
+ {
1453
+ code: "fo-FO",
1454
+ name: "Faroese (Faroe Islands) (fo-FO)"
1455
+ },
1456
+ {
1457
+ code: "fil",
1458
+ name: "Filipino (fil)"
1459
+ },
1460
+ {
1461
+ code: "fil-PH",
1462
+ name: "Filipino (Philippines) (fil-PH)"
1463
+ },
1464
+ {
1465
+ code: "fi",
1466
+ name: "Finnish (fi)"
1467
+ },
1468
+ {
1469
+ code: "fi-FI",
1470
+ name: "Finnish (Finland) (fi-FI)"
1471
+ },
1472
+ {
1473
+ code: "fr",
1474
+ name: "French (fr)"
1475
+ },
1476
+ {
1477
+ code: "fr-BE",
1478
+ name: "French (Belgium) (fr-BE)"
1479
+ },
1480
+ {
1481
+ code: "fr-BJ",
1482
+ name: "French (Benin) (fr-BJ)"
1483
+ },
1484
+ {
1485
+ code: "fr-BF",
1486
+ name: "French (Burkina Faso) (fr-BF)"
1487
+ },
1488
+ {
1489
+ code: "fr-BI",
1490
+ name: "French (Burundi) (fr-BI)"
1491
+ },
1492
+ {
1493
+ code: "fr-CM",
1494
+ name: "French (Cameroon) (fr-CM)"
1495
+ },
1496
+ {
1497
+ code: "fr-CA",
1498
+ name: "French (Canada) (fr-CA)"
1499
+ },
1500
+ {
1501
+ code: "fr-CF",
1502
+ name: "French (Central African Republic) (fr-CF)"
1503
+ },
1504
+ {
1505
+ code: "fr-TD",
1506
+ name: "French (Chad) (fr-TD)"
1507
+ },
1508
+ {
1509
+ code: "fr-KM",
1510
+ name: "French (Comoros) (fr-KM)"
1511
+ },
1512
+ {
1513
+ code: "fr-CG",
1514
+ name: "French (Congo - Brazzaville) (fr-CG)"
1515
+ },
1516
+ {
1517
+ code: "fr-CD",
1518
+ name: "French (Congo - Kinshasa) (fr-CD)"
1519
+ },
1520
+ {
1521
+ code: "fr-CI",
1522
+ name: "French (Côte d’Ivoire) (fr-CI)"
1523
+ },
1524
+ {
1525
+ code: "fr-DJ",
1526
+ name: "French (Djibouti) (fr-DJ)"
1527
+ },
1528
+ {
1529
+ code: "fr-GQ",
1530
+ name: "French (Equatorial Guinea) (fr-GQ)"
1531
+ },
1532
+ {
1533
+ code: "fr-FR",
1534
+ name: "French (France) (fr-FR)"
1535
+ },
1536
+ {
1537
+ code: "fr-GF",
1538
+ name: "French (French Guiana) (fr-GF)"
1539
+ },
1540
+ {
1541
+ code: "fr-GA",
1542
+ name: "French (Gabon) (fr-GA)"
1543
+ },
1544
+ {
1545
+ code: "fr-GP",
1546
+ name: "French (Guadeloupe) (fr-GP)"
1547
+ },
1548
+ {
1549
+ code: "fr-GN",
1550
+ name: "French (Guinea) (fr-GN)"
1551
+ },
1552
+ {
1553
+ code: "fr-LU",
1554
+ name: "French (Luxembourg) (fr-LU)"
1555
+ },
1556
+ {
1557
+ code: "fr-MG",
1558
+ name: "French (Madagascar) (fr-MG)"
1559
+ },
1560
+ {
1561
+ code: "fr-ML",
1562
+ name: "French (Mali) (fr-ML)"
1563
+ },
1564
+ {
1565
+ code: "fr-MQ",
1566
+ name: "French (Martinique) (fr-MQ)"
1567
+ },
1568
+ {
1569
+ code: "fr-YT",
1570
+ name: "French (Mayotte) (fr-YT)"
1571
+ },
1572
+ {
1573
+ code: "fr-MC",
1574
+ name: "French (Monaco) (fr-MC)"
1575
+ },
1576
+ {
1577
+ code: "fr-NE",
1578
+ name: "French (Niger) (fr-NE)"
1579
+ },
1580
+ {
1581
+ code: "fr-RW",
1582
+ name: "French (Rwanda) (fr-RW)"
1583
+ },
1584
+ {
1585
+ code: "fr-RE",
1586
+ name: "French (Réunion) (fr-RE)"
1587
+ },
1588
+ {
1589
+ code: "fr-BL",
1590
+ name: "French (Saint Barthélemy) (fr-BL)"
1591
+ },
1592
+ {
1593
+ code: "fr-MF",
1594
+ name: "French (Saint Martin) (fr-MF)"
1595
+ },
1596
+ {
1597
+ code: "fr-MU",
1598
+ name: "French (Mauritius) (fr-MU)"
1599
+ },
1600
+ {
1601
+ code: "fr-SN",
1602
+ name: "French (Senegal) (fr-SN)"
1603
+ },
1604
+ {
1605
+ code: "fr-CH",
1606
+ name: "French (Switzerland) (fr-CH)"
1607
+ },
1608
+ {
1609
+ code: "fr-TG",
1610
+ name: "French (Togo) (fr-TG)"
1611
+ },
1612
+ {
1613
+ code: "ff",
1614
+ name: "Fulah (ff)"
1615
+ },
1616
+ {
1617
+ code: "ff-SN",
1618
+ name: "Fulah (Senegal) (ff-SN)"
1619
+ },
1620
+ {
1621
+ code: "gl",
1622
+ name: "Galician (gl)"
1623
+ },
1624
+ {
1625
+ code: "gl-ES",
1626
+ name: "Galician (Spain) (gl-ES)"
1627
+ },
1628
+ {
1629
+ code: "lao",
1630
+ name: "Laotian (Laos) (lao)"
1631
+ },
1632
+ {
1633
+ code: "lg",
1634
+ name: "Ganda (lg)"
1635
+ },
1636
+ {
1637
+ code: "lg-UG",
1638
+ name: "Ganda (Uganda) (lg-UG)"
1639
+ },
1640
+ {
1641
+ code: "ka",
1642
+ name: "Georgian (ka)"
1643
+ },
1644
+ {
1645
+ code: "ka-GE",
1646
+ name: "Georgian (Georgia) (ka-GE)"
1647
+ },
1648
+ {
1649
+ code: "de",
1650
+ name: "German (de)"
1651
+ },
1652
+ {
1653
+ code: "de-AT",
1654
+ name: "German (Austria) (de-AT)"
1655
+ },
1656
+ {
1657
+ code: "de-BE",
1658
+ name: "German (Belgium) (de-BE)"
1659
+ },
1660
+ {
1661
+ code: "de-DE",
1662
+ name: "German (Germany) (de-DE)"
1663
+ },
1664
+ {
1665
+ code: "de-LI",
1666
+ name: "German (Liechtenstein) (de-LI)"
1667
+ },
1668
+ {
1669
+ code: "de-LU",
1670
+ name: "German (Luxembourg) (de-LU)"
1671
+ },
1672
+ {
1673
+ code: "de-CH",
1674
+ name: "German (Switzerland) (de-CH)"
1675
+ },
1676
+ {
1677
+ code: "el",
1678
+ name: "Greek (el)"
1679
+ },
1680
+ {
1681
+ code: "el-CY",
1682
+ name: "Greek (Cyprus) (el-CY)"
1683
+ },
1684
+ {
1685
+ code: "el-GR",
1686
+ name: "Greek (Greece) (el-GR)"
1687
+ },
1688
+ {
1689
+ code: "gu",
1690
+ name: "Gujarati (gu)"
1691
+ },
1692
+ {
1693
+ code: "gu-IN",
1694
+ name: "Gujarati (India) (gu-IN)"
1695
+ },
1696
+ {
1697
+ code: "guz",
1698
+ name: "Gusii (guz)"
1699
+ },
1700
+ {
1701
+ code: "guz-KE",
1702
+ name: "Gusii (Kenya) (guz-KE)"
1703
+ },
1704
+ {
1705
+ code: "ha",
1706
+ name: "Hausa (ha)"
1707
+ },
1708
+ {
1709
+ code: "ha-Latn",
1710
+ name: "Hausa (Latin) (ha-Latn)"
1711
+ },
1712
+ {
1713
+ code: "ha-Latn-GH",
1714
+ name: "Hausa (Latin, Ghana) (ha-Latn-GH)"
1715
+ },
1716
+ {
1717
+ code: "ha-Latn-NE",
1718
+ name: "Hausa (Latin, Niger) (ha-Latn-NE)"
1719
+ },
1720
+ {
1721
+ code: "ha-Latn-NG",
1722
+ name: "Hausa (Latin, Nigeria) (ha-Latn-NG)"
1723
+ },
1724
+ {
1725
+ code: "haw",
1726
+ name: "Hawaiian (haw)"
1727
+ },
1728
+ {
1729
+ code: "haw-US",
1730
+ name: "Hawaiian (United States) (haw-US)"
1731
+ },
1732
+ {
1733
+ code: "he",
1734
+ name: "Hebrew (he)"
1735
+ },
1736
+ {
1737
+ code: "he-IL",
1738
+ name: "Hebrew (Israel) (he-IL)"
1739
+ },
1740
+ {
1741
+ code: "hi",
1742
+ name: "Hindi (hi)"
1743
+ },
1744
+ {
1745
+ code: "hi-IN",
1746
+ name: "Hindi (India) (hi-IN)"
1747
+ },
1748
+ {
1749
+ code: "hu",
1750
+ name: "Hungarian (hu)"
1751
+ },
1752
+ {
1753
+ code: "hu-HU",
1754
+ name: "Hungarian (Hungary) (hu-HU)"
1755
+ },
1756
+ {
1757
+ code: "is",
1758
+ name: "Icelandic (is)"
1759
+ },
1760
+ {
1761
+ code: "is-IS",
1762
+ name: "Icelandic (Iceland) (is-IS)"
1763
+ },
1764
+ {
1765
+ code: "ig",
1766
+ name: "Igbo (ig)"
1767
+ },
1768
+ {
1769
+ code: "ig-NG",
1770
+ name: "Igbo (Nigeria) (ig-NG)"
1771
+ },
1772
+ {
1773
+ code: "smn",
1774
+ name: "Inari Sami"
1775
+ },
1776
+ {
1777
+ code: "smn-FI",
1778
+ name: "Inari Sami (Finland)"
1779
+ },
1780
+ {
1781
+ code: "id",
1782
+ name: "Indonesian (id)"
1783
+ },
1784
+ {
1785
+ code: "id-ID",
1786
+ name: "Indonesian (Indonesia) (id-ID)"
1787
+ },
1788
+ {
1789
+ code: "ga",
1790
+ name: "Irish (ga)"
1791
+ },
1792
+ {
1793
+ code: "ga-IE",
1794
+ name: "Irish (Ireland) (ga-IE)"
1795
+ },
1796
+ {
1797
+ code: "it",
1798
+ name: "Italian (it)"
1799
+ },
1800
+ {
1801
+ code: "it-IT",
1802
+ name: "Italian (Italy) (it-IT)"
1803
+ },
1804
+ {
1805
+ code: "it-CH",
1806
+ name: "Italian (Switzerland) (it-CH)"
1807
+ },
1808
+ {
1809
+ code: "ja",
1810
+ name: "Japanese (ja)"
1811
+ },
1812
+ {
1813
+ code: "ja-JP",
1814
+ name: "Japanese (Japan) (ja-JP)"
1815
+ },
1816
+ {
1817
+ code: "dyo",
1818
+ name: "Jola-Fonyi (dyo)"
1819
+ },
1820
+ {
1821
+ code: "dyo-SN",
1822
+ name: "Jola-Fonyi (Senegal) (dyo-SN)"
1823
+ },
1824
+ {
1825
+ code: "kea",
1826
+ name: "Kabuverdianu (kea)"
1827
+ },
1828
+ {
1829
+ code: "kea-CV",
1830
+ name: "Kabuverdianu (Cape Verde) (kea-CV)"
1831
+ },
1832
+ {
1833
+ code: "kab",
1834
+ name: "Kabyle (kab)"
1835
+ },
1836
+ {
1837
+ code: "kab-DZ",
1838
+ name: "Kabyle (Algeria) (kab-DZ)"
1839
+ },
1840
+ {
1841
+ code: "kl",
1842
+ name: "Kalaallisut (kl)"
1843
+ },
1844
+ {
1845
+ code: "kl-GL",
1846
+ name: "Kalaallisut (Greenland) (kl-GL)"
1847
+ },
1848
+ {
1849
+ code: "kln",
1850
+ name: "Kalenjin (kln)"
1851
+ },
1852
+ {
1853
+ code: "kln-KE",
1854
+ name: "Kalenjin (Kenya) (kln-KE)"
1855
+ },
1856
+ {
1857
+ code: "kam",
1858
+ name: "Kamba (kam)"
1859
+ },
1860
+ {
1861
+ code: "kam-KE",
1862
+ name: "Kamba (Kenya) (kam-KE)"
1863
+ },
1864
+ {
1865
+ code: "kn",
1866
+ name: "Kannada (kn)"
1867
+ },
1868
+ {
1869
+ code: "kn-IN",
1870
+ name: "Kannada (India) (kn-IN)"
1871
+ },
1872
+ {
1873
+ code: "kaa",
1874
+ name: "Kara-Kalpak (kaa)"
1875
+ },
1876
+ {
1877
+ code: "kk",
1878
+ name: "Kazakh (kk)"
1879
+ },
1880
+ {
1881
+ code: "kk-Cyrl",
1882
+ name: "Kazakh (Cyrillic) (kk-Cyrl)"
1883
+ },
1884
+ {
1885
+ code: "kk-Cyrl-KZ",
1886
+ name: "Kazakh (Cyrillic, Kazakhstan) (kk-Cyrl-KZ)"
1887
+ },
1888
+ {
1889
+ code: "km",
1890
+ name: "Khmer (km)"
1891
+ },
1892
+ {
1893
+ code: "km-KH",
1894
+ name: "Khmer (Cambodia) (km-KH)"
1895
+ },
1896
+ {
1897
+ code: "ki",
1898
+ name: "Kikuyu (ki)"
1899
+ },
1900
+ {
1901
+ code: "ki-KE",
1902
+ name: "Kikuyu (Kenya) (ki-KE)"
1903
+ },
1904
+ {
1905
+ code: "rw",
1906
+ name: "Kinyarwanda (rw)"
1907
+ },
1908
+ {
1909
+ code: "rw-RW",
1910
+ name: "Kinyarwanda (Rwanda) (rw-RW)"
1911
+ },
1912
+ {
1913
+ code: "kok",
1914
+ name: "Konkani (kok)"
1915
+ },
1916
+ {
1917
+ code: "kok-IN",
1918
+ name: "Konkani (India) (kok-IN)"
1919
+ },
1920
+ {
1921
+ code: "ko",
1922
+ name: "Korean (ko)"
1923
+ },
1924
+ {
1925
+ code: "ko-KR",
1926
+ name: "Korean (South Korea) (ko-KR)"
1927
+ },
1928
+ {
1929
+ code: "khq",
1930
+ name: "Koyra Chiini (khq)"
1931
+ },
1932
+ {
1933
+ code: "khq-ML",
1934
+ name: "Koyra Chiini (Mali) (khq-ML)"
1935
+ },
1936
+ {
1937
+ code: "ses",
1938
+ name: "Koyraboro Senni (ses)"
1939
+ },
1940
+ {
1941
+ code: "ses-ML",
1942
+ name: "Koyraboro Senni (Mali) (ses-ML)"
1943
+ },
1944
+ {
1945
+ code: "nmg",
1946
+ name: "Kwasio (nmg)"
1947
+ },
1948
+ {
1949
+ code: "nmg-CM",
1950
+ name: "Kwasio (Cameroon) (nmg-CM)"
1951
+ },
1952
+ {
1953
+ code: "ky",
1954
+ name: "Kyrgyz (ky)"
1955
+ },
1956
+ {
1957
+ code: "lag",
1958
+ name: "Langi (lag)"
1959
+ },
1960
+ {
1961
+ code: "lag-TZ",
1962
+ name: "Langi (Tanzania) (lag-TZ)"
1963
+ },
1964
+ {
1965
+ code: "lv",
1966
+ name: "Latvian (lv)"
1967
+ },
1968
+ {
1969
+ code: "lv-LV",
1970
+ name: "Latvian (Latvia) (lv-LV)"
1971
+ },
1972
+ {
1973
+ code: "lir",
1974
+ name: "Liberian English"
1975
+ },
1976
+ {
1977
+ code: "ln",
1978
+ name: "Lingala (ln)"
1979
+ },
1980
+ {
1981
+ code: "ln-CG",
1982
+ name: "Lingala (Congo - Brazzaville) (ln-CG)"
1983
+ },
1984
+ {
1985
+ code: "ln-CD",
1986
+ name: "Lingala (Congo - Kinshasa) (ln-CD)"
1987
+ },
1988
+ {
1989
+ code: "lt",
1990
+ name: "Lithuanian (lt)"
1991
+ },
1992
+ {
1993
+ code: "lt-LT",
1994
+ name: "Lithuanian (Lithuania) (lt-LT)"
1995
+ },
1996
+ {
1997
+ code: "lu",
1998
+ name: "Luba-Katanga (lu)"
1999
+ },
2000
+ {
2001
+ code: "lu-CD",
2002
+ name: "Luba-Katanga (Congo - Kinshasa) (lu-CD)"
2003
+ },
2004
+ {
2005
+ code: "luo",
2006
+ name: "Luo (luo)"
2007
+ },
2008
+ {
2009
+ code: "luo-KE",
2010
+ name: "Luo (Kenya) (luo-KE)"
2011
+ },
2012
+ {
2013
+ code: "luy",
2014
+ name: "Luyia (luy)"
2015
+ },
2016
+ {
2017
+ code: "luy-KE",
2018
+ name: "Luyia (Kenya) (luy-KE)"
2019
+ },
2020
+ {
2021
+ code: "mk",
2022
+ name: "Macedonian (mk)"
2023
+ },
2024
+ {
2025
+ code: "mk-MK",
2026
+ name: "Macedonian (Macedonia) (mk-MK)"
2027
+ },
2028
+ {
2029
+ code: "jmc",
2030
+ name: "Machame (jmc)"
2031
+ },
2032
+ {
2033
+ code: "jmc-TZ",
2034
+ name: "Machame (Tanzania) (jmc-TZ)"
2035
+ },
2036
+ {
2037
+ code: "mgh",
2038
+ name: "Makhuwa-Meetto (mgh)"
2039
+ },
2040
+ {
2041
+ code: "mgh-MZ",
2042
+ name: "Makhuwa-Meetto (Mozambique) (mgh-MZ)"
2043
+ },
2044
+ {
2045
+ code: "kde",
2046
+ name: "Makonde (kde)"
2047
+ },
2048
+ {
2049
+ code: "kde-TZ",
2050
+ name: "Makonde (Tanzania) (kde-TZ)"
2051
+ },
2052
+ {
2053
+ code: "mg",
2054
+ name: "Malagasy (mg)"
2055
+ },
2056
+ {
2057
+ code: "mg-MG",
2058
+ name: "Malagasy (Madagascar) (mg-MG)"
2059
+ },
2060
+ {
2061
+ code: "ms",
2062
+ name: "Malay (ms)"
2063
+ },
2064
+ {
2065
+ code: "ms-BN",
2066
+ name: "Malay (Brunei) (ms-BN)"
2067
+ },
2068
+ {
2069
+ code: "ms-MY",
2070
+ name: "Malay (Malaysia) (ms-MY)"
2071
+ },
2072
+ {
2073
+ code: "ml",
2074
+ name: "Malayalam (ml)"
2075
+ },
2076
+ {
2077
+ code: "ml-IN",
2078
+ name: "Malayalam (India) (ml-IN)"
2079
+ },
2080
+ {
2081
+ code: "mt",
2082
+ name: "Maltese (mt)"
2083
+ },
2084
+ {
2085
+ code: "mt-MT",
2086
+ name: "Maltese (Malta) (mt-MT)"
2087
+ },
2088
+ {
2089
+ code: "gv",
2090
+ name: "Manx (gv)"
2091
+ },
2092
+ {
2093
+ code: "gv-GB",
2094
+ name: "Manx (United Kingdom) (gv-GB)"
2095
+ },
2096
+ {
2097
+ code: "mr",
2098
+ name: "Marathi (mr)"
2099
+ },
2100
+ {
2101
+ code: "mr-IN",
2102
+ name: "Marathi (India) (mr-IN)"
2103
+ },
2104
+ {
2105
+ code: "mas",
2106
+ name: "Masai (mas)"
2107
+ },
2108
+ {
2109
+ code: "mas-KE",
2110
+ name: "Masai (Kenya) (mas-KE)"
2111
+ },
2112
+ {
2113
+ code: "mas-TZ",
2114
+ name: "Masai (Tanzania) (mas-TZ)"
2115
+ },
2116
+ {
2117
+ code: "mer",
2118
+ name: "Meru (mer)"
2119
+ },
2120
+ {
2121
+ code: "mer-KE",
2122
+ name: "Meru (Kenya) (mer-KE)"
2123
+ },
2124
+ {
2125
+ code: "mn",
2126
+ name: "Mongolian (mn)"
2127
+ },
2128
+ {
2129
+ code: "mfe",
2130
+ name: "Morisyen (mfe)"
2131
+ },
2132
+ {
2133
+ code: "mfe-MU",
2134
+ name: "Morisyen (Mauritius) (mfe-MU)"
2135
+ },
2136
+ {
2137
+ code: "mua",
2138
+ name: "Mundang (mua)"
2139
+ },
2140
+ {
2141
+ code: "mua-CM",
2142
+ name: "Mundang (Cameroon) (mua-CM)"
2143
+ },
2144
+ {
2145
+ code: "naq",
2146
+ name: "Nama (naq)"
2147
+ },
2148
+ {
2149
+ code: "naq-NA",
2150
+ name: "Nama (Namibia) (naq-NA)"
2151
+ },
2152
+ {
2153
+ code: "ne",
2154
+ name: "Nepali (ne)"
2155
+ },
2156
+ {
2157
+ code: "ne-IN",
2158
+ name: "Nepali (India) (ne-IN)"
2159
+ },
2160
+ {
2161
+ code: "ne-NP",
2162
+ name: "Nepali (Nepal) (ne-NP)"
2163
+ },
2164
+ {
2165
+ code: "se",
2166
+ name: "Northern Sami"
2167
+ },
2168
+ {
2169
+ code: "se-FI",
2170
+ name: "Northern Sami (Finland)"
2171
+ },
2172
+ {
2173
+ code: "se-NO",
2174
+ name: "Northern Sami (Norway)"
2175
+ },
2176
+ {
2177
+ code: "se-SE",
2178
+ name: "Northern Sami (Sweden)"
2179
+ },
2180
+ {
2181
+ code: "nd",
2182
+ name: "North Ndebele (nd)"
2183
+ },
2184
+ {
2185
+ code: "nd-ZW",
2186
+ name: "North Ndebele (Zimbabwe) (nd-ZW)"
2187
+ },
2188
+ {
2189
+ code: "nb",
2190
+ name: "Norwegian Bokmål (nb)"
2191
+ },
2192
+ {
2193
+ code: "nb-NO",
2194
+ name: "Norwegian Bokmål (Norway) (nb-NO)"
2195
+ },
2196
+ {
2197
+ code: "nn",
2198
+ name: "Norwegian Nynorsk (nn)"
2199
+ },
2200
+ {
2201
+ code: "nn-NO",
2202
+ name: "Norwegian Nynorsk (Norway) (nn-NO)"
2203
+ },
2204
+ {
2205
+ code: "nus",
2206
+ name: "Nuer (nus)"
2207
+ },
2208
+ {
2209
+ code: "nus-SD",
2210
+ name: "Nuer (Sudan) (nus-SD)"
2211
+ },
2212
+ {
2213
+ code: "nyn",
2214
+ name: "Nyankole (nyn)"
2215
+ },
2216
+ {
2217
+ code: "nyn-UG",
2218
+ name: "Nyankole (Uganda) (nyn-UG)"
2219
+ },
2220
+ {
2221
+ code: "or",
2222
+ name: "Oriya (or)"
2223
+ },
2224
+ {
2225
+ code: "or-IN",
2226
+ name: "Oriya (India) (or-IN)"
2227
+ },
2228
+ {
2229
+ code: "om",
2230
+ name: "Oromo (om)"
2231
+ },
2232
+ {
2233
+ code: "om-ET",
2234
+ name: "Oromo (Ethiopia) (om-ET)"
2235
+ },
2236
+ {
2237
+ code: "om-KE",
2238
+ name: "Oromo (Kenya) (om-KE)"
2239
+ },
2240
+ {
2241
+ code: "ps",
2242
+ name: "Pashto (ps)"
2243
+ },
2244
+ {
2245
+ code: "ps-AF",
2246
+ name: "Pashto (Afghanistan) (ps-AF)"
2247
+ },
2248
+ {
2249
+ code: "fa",
2250
+ name: "Persian (fa)"
2251
+ },
2252
+ {
2253
+ code: "fa-AF",
2254
+ name: "Persian (Afghanistan) (fa-AF)"
2255
+ },
2256
+ {
2257
+ code: "fa-IR",
2258
+ name: "Persian (Iran) (fa-IR)"
2259
+ },
2260
+ {
2261
+ code: "pl",
2262
+ name: "Polish (pl)"
2263
+ },
2264
+ {
2265
+ code: "pl-PL",
2266
+ name: "Polish (Poland) (pl-PL)"
2267
+ },
2268
+ {
2269
+ code: "pt",
2270
+ name: "Portuguese (pt)"
2271
+ },
2272
+ {
2273
+ code: "pt-AO",
2274
+ name: "Portuguese (Angola) (pt-AO)"
2275
+ },
2276
+ {
2277
+ code: "pt-BR",
2278
+ name: "Portuguese (Brazil) (pt-BR)"
2279
+ },
2280
+ {
2281
+ code: "pt-GW",
2282
+ name: "Portuguese (Guinea-Bissau) (pt-GW)"
2283
+ },
2284
+ {
2285
+ code: "pt-MZ",
2286
+ name: "Portuguese (Mozambique) (pt-MZ)"
2287
+ },
2288
+ {
2289
+ code: "pt-PT",
2290
+ name: "Portuguese (Portugal) (pt-PT)"
2291
+ },
2292
+ {
2293
+ code: "pt-ST",
2294
+ name: "Portuguese (São Tomé and Príncipe) (pt-ST)"
2295
+ },
2296
+ {
2297
+ code: "pa",
2298
+ name: "Punjabi (pa)"
2299
+ },
2300
+ {
2301
+ code: "pa-Arab",
2302
+ name: "Punjabi (Arabic) (pa-Arab)"
2303
+ },
2304
+ {
2305
+ code: "pa-Arab-PK",
2306
+ name: "Punjabi (Arabic, Pakistan) (pa-Arab-PK)"
2307
+ },
2308
+ {
2309
+ code: "pa-Guru",
2310
+ name: "Punjabi (Gurmukhi) (pa-Guru)"
2311
+ },
2312
+ {
2313
+ code: "pa-Guru-IN",
2314
+ name: "Punjabi (Gurmukhi, India) (pa-Guru-IN)"
2315
+ },
2316
+ {
2317
+ code: "ro",
2318
+ name: "Romanian (ro)"
2319
+ },
2320
+ {
2321
+ code: "ro-MD",
2322
+ name: "Romanian (Moldova) (ro-MD)"
2323
+ },
2324
+ {
2325
+ code: "ro-RO",
2326
+ name: "Romanian (Romania) (ro-RO)"
2327
+ },
2328
+ {
2329
+ code: "rm",
2330
+ name: "Romansh (rm)"
2331
+ },
2332
+ {
2333
+ code: "rm-CH",
2334
+ name: "Romansh (Switzerland) (rm-CH)"
2335
+ },
2336
+ {
2337
+ code: "rof",
2338
+ name: "Rombo (rof)"
2339
+ },
2340
+ {
2341
+ code: "rof-TZ",
2342
+ name: "Rombo (Tanzania) (rof-TZ)"
2343
+ },
2344
+ {
2345
+ code: "rn",
2346
+ name: "Rundi (rn)"
2347
+ },
2348
+ {
2349
+ code: "rn-BI",
2350
+ name: "Rundi (Burundi) (rn-BI)"
2351
+ },
2352
+ {
2353
+ code: "ru",
2354
+ name: "Russian (ru)"
2355
+ },
2356
+ {
2357
+ code: "ru-MD",
2358
+ name: "Russian (Moldova) (ru-MD)"
2359
+ },
2360
+ {
2361
+ code: "ru-RU",
2362
+ name: "Russian (Russia) (ru-RU)"
2363
+ },
2364
+ {
2365
+ code: "ru-UA",
2366
+ name: "Russian (Ukraine) (ru-UA)"
2367
+ },
2368
+ {
2369
+ code: "rwk",
2370
+ name: "Rwa (rwk)"
2371
+ },
2372
+ {
2373
+ code: "rwk-TZ",
2374
+ name: "Rwa (Tanzania) (rwk-TZ)"
2375
+ },
2376
+ {
2377
+ code: "saq",
2378
+ name: "Samburu (saq)"
2379
+ },
2380
+ {
2381
+ code: "saq-KE",
2382
+ name: "Samburu (Kenya) (saq-KE)"
2383
+ },
2384
+ {
2385
+ code: "sg",
2386
+ name: "Sango (sg)"
2387
+ },
2388
+ {
2389
+ code: "sg-CF",
2390
+ name: "Sango (Central African Republic) (sg-CF)"
2391
+ },
2392
+ {
2393
+ code: "sbp",
2394
+ name: "Sangu (sbp)"
2395
+ },
2396
+ {
2397
+ code: "sbp-TZ",
2398
+ name: "Sangu (Tanzania) (sbp-TZ)"
2399
+ },
2400
+ {
2401
+ code: "sa",
2402
+ name: "Sanskrit (sa)"
2403
+ },
2404
+ {
2405
+ code: "gd",
2406
+ name: "Scottish Gaelic (gd)"
2407
+ },
2408
+ {
2409
+ code: "gd-GB",
2410
+ name: "Scottish Gaelic (United Kingdom)"
2411
+ },
2412
+ {
2413
+ code: "seh",
2414
+ name: "Sena (seh)"
2415
+ },
2416
+ {
2417
+ code: "seh-MZ",
2418
+ name: "Sena (Mozambique) (seh-MZ)"
2419
+ },
2420
+ {
2421
+ code: "sr",
2422
+ name: "Serbian (sr)"
2423
+ },
2424
+ {
2425
+ code: "sr-Cyrl",
2426
+ name: "Serbian (Cyrillic) (sr-Cyrl)"
2427
+ },
2428
+ {
2429
+ code: "sr-Cyrl-BA",
2430
+ name: "Serbian (Cyrillic, Bosnia and Herzegovina)(sr-Cyrl-BA) "
2431
+ },
2432
+ {
2433
+ code: "sr-Cyrl-ME",
2434
+ name: "Serbian (Cyrillic, Montenegro) (sr-Cyrl-ME)"
2435
+ },
2436
+ {
2437
+ code: "sr-Cyrl-RS",
2438
+ name: "Serbian (Cyrillic, Serbia) (sr-Cyrl-RS)"
2439
+ },
2440
+ {
2441
+ code: "sr-Latn",
2442
+ name: "Serbian (Latin) (sr-Latn)"
2443
+ },
2444
+ {
2445
+ code: "sr-Latn-BA",
2446
+ name: "Serbian (Latin, Bosnia and Herzegovina) (sr-Latn-BA) "
2447
+ },
2448
+ {
2449
+ code: "sr-Latn-ME",
2450
+ name: "Serbian (Latin, Montenegro) (sr-Latn-ME)"
2451
+ },
2452
+ {
2453
+ code: "sr-Latn-RS",
2454
+ name: "Serbian (Latin, Serbia) (sr-Latn-RS)"
2455
+ },
2456
+ {
2457
+ code: "ksb",
2458
+ name: "Shambala (ksb)"
2459
+ },
2460
+ {
2461
+ code: "ksb-TZ",
2462
+ name: "Shambala (Tanzania) (ksb-TZ)"
2463
+ },
2464
+ {
2465
+ code: "sn",
2466
+ name: "Shona (sn)"
2467
+ },
2468
+ {
2469
+ code: "sn-ZW",
2470
+ name: "Shona (Zimbabwe) (sn-ZW)"
2471
+ },
2472
+ {
2473
+ code: "ii",
2474
+ name: "Sichuan Yi (ii)"
2475
+ },
2476
+ {
2477
+ code: "ii-CN",
2478
+ name: "Sichuan Yi (China) (ii-CN)"
2479
+ },
2480
+ {
2481
+ code: "si",
2482
+ name: "Sinhala (si)"
2483
+ },
2484
+ {
2485
+ code: "si-LK",
2486
+ name: "Sinhala (Sri Lanka) (si-LK)"
2487
+ },
2488
+ {
2489
+ code: "sk",
2490
+ name: "Slovak (sk)"
2491
+ },
2492
+ {
2493
+ code: "sk-SK",
2494
+ name: "Slovak (Slovakia) (sk-SK)"
2495
+ },
2496
+ {
2497
+ code: "sl",
2498
+ name: "Slovenian (sl)"
2499
+ },
2500
+ {
2501
+ code: "sl-SI",
2502
+ name: "Slovenian (Slovenia) (sl-SI)"
2503
+ },
2504
+ {
2505
+ code: "xog",
2506
+ name: "Soga (xog)"
2507
+ },
2508
+ {
2509
+ code: "xog-UG",
2510
+ name: "Soga (Uganda) (xog-UG)"
2511
+ },
2512
+ {
2513
+ code: "so",
2514
+ name: "Somali (so)"
2515
+ },
2516
+ {
2517
+ code: "so-DJ",
2518
+ name: "Somali (Djibouti) (so-DJ)"
2519
+ },
2520
+ {
2521
+ code: "so-ET",
2522
+ name: "Somali (Ethiopia) (so-ET)"
2523
+ },
2524
+ {
2525
+ code: "so-KE",
2526
+ name: "Somali (Kenya) (so-KE)"
2527
+ },
2528
+ {
2529
+ code: "so-SO",
2530
+ name: "Somali (Somalia) (so-SO)"
2531
+ },
2532
+ {
2533
+ code: "es",
2534
+ name: "Spanish (es)"
2535
+ },
2536
+ {
2537
+ code: "es-AR",
2538
+ name: "Spanish (Argentina) (es-AR)"
2539
+ },
2540
+ {
2541
+ code: "es-BO",
2542
+ name: "Spanish (Bolivia) (es-BO)"
2543
+ },
2544
+ {
2545
+ code: "es-CL",
2546
+ name: "Spanish (Chile) (es-CL)"
2547
+ },
2548
+ {
2549
+ code: "es-CO",
2550
+ name: "Spanish (Colombia) (es-CO)"
2551
+ },
2552
+ {
2553
+ code: "es-CR",
2554
+ name: "Spanish (Costa Rica) (es-CR)"
2555
+ },
2556
+ {
2557
+ code: "es-DO",
2558
+ name: "Spanish (Dominican Republic) (es-DO)"
2559
+ },
2560
+ {
2561
+ code: "es-EC",
2562
+ name: "Spanish (Ecuador) (es-EC)"
2563
+ },
2564
+ {
2565
+ code: "es-SV",
2566
+ name: "Spanish (El Salvador) (es-SV)"
2567
+ },
2568
+ {
2569
+ code: "es-GQ",
2570
+ name: "Spanish (Equatorial Guinea) (es-GQ)"
2571
+ },
2572
+ {
2573
+ code: "es-GT",
2574
+ name: "Spanish (Guatemala) (es-GT)"
2575
+ },
2576
+ {
2577
+ code: "es-HN",
2578
+ name: "Spanish (Honduras) (es-HN)"
2579
+ },
2580
+ {
2581
+ code: "es-419",
2582
+ name: "Spanish (Latin America) (es-419)"
2583
+ },
2584
+ {
2585
+ code: "es-MX",
2586
+ name: "Spanish (Mexico) (es-MX)"
2587
+ },
2588
+ {
2589
+ code: "es-NI",
2590
+ name: "Spanish (Nicaragua) (es-NI)"
2591
+ },
2592
+ {
2593
+ code: "es-PA",
2594
+ name: "Spanish (Panama) (es-PA)"
2595
+ },
2596
+ {
2597
+ code: "es-PY",
2598
+ name: "Spanish (Paraguay) (es-PY)"
2599
+ },
2600
+ {
2601
+ code: "es-PE",
2602
+ name: "Spanish (Peru) (es-PE)"
2603
+ },
2604
+ {
2605
+ code: "es-PR",
2606
+ name: "Spanish (Puerto Rico) (es-PR)"
2607
+ },
2608
+ {
2609
+ code: "es-ES",
2610
+ name: "Spanish (Spain) (es-ES)"
2611
+ },
2612
+ {
2613
+ code: "es-US",
2614
+ name: "Spanish (United States) (es-US)"
2615
+ },
2616
+ {
2617
+ code: "es-UY",
2618
+ name: "Spanish (Uruguay) (es-UY)"
2619
+ },
2620
+ {
2621
+ code: "es-VE",
2622
+ name: "Spanish (Venezuela) (es-VE)"
2623
+ },
2624
+ {
2625
+ code: "sw",
2626
+ name: "Swahili (sw)"
2627
+ },
2628
+ {
2629
+ code: "sw-KE",
2630
+ name: "Swahili (Kenya) (sw-KE)"
2631
+ },
2632
+ {
2633
+ code: "sw-TZ",
2634
+ name: "Swahili (Tanzania) (sw-TZ)"
2635
+ },
2636
+ {
2637
+ code: "sv",
2638
+ name: "Swedish (sv)"
2639
+ },
2640
+ {
2641
+ code: "sv-FI",
2642
+ name: "Swedish (Finland) (sv-FI)"
2643
+ },
2644
+ {
2645
+ code: "sv-SE",
2646
+ name: "Swedish (Sweden) (sv-SE)"
2647
+ },
2648
+ {
2649
+ code: "gsw",
2650
+ name: "Swiss German (gsw)"
2651
+ },
2652
+ {
2653
+ code: "gsw-CH",
2654
+ name: "Swiss German (Switzerland) (gsw-CH)"
2655
+ },
2656
+ {
2657
+ code: "shi",
2658
+ name: "Tachelhit (shi)"
2659
+ },
2660
+ {
2661
+ code: "shi-Latn",
2662
+ name: "Tachelhit (Latin) (shi-Latn)"
2663
+ },
2664
+ {
2665
+ code: "shi-Latn-MA",
2666
+ name: "Tachelhit (Latin, Morocco) (shi-Latn-MA)"
2667
+ },
2668
+ {
2669
+ code: "shi-Tfng",
2670
+ name: "Tachelhit (Tifinagh) (shi-Tfng)"
2671
+ },
2672
+ {
2673
+ code: "shi-Tfng-MA",
2674
+ name: "Tachelhit (Tifinagh, Morocco) (shi-Tfng-MA)"
2675
+ },
2676
+ {
2677
+ code: "dav",
2678
+ name: "Taita (dav)"
2679
+ },
2680
+ {
2681
+ code: "dav-KE",
2682
+ name: "Taita (Kenya) (dav-KE)"
2683
+ },
2684
+ {
2685
+ code: "tg",
2686
+ name: "Tajik (tg)"
2687
+ },
2688
+ {
2689
+ code: "ta",
2690
+ name: "Tamil (ta)"
2691
+ },
2692
+ {
2693
+ code: "ta-IN",
2694
+ name: "Tamil (India) (ta-IN)"
2695
+ },
2696
+ {
2697
+ code: "ta-LK",
2698
+ name: "Tamil (Sri Lanka) (ta-LK)"
2699
+ },
2700
+ {
2701
+ code: "twq",
2702
+ name: "Tasawaq (twq)"
2703
+ },
2704
+ {
2705
+ code: "twq-NE",
2706
+ name: "Tasawaq (Niger) (twq-NE)"
2707
+ },
2708
+ {
2709
+ code: "mi",
2710
+ name: "Te Reo Māori (mi)"
2711
+ },
2712
+ {
2713
+ code: "te",
2714
+ name: "Telugu (te)"
2715
+ },
2716
+ {
2717
+ code: "te-IN",
2718
+ name: "Telugu (India) (te-IN)"
2719
+ },
2720
+ {
2721
+ code: "teo",
2722
+ name: "Teso (teo)"
2723
+ },
2724
+ {
2725
+ code: "teo-KE",
2726
+ name: "Teso (Kenya) (teo-KE)"
2727
+ },
2728
+ {
2729
+ code: "teo-UG",
2730
+ name: "Teso (Uganda) (teo-UG)"
2731
+ },
2732
+ {
2733
+ code: "th",
2734
+ name: "Thai (th)"
2735
+ },
2736
+ {
2737
+ code: "th-TH",
2738
+ name: "Thai (Thailand) (th-TH)"
2739
+ },
2740
+ {
2741
+ code: "bo",
2742
+ name: "Tibetan (bo)"
2743
+ },
2744
+ {
2745
+ code: "bo-CN",
2746
+ name: "Tibetan (China) (bo-CN)"
2747
+ },
2748
+ {
2749
+ code: "bo-IN",
2750
+ name: "Tibetan (India) (bo-IN)"
2751
+ },
2752
+ {
2753
+ code: "ti",
2754
+ name: "Tigrinya (ti)"
2755
+ },
2756
+ {
2757
+ code: "ti-ER",
2758
+ name: "Tigrinya (Eritrea) (ti-ER)"
2759
+ },
2760
+ {
2761
+ code: "ti-ET",
2762
+ name: "Tigrinya (Ethiopia) (ti-ET)"
2763
+ },
2764
+ {
2765
+ code: "to",
2766
+ name: "Tongan (to)"
2767
+ },
2768
+ {
2769
+ code: "to-TO",
2770
+ name: "Tongan (Tonga) (to-TO)"
2771
+ },
2772
+ {
2773
+ code: "tr",
2774
+ name: "Turkish (tr)"
2775
+ },
2776
+ {
2777
+ code: "tk",
2778
+ name: "Turkmen (tk)"
2779
+ },
2780
+ {
2781
+ code: "tr-TR",
2782
+ name: "Turkish (Turkey) (tr-TR)"
2783
+ },
2784
+ {
2785
+ code: "tch",
2786
+ name: "Turks And Caicos Creole English"
2787
+ },
2788
+ {
2789
+ code: "uk",
2790
+ name: "Ukrainian (uk)"
2791
+ },
2792
+ {
2793
+ code: "uk-UA",
2794
+ name: "Ukrainian (Ukraine) (uk-UA)"
2795
+ },
2796
+ {
2797
+ code: "ur",
2798
+ name: "Urdu (ur)"
2799
+ },
2800
+ {
2801
+ code: "ur-IN",
2802
+ name: "Urdu (India) (ur-IN)"
2803
+ },
2804
+ {
2805
+ code: "ur-PK",
2806
+ name: "Urdu (Pakistan) (ur-PK)"
2807
+ },
2808
+ {
2809
+ code: "ug",
2810
+ name: "Uyghur"
2811
+ },
2812
+ {
2813
+ code: "ug-CN",
2814
+ name: "Uyghur (China)"
2815
+ },
2816
+ {
2817
+ code: "uz",
2818
+ name: "Uzbek (uz)"
2819
+ },
2820
+ {
2821
+ code: "uz-Arab",
2822
+ name: "Uzbek (Arabic) (uz-Arab)"
2823
+ },
2824
+ {
2825
+ code: "uz-Arab-AF",
2826
+ name: "Uzbek (Arabic, Afghanistan) (uz-Arab-AF)"
2827
+ },
2828
+ {
2829
+ code: "uz-Cyrl",
2830
+ name: "Uzbek (Cyrillic) (uz-Cyrl)"
2831
+ },
2832
+ {
2833
+ code: "uz-Cyrl-UZ",
2834
+ name: "Uzbek (Cyrillic, Uzbekistan) (uz-Cyrl-UZ)"
2835
+ },
2836
+ {
2837
+ code: "uz-Latn",
2838
+ name: "Uzbek (Latin) (uz-Latn)"
2839
+ },
2840
+ {
2841
+ code: "uz-Latn-UZ",
2842
+ name: "Uzbek (Latin, Uzbekistan) (uz-Latn-UZ)"
2843
+ },
2844
+ {
2845
+ code: "vai",
2846
+ name: "Vai (vai)"
2847
+ },
2848
+ {
2849
+ code: "vai-Latn",
2850
+ name: "Vai (Latin) (vai-Latn)"
2851
+ },
2852
+ {
2853
+ code: "vai-Latn-LR",
2854
+ name: "Vai (Latin, Liberia) (vai-Latn-LR)"
2855
+ },
2856
+ {
2857
+ code: "vai-Vaii",
2858
+ name: "Vai (Vai) (vai-Vaii)"
2859
+ },
2860
+ {
2861
+ code: "vai-Vaii-LR",
2862
+ name: "Vai (Vai, Liberia) (vai-Vaii-LR)"
2863
+ },
2864
+ {
2865
+ code: "val",
2866
+ name: "Valencian (val)"
2867
+ },
2868
+ {
2869
+ code: "val-ES",
2870
+ name: "Valencian (Spain) (val-ES)"
2871
+ },
2872
+ {
2873
+ code: "ca-ES-valencia",
2874
+ name: "Valencian (Spain Catalan) (ca-ES-valencia)"
2875
+ },
2876
+ {
2877
+ code: "vi",
2878
+ name: "Vietnamese (vi)"
2879
+ },
2880
+ {
2881
+ code: "vi-VN",
2882
+ name: "Vietnamese (Vietnam) (vi-VN)"
2883
+ },
2884
+ {
2885
+ code: "vun",
2886
+ name: "Vunjo (vun)"
2887
+ },
2888
+ {
2889
+ code: "vun-TZ",
2890
+ name: "Vunjo (Tanzania) (vun-TZ)"
2891
+ },
2892
+ {
2893
+ code: "cy",
2894
+ name: "Welsh (cy)"
2895
+ },
2896
+ {
2897
+ code: "cy-GB",
2898
+ name: "Welsh (United Kingdom) (cy-GB)"
2899
+ },
2900
+ {
2901
+ code: "wo",
2902
+ name: "Wolof (wo)"
2903
+ },
2904
+ {
2905
+ code: "xh",
2906
+ name: "Xhosa (xh)"
2907
+ },
2908
+ {
2909
+ code: "yav",
2910
+ name: "Yangben (yav)"
2911
+ },
2912
+ {
2913
+ code: "yav-CM",
2914
+ name: "Yangben (Cameroon) (yav-CM)"
2915
+ },
2916
+ {
2917
+ code: "yo",
2918
+ name: "Yoruba (yo)"
2919
+ },
2920
+ {
2921
+ code: "yo-NG",
2922
+ name: "Yoruba (Nigeria) (yo-NG)"
2923
+ },
2924
+ {
2925
+ code: "dje",
2926
+ name: "Zarma (dje)"
2927
+ },
2928
+ {
2929
+ code: "dje-NE",
2930
+ name: "Zarma (Niger) (dje-NE)"
2931
+ },
2932
+ {
2933
+ code: "zu",
2934
+ name: "Zulu (zu)"
2935
+ },
2936
+ {
2937
+ code: "zu-ZA",
2938
+ name: "Zulu (South Africa) (zu-ZA)"
2939
+ }
2940
+ ];
2941
+ const getInitLocale = () => {
2942
+ const envLocaleCode = process.env.STRAPI_PLUGIN_I18N_INIT_LOCALE_CODE;
2943
+ if (envLocaleCode) {
2944
+ const matchingLocale = isoLocales.find(({ code }) => code === envLocaleCode);
2945
+ if (!matchingLocale) {
2946
+ throw new Error(
2947
+ "Unknown locale code provided in the environment variable STRAPI_PLUGIN_I18N_INIT_LOCALE_CODE"
2948
+ );
2949
+ }
2950
+ return { ...matchingLocale };
2951
+ }
2952
+ return {
2953
+ code: "en",
2954
+ name: "English (en)"
2955
+ };
2956
+ };
2957
+ const DEFAULT_LOCALE = getInitLocale();
2958
+ const find = (params = {}) => strapi.db.query("plugin::i18n.locale").findMany({ where: params });
2959
+ const findById = (id) => strapi.db.query("plugin::i18n.locale").findOne({ where: { id } });
2960
+ const findByCode = (code) => strapi.db.query("plugin::i18n.locale").findOne({ where: { code } });
2961
+ const count = (params = {}) => strapi.db.query("plugin::i18n.locale").count({ where: params });
2962
+ const create = async (locale2) => {
2963
+ const result = await strapi.db.query("plugin::i18n.locale").create({ data: locale2 });
2964
+ getService("metrics").sendDidUpdateI18nLocalesEvent();
2965
+ return result;
2966
+ };
2967
+ const update = async (params, updates) => {
2968
+ const result = await strapi.db.query("plugin::i18n.locale").update({ where: params, data: updates });
2969
+ getService("metrics").sendDidUpdateI18nLocalesEvent();
2970
+ return result;
2971
+ };
2972
+ const deleteFn = async ({ id }) => {
2973
+ const localeToDelete = await findById(id);
2974
+ if (localeToDelete) {
2975
+ await deleteAllLocalizedEntriesFor({ locale: localeToDelete.code });
2976
+ const result = await strapi.db.query("plugin::i18n.locale").delete({ where: { id } });
2977
+ getService("metrics").sendDidUpdateI18nLocalesEvent();
2978
+ return result;
2979
+ }
2980
+ return localeToDelete;
2981
+ };
2982
+ const setDefaultLocale = ({ code }) => getCoreStore().set({ key: "default_locale", value: code });
2983
+ const getDefaultLocale = () => getCoreStore().get({ key: "default_locale" });
2984
+ const setIsDefault = async (locales2) => {
2985
+ if (isNil(locales2)) {
2986
+ return locales2;
2987
+ }
2988
+ const actualDefault = await getDefaultLocale();
2989
+ if (Array.isArray(locales2)) {
2990
+ return locales2.map((locale2) => ({ ...locale2, isDefault: actualDefault === locale2.code }));
2991
+ }
2992
+ return { ...locales2, isDefault: actualDefault === locales2.code };
2993
+ };
2994
+ const initDefaultLocale = async () => {
2995
+ const existingLocalesNb = await strapi.db.query("plugin::i18n.locale").count();
2996
+ if (existingLocalesNb === 0) {
2997
+ await create(DEFAULT_LOCALE);
2998
+ await setDefaultLocale({ code: DEFAULT_LOCALE.code });
2999
+ }
3000
+ };
3001
+ const deleteAllLocalizedEntriesFor = async ({ locale: locale2 }) => {
3002
+ const { isLocalizedContentType: isLocalizedContentType2 } = getService("content-types");
3003
+ const localizedModels = Object.values(strapi.contentTypes).filter(isLocalizedContentType2);
3004
+ for (const model of localizedModels) {
3005
+ await strapi.db.query(model.uid).deleteMany({ where: { locale: locale2 } });
3006
+ }
3007
+ };
3008
+ const locales = () => ({
3009
+ find,
3010
+ findById,
3011
+ findByCode,
3012
+ create,
3013
+ update,
3014
+ count,
3015
+ setDefaultLocale,
3016
+ getDefaultLocale,
3017
+ setIsDefault,
3018
+ delete: deleteFn,
3019
+ initDefaultLocale
3020
+ });
3021
+ const getIsoLocales = () => isoLocales;
3022
+ const isoLocalesService = () => ({
3023
+ getIsoLocales
3024
+ });
3025
+ const {
3026
+ isRelationalAttribute,
3027
+ getVisibleAttributes,
3028
+ isTypedAttribute,
3029
+ getScalarAttributes,
3030
+ getRelationalAttributes
3031
+ } = contentTypes$2;
3032
+ const { ApplicationError: ApplicationError$2 } = errors;
3033
+ const hasLocalizedOption = (modelOrAttribute) => {
3034
+ return prop("pluginOptions.i18n.localized", modelOrAttribute) === true;
3035
+ };
3036
+ const getValidLocale = async (locale2) => {
3037
+ const localesService = getService("locales");
3038
+ if (isNil(locale2)) {
3039
+ return localesService.getDefaultLocale();
3040
+ }
3041
+ const foundLocale = await localesService.findByCode(locale2);
3042
+ if (!foundLocale) {
3043
+ throw new ApplicationError$2("Locale not found");
3044
+ }
3045
+ return locale2;
3046
+ };
3047
+ const isLocalizedAttribute = (attribute) => {
3048
+ return hasLocalizedOption(attribute) || isRelationalAttribute(attribute) || isTypedAttribute(attribute, "uid");
3049
+ };
3050
+ const isLocalizedContentType = (model) => {
3051
+ return hasLocalizedOption(model);
3052
+ };
3053
+ const getNonLocalizedAttributes = (model) => {
3054
+ return getVisibleAttributes(model).filter(
3055
+ (attrName) => !isLocalizedAttribute(model.attributes[attrName])
3056
+ );
3057
+ };
3058
+ const removeId = (value) => {
3059
+ if (typeof value === "object" && has("id", value)) {
3060
+ delete value.id;
3061
+ }
3062
+ };
3063
+ const removeIds = (model) => (entry) => removeIdsMut(model, cloneDeep(entry));
3064
+ const removeIdsMut = (model, entry) => {
3065
+ if (isNil(entry)) {
3066
+ return entry;
3067
+ }
3068
+ removeId(entry);
3069
+ _.forEach(model.attributes, (attr, attrName) => {
3070
+ const value = entry[attrName];
3071
+ if (attr.type === "dynamiczone" && isArray(value)) {
3072
+ value.forEach((compo) => {
3073
+ if (has("__component", compo)) {
3074
+ const model2 = strapi.components[compo.__component];
3075
+ removeIdsMut(model2, compo);
3076
+ }
3077
+ });
3078
+ } else if (attr.type === "component") {
3079
+ const model2 = strapi.components[attr.component];
3080
+ if (isArray(value)) {
3081
+ value.forEach((compo) => removeIdsMut(model2, compo));
3082
+ } else {
3083
+ removeIdsMut(model2, value);
3084
+ }
3085
+ }
3086
+ });
3087
+ return entry;
3088
+ };
3089
+ const copyNonLocalizedAttributes = (model, entry) => {
3090
+ const nonLocalizedAttributes = getNonLocalizedAttributes(model);
3091
+ return pipe(pick(nonLocalizedAttributes), removeIds(model))(entry);
3092
+ };
3093
+ const getLocalizedAttributes = (model) => {
3094
+ return getVisibleAttributes(model).filter(
3095
+ (attrName) => isLocalizedAttribute(model.attributes[attrName])
3096
+ );
3097
+ };
3098
+ const fillNonLocalizedAttributes = (entry, relatedEntry, { model }) => {
3099
+ if (isNil(relatedEntry)) {
3100
+ return;
3101
+ }
3102
+ const modelDef = strapi.getModel(model);
3103
+ const relatedEntryCopy = copyNonLocalizedAttributes(modelDef, relatedEntry);
3104
+ _.forEach(relatedEntryCopy, (value, field) => {
3105
+ if (isNil(entry[field])) {
3106
+ entry[field] = value;
3107
+ }
3108
+ });
3109
+ };
3110
+ const getNestedPopulateOfNonLocalizedAttributes = (modelUID) => {
3111
+ const schema2 = strapi.getModel(modelUID);
3112
+ const scalarAttributes = getScalarAttributes(schema2);
3113
+ const nonLocalizedAttributes = getNonLocalizedAttributes(schema2);
3114
+ const allAttributes = [...scalarAttributes, ...nonLocalizedAttributes];
3115
+ if (schema2.modelType === "component") {
3116
+ allAttributes.push(...getRelationalAttributes(schema2));
3117
+ }
3118
+ const currentAttributesToPopulate = allAttributes.filter((value, index2, self) => {
3119
+ return self.indexOf(value) === index2 && self.lastIndexOf(value) === index2;
3120
+ });
3121
+ const attributesToPopulate = [...currentAttributesToPopulate];
3122
+ for (const attrName of currentAttributesToPopulate) {
3123
+ const attr = schema2.attributes[attrName];
3124
+ if (attr.type === "component") {
3125
+ const nestedPopulate = getNestedPopulateOfNonLocalizedAttributes(attr.component).map(
3126
+ (nestedAttr) => `${attrName}.${nestedAttr}`
3127
+ );
3128
+ attributesToPopulate.push(...nestedPopulate);
3129
+ } else if (attr.type === "dynamiczone") {
3130
+ attr.components.forEach((componentName) => {
3131
+ const nestedPopulate = getNestedPopulateOfNonLocalizedAttributes(componentName).map(
3132
+ (nestedAttr) => `${attrName}.${nestedAttr}`
3133
+ );
3134
+ attributesToPopulate.push(...nestedPopulate);
3135
+ });
3136
+ }
3137
+ }
3138
+ return attributesToPopulate;
3139
+ };
3140
+ const contentTypes = () => ({
3141
+ isLocalizedContentType,
3142
+ getValidLocale,
3143
+ getLocalizedAttributes,
3144
+ getNonLocalizedAttributes,
3145
+ copyNonLocalizedAttributes,
3146
+ fillNonLocalizedAttributes,
3147
+ getNestedPopulateOfNonLocalizedAttributes
3148
+ });
3149
+ const LOCALIZATION_FIELDS = ["locale", "localizations"];
3150
+ const sanitize = ({ strapi: strapi2 }) => {
3151
+ const { isLocalizedContentType: isLocalizedContentType2 } = getService("content-types");
3152
+ const sanitizeLocalizationFields = curry(
3153
+ (schema2, entity) => traverseEntity(
3154
+ ({ key, schema: schema22 }, { remove }) => {
3155
+ const isLocalized = isLocalizedContentType2(schema22);
3156
+ const isLocalizationField = LOCALIZATION_FIELDS.includes(key);
3157
+ if (!isLocalized && isLocalizationField) {
3158
+ remove(key);
3159
+ }
3160
+ },
3161
+ { schema: schema2, getModel: strapi2.getModel.bind(strapi2) },
3162
+ entity
3163
+ )
3164
+ );
3165
+ return {
3166
+ sanitizeLocalizationFields
3167
+ };
3168
+ };
3169
+ const services = {
3170
+ permissions,
3171
+ metrics,
3172
+ localizations,
3173
+ locales,
3174
+ sanitize,
3175
+ "iso-locales": isoLocalesService,
3176
+ "content-types": contentTypes
3177
+ };
3178
+ const admin = {
3179
+ type: "admin",
3180
+ routes: [
3181
+ {
3182
+ method: "GET",
3183
+ path: "/iso-locales",
3184
+ handler: "iso-locales.listIsoLocales",
3185
+ config: {
3186
+ policies: [
3187
+ "admin::isAuthenticatedAdmin",
3188
+ {
3189
+ name: "plugin::content-manager.hasPermissions",
3190
+ config: { actions: ["plugin::i18n.locale.read"] }
3191
+ }
3192
+ ]
3193
+ }
3194
+ },
3195
+ {
3196
+ method: "GET",
3197
+ path: "/locales",
3198
+ handler: "locales.listLocales",
3199
+ config: {
3200
+ policies: ["admin::isAuthenticatedAdmin"]
3201
+ }
3202
+ },
3203
+ {
3204
+ method: "POST",
3205
+ path: "/locales",
3206
+ handler: "locales.createLocale",
3207
+ config: {
3208
+ policies: [
3209
+ "admin::isAuthenticatedAdmin",
3210
+ {
3211
+ name: "plugin::content-manager.hasPermissions",
3212
+ config: { actions: ["plugin::i18n.locale.create"] }
3213
+ }
3214
+ ]
3215
+ }
3216
+ },
3217
+ {
3218
+ method: "PUT",
3219
+ path: "/locales/:id",
3220
+ handler: "locales.updateLocale",
3221
+ config: {
3222
+ policies: [
3223
+ "admin::isAuthenticatedAdmin",
3224
+ {
3225
+ name: "plugin::content-manager.hasPermissions",
3226
+ config: { actions: ["plugin::i18n.locale.update"] }
3227
+ }
3228
+ ]
3229
+ }
3230
+ },
3231
+ {
3232
+ method: "DELETE",
3233
+ path: "/locales/:id",
3234
+ handler: "locales.deleteLocale",
3235
+ config: {
3236
+ policies: [
3237
+ "admin::isAuthenticatedAdmin",
3238
+ {
3239
+ name: "plugin::content-manager.hasPermissions",
3240
+ config: { actions: ["plugin::i18n.locale.delete"] }
3241
+ }
3242
+ ]
3243
+ }
3244
+ },
3245
+ {
3246
+ method: "POST",
3247
+ path: "/content-manager/actions/get-non-localized-fields",
3248
+ handler: "content-types.getNonLocalizedAttributes",
3249
+ config: {
3250
+ policies: ["admin::isAuthenticatedAdmin"]
3251
+ }
3252
+ }
3253
+ ]
3254
+ };
3255
+ const contentApi = {
3256
+ type: "content-api",
3257
+ routes: [
3258
+ {
3259
+ method: "GET",
3260
+ path: "/locales",
3261
+ handler: "locales.listLocales"
3262
+ }
3263
+ ]
3264
+ };
3265
+ const routes = {
3266
+ admin,
3267
+ "content-api": contentApi
3268
+ };
3269
+ const allowedLocaleCodes = isoLocales.map(prop("code"));
3270
+ const createLocaleSchema = yup.object().shape({
3271
+ name: yup.string().max(50).nullable(),
3272
+ code: yup.string().oneOf(allowedLocaleCodes).required(),
3273
+ isDefault: yup.boolean().required()
3274
+ }).noUnknown();
3275
+ const updateLocaleSchema = yup.object().shape({
3276
+ name: yup.string().min(1).max(50).nullable(),
3277
+ isDefault: yup.boolean()
3278
+ }).noUnknown();
3279
+ const validateCreateLocaleInput = validateYupSchema(createLocaleSchema);
3280
+ const validateUpdateLocaleInput = validateYupSchema(updateLocaleSchema);
3281
+ const formatLocale = (locale2) => {
3282
+ return {
3283
+ ...locale2,
3284
+ name: locale2.name || null
3285
+ };
3286
+ };
3287
+ const { setCreatorFields } = utils;
3288
+ const { ApplicationError: ApplicationError$1 } = utils.errors;
3289
+ const sanitizeLocale = (locale2) => {
3290
+ const model = strapi.getModel("plugin::i18n.locale");
3291
+ return strapi.contentAPI.sanitize.output(locale2, model);
3292
+ };
3293
+ const controller$2 = {
3294
+ async listLocales(ctx) {
3295
+ const localesService = getService("locales");
3296
+ const locales2 = await localesService.find();
3297
+ const sanitizedLocales = await sanitizeLocale(locales2);
3298
+ ctx.body = await localesService.setIsDefault(sanitizedLocales);
3299
+ },
3300
+ async createLocale(ctx) {
3301
+ const { user } = ctx.state;
3302
+ const body = ctx.request.body;
3303
+ const { isDefault, ...localeToCreate } = body;
3304
+ await validateCreateLocaleInput(body);
3305
+ const localesService = getService("locales");
3306
+ const existingLocale = await localesService.findByCode(body.code);
3307
+ if (existingLocale) {
3308
+ throw new ApplicationError$1("This locale already exists");
3309
+ }
3310
+ const localeToPersist = setCreatorFields({ user })(formatLocale(localeToCreate));
3311
+ const locale2 = await localesService.create(localeToPersist);
3312
+ if (isDefault) {
3313
+ await localesService.setDefaultLocale(locale2);
3314
+ }
3315
+ const sanitizedLocale = await sanitizeLocale(locale2);
3316
+ ctx.body = await localesService.setIsDefault(sanitizedLocale);
3317
+ },
3318
+ async updateLocale(ctx) {
3319
+ const { user } = ctx.state;
3320
+ const { id } = ctx.params;
3321
+ const body = ctx.request.body;
3322
+ const { isDefault, ...updates } = body;
3323
+ await validateUpdateLocaleInput(body);
3324
+ const localesService = getService("locales");
3325
+ const existingLocale = await localesService.findById(id);
3326
+ if (!existingLocale) {
3327
+ return ctx.notFound("locale.notFound");
3328
+ }
3329
+ const allowedParams = ["name"];
3330
+ const cleanUpdates = setCreatorFields({ user, isEdition: true })(pick(allowedParams, updates));
3331
+ const updatedLocale = await localesService.update({ id }, cleanUpdates);
3332
+ if (isDefault) {
3333
+ await localesService.setDefaultLocale(updatedLocale);
3334
+ }
3335
+ const sanitizedLocale = await sanitizeLocale(updatedLocale);
3336
+ ctx.body = await localesService.setIsDefault(sanitizedLocale);
3337
+ },
3338
+ async deleteLocale(ctx) {
3339
+ const { id } = ctx.params;
3340
+ const localesService = getService("locales");
3341
+ const existingLocale = await localesService.findById(id);
3342
+ if (!existingLocale) {
3343
+ return ctx.notFound("locale.notFound");
3344
+ }
3345
+ const defaultLocaleCode = await localesService.getDefaultLocale();
3346
+ if (existingLocale.code === defaultLocaleCode) {
3347
+ throw new ApplicationError$1("Cannot delete the default locale");
3348
+ }
3349
+ await localesService.delete({ id });
3350
+ const sanitizedLocale = await sanitizeLocale(existingLocale);
3351
+ ctx.body = await localesService.setIsDefault(sanitizedLocale);
3352
+ }
3353
+ };
3354
+ const validateGetNonLocalizedAttributesSchema = yup.object().shape({
3355
+ model: yup.string().required(),
3356
+ id: yup.mixed().when("model", {
3357
+ is: (model) => get("kind", strapi.contentType(model)) === "singleType",
3358
+ then: yup.strapiID().nullable(),
3359
+ otherwise: yup.strapiID().required()
3360
+ }),
3361
+ locale: yup.string().required()
3362
+ }).noUnknown().required();
3363
+ const validateGetNonLocalizedAttributesInput = validateYupSchema(
3364
+ validateGetNonLocalizedAttributesSchema
3365
+ );
3366
+ const { ApplicationError } = errors;
3367
+ const { PUBLISHED_AT_ATTRIBUTE } = contentTypes$2.constants;
3368
+ const getLocalesProperty = getOr([], "properties.locales");
3369
+ const getFieldsProperty = prop("properties.fields");
3370
+ const getFirstLevelPath = map((path) => path.split(".")[0]);
3371
+ const controller$1 = {
3372
+ async getNonLocalizedAttributes(ctx) {
3373
+ const { user } = ctx.state;
3374
+ const body = ctx.request.body;
3375
+ const { model, id, locale: locale2 } = body;
3376
+ await validateGetNonLocalizedAttributesInput({ model, id, locale: locale2 });
3377
+ const {
3378
+ copyNonLocalizedAttributes: copyNonLocalizedAttributes2,
3379
+ isLocalizedContentType: isLocalizedContentType2,
3380
+ getNestedPopulateOfNonLocalizedAttributes: getNestedPopulateOfNonLocalizedAttributes2
3381
+ } = getService("content-types");
3382
+ const {
3383
+ default: { READ_ACTION, CREATE_ACTION }
3384
+ } = strapi.service("admin::constants");
3385
+ const modelDef = strapi.contentType(model);
3386
+ const attributesToPopulate = getNestedPopulateOfNonLocalizedAttributes2(model);
3387
+ if (!isLocalizedContentType2(modelDef)) {
3388
+ throw new ApplicationError(`Model ${model} is not localized`);
3389
+ }
3390
+ const params = modelDef.kind === "singleType" ? {} : { id };
3391
+ const entity = await strapi.db.query(model).findOne({ where: params, populate: attributesToPopulate });
3392
+ if (!entity) {
3393
+ return ctx.notFound();
3394
+ }
3395
+ const permissions2 = await strapi.admin.services.permission.findMany({
3396
+ where: {
3397
+ action: [READ_ACTION, CREATE_ACTION],
3398
+ subject: model,
3399
+ role: {
3400
+ id: user.roles.map(prop("id"))
3401
+ }
3402
+ }
3403
+ });
3404
+ const localePermissions = permissions2.filter((perm) => getLocalesProperty(perm).includes(locale2)).map(getFieldsProperty);
3405
+ const permittedFields = pipe(flatten, getFirstLevelPath, uniq)(localePermissions);
3406
+ const nonLocalizedFields = copyNonLocalizedAttributes2(modelDef, entity);
3407
+ const sanitizedNonLocalizedFields = pick(permittedFields, nonLocalizedFields);
3408
+ const availableLocalesResult = await strapi.plugins["content-manager"].service("document-metadata").getMetadata(model, entity, {
3409
+ availableLocales: true
3410
+ });
3411
+ const availableLocales = availableLocalesResult.availableLocales.map(
3412
+ (localeResult) => pick(["id", "locale", PUBLISHED_AT_ATTRIBUTE], localeResult)
3413
+ );
3414
+ ctx.body = {
3415
+ nonLocalizedFields: sanitizedNonLocalizedFields,
3416
+ localizations: availableLocales.concat(
3417
+ pick(["id", "locale", PUBLISHED_AT_ATTRIBUTE], entity)
3418
+ )
3419
+ };
3420
+ }
3421
+ };
3422
+ const controller = {
3423
+ listIsoLocales(ctx) {
3424
+ const isoLocalesService2 = getService("iso-locales");
3425
+ ctx.body = isoLocalesService2.getIsoLocales();
3426
+ }
3427
+ };
3428
+ const controllers = {
3429
+ locales: controller$2,
3430
+ "iso-locales": controller,
3431
+ "content-types": controller$1
3432
+ };
3433
+ const index = () => ({
3434
+ register,
3435
+ bootstrap,
3436
+ routes,
3437
+ controllers,
3438
+ contentTypes: contentTypes$1,
3439
+ services
3440
+ });
3441
+ export {
3442
+ index as default
3443
+ };
3444
+ //# sourceMappingURL=index.mjs.map