@strapi/i18n 5.50.1 → 5.50.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/src/services/locales.d.ts +1 -1
- package/dist/admin/src/services/relations.d.ts +1 -1
- package/dist/admin/src/utils/schemas.d.ts +9 -9
- package/dist/admin/translations/ko.json.js +34 -1
- package/dist/admin/translations/ko.json.js.map +1 -1
- package/dist/admin/translations/ko.json.mjs +34 -1
- package/dist/admin/translations/ko.json.mjs.map +1 -1
- package/dist/server/services/ai-localizations.js.map +1 -1
- package/dist/server/services/ai-localizations.mjs.map +1 -1
- package/dist/server/src/controllers/index.d.ts +3 -3
- package/dist/server/src/index.d.ts +16 -16
- package/dist/server/src/routes/index.d.ts +1 -1
- package/dist/server/src/services/ai-localizations.d.ts.map +1 -1
- package/dist/server/src/services/fill-from-locale.d.ts +1 -1
- package/dist/server/src/services/index.d.ts +11 -11
- package/dist/server/src/services/sanitize/index.d.ts +1 -1
- package/package.json +15 -10
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { GetISOLocales } from '../../../shared/contracts/iso-locales';
|
|
2
2
|
import type { GetLocales, CreateLocale, DeleteLocale, UpdateLocale } from '../../../shared/contracts/locales';
|
|
3
|
-
declare const useCreateLocaleMutation: import("@reduxjs/toolkit/dist/query/react/buildHooks").UseMutation<import("@reduxjs/toolkit/query").MutationDefinition<Omit<import("../../../shared/contracts/locales").Locale, keyof import("../../../shared/contracts/shared").Entity>, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError | import("@reduxjs/toolkit").SerializedError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AiUsage" | "AiFeatureConfig" | "Locale" | "KeyStatistics" | "Settings" | "AILocalizationJobs", CreateLocale.Response, "adminApi">>, useDeleteLocaleMutation: import("@reduxjs/toolkit/dist/query/react/buildHooks").UseMutation<import("@reduxjs/toolkit/query").MutationDefinition<import("@strapi/types/dist/data").ID, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError | import("@reduxjs/toolkit").SerializedError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AiUsage" | "AiFeatureConfig" | "Locale" | "KeyStatistics" | "Settings" | "AILocalizationJobs", DeleteLocale.Response, "adminApi">>, useGetLocalesQuery: import("@reduxjs/toolkit/dist/query/react/buildHooks").UseQuery<import("@reduxjs/toolkit/query").QueryDefinition<void, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError | import("@reduxjs/toolkit").SerializedError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AiUsage" | "AiFeatureConfig" | "Locale" | "KeyStatistics" | "Settings" | "AILocalizationJobs", GetLocales.Response, "adminApi">>, useGetDefaultLocalesQuery: import("@reduxjs/toolkit/dist/query/react/buildHooks").UseQuery<import("@reduxjs/toolkit/query").QueryDefinition<void, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError | import("@reduxjs/toolkit").SerializedError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AiUsage" | "AiFeatureConfig" | "Locale" | "KeyStatistics" | "Settings" | "AILocalizationJobs", GetISOLocales.Response, "adminApi">>, useUpdateLocaleMutation: import("@reduxjs/toolkit/dist/query/react/buildHooks").UseMutation<import("@reduxjs/toolkit/query").MutationDefinition<Pick<import("../../../shared/contracts/locales").Locale, "name" | "isDefault"> & UpdateLocale.Params, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError | import("@reduxjs/toolkit").SerializedError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AiUsage" | "AiFeatureConfig" | "Locale" | "KeyStatistics" | "Settings" | "AILocalizationJobs", UpdateLocale.Response, "adminApi">>;
|
|
3
|
+
declare const useCreateLocaleMutation: import("@reduxjs/toolkit/dist/query/react/buildHooks").UseMutation<import("@reduxjs/toolkit/query").MutationDefinition<Omit<import("../../../shared/contracts/locales").Locale, keyof import("../../../shared/contracts/shared").Entity>, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError | import("@reduxjs/toolkit").SerializedError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AiUsage" | "AiFeatureConfig" | "Locale" | "KeyStatistics" | "Settings" | "AILocalizationJobs", CreateLocale.Response, "adminApi">>, useDeleteLocaleMutation: import("@reduxjs/toolkit/dist/query/react/buildHooks").UseMutation<import("@reduxjs/toolkit/query").MutationDefinition<import("@strapi/types/dist/data/constants.js").ID, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError | import("@reduxjs/toolkit").SerializedError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AiUsage" | "AiFeatureConfig" | "Locale" | "KeyStatistics" | "Settings" | "AILocalizationJobs", DeleteLocale.Response, "adminApi">>, useGetLocalesQuery: import("@reduxjs/toolkit/dist/query/react/buildHooks").UseQuery<import("@reduxjs/toolkit/query").QueryDefinition<void, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError | import("@reduxjs/toolkit").SerializedError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AiUsage" | "AiFeatureConfig" | "Locale" | "KeyStatistics" | "Settings" | "AILocalizationJobs", GetLocales.Response, "adminApi">>, useGetDefaultLocalesQuery: import("@reduxjs/toolkit/dist/query/react/buildHooks").UseQuery<import("@reduxjs/toolkit/query").QueryDefinition<void, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError | import("@reduxjs/toolkit").SerializedError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AiUsage" | "AiFeatureConfig" | "Locale" | "KeyStatistics" | "Settings" | "AILocalizationJobs", GetISOLocales.Response, "adminApi">>, useUpdateLocaleMutation: import("@reduxjs/toolkit/dist/query/react/buildHooks").UseMutation<import("@reduxjs/toolkit/query").MutationDefinition<Pick<import("../../../shared/contracts/locales").Locale, "name" | "isDefault"> & UpdateLocale.Params, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError | import("@reduxjs/toolkit").SerializedError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AiUsage" | "AiFeatureConfig" | "Locale" | "KeyStatistics" | "Settings" | "AILocalizationJobs", UpdateLocale.Response, "adminApi">>;
|
|
4
4
|
export { useCreateLocaleMutation, useDeleteLocaleMutation, useGetLocalesQuery, useGetDefaultLocalesQuery, useUpdateLocaleMutation, };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
declare const useGetManyDraftRelationCountQuery: import("@reduxjs/toolkit/dist/query/react/buildHooks").UseQuery<import("@reduxjs/toolkit/query").QueryDefinition<{
|
|
2
|
-
documentIds?: import("@strapi/types/dist/modules/documents").ID[];
|
|
2
|
+
documentIds?: import("@strapi/types/dist/modules/documents/index.js").ID[];
|
|
3
3
|
locale?: string | string[] | null;
|
|
4
4
|
} & {
|
|
5
5
|
model: string;
|
|
@@ -272,7 +272,7 @@ declare const mutateCTBContentTypeSchema: (nextSchema: {
|
|
|
272
272
|
private?: boolean | undefined;
|
|
273
273
|
writable?: boolean | undefined;
|
|
274
274
|
visible?: boolean | undefined;
|
|
275
|
-
default?: import("@strapi/types/dist/utils").JSONPrimitive | (() => import("@strapi/types/dist/utils").JSONPrimitive) | undefined;
|
|
275
|
+
default?: import("@strapi/types/dist/utils/json.js").JSONPrimitive | (() => import("@strapi/types/dist/utils/json.js").JSONPrimitive) | undefined;
|
|
276
276
|
} | {
|
|
277
277
|
type: "media";
|
|
278
278
|
pluginOptions?: object | undefined;
|
|
@@ -362,7 +362,7 @@ declare const mutateCTBContentTypeSchema: (nextSchema: {
|
|
|
362
362
|
} | import("json-logic-js").JsonLogicCat<import("json-logic-js").AdditionalOperation> | import("json-logic-js").JsonLogicSubstr<import("json-logic-js").AdditionalOperation> | import("json-logic-js").JsonLogicLog<import("json-logic-js").AdditionalOperation> | null;
|
|
363
363
|
} | undefined;
|
|
364
364
|
column?: Partial<Schema.Attribute.Column> | undefined;
|
|
365
|
-
target: import("@strapi/types/dist/uid").ContentType;
|
|
365
|
+
target: import("@strapi/types/dist/uid/index.js").ContentType;
|
|
366
366
|
inversedBy?: string | undefined;
|
|
367
367
|
mappedBy?: string | undefined;
|
|
368
368
|
configurable?: boolean | undefined;
|
|
@@ -384,7 +384,7 @@ declare const mutateCTBContentTypeSchema: (nextSchema: {
|
|
|
384
384
|
} | import("json-logic-js").JsonLogicCat<import("json-logic-js").AdditionalOperation> | import("json-logic-js").JsonLogicSubstr<import("json-logic-js").AdditionalOperation> | import("json-logic-js").JsonLogicLog<import("json-logic-js").AdditionalOperation> | null;
|
|
385
385
|
} | undefined;
|
|
386
386
|
column?: Partial<Schema.Attribute.Column> | undefined;
|
|
387
|
-
target: import("@strapi/types/dist/uid").ContentType;
|
|
387
|
+
target: import("@strapi/types/dist/uid/index.js").ContentType;
|
|
388
388
|
inversedBy?: string | undefined;
|
|
389
389
|
mappedBy?: string | undefined;
|
|
390
390
|
configurable?: boolean | undefined;
|
|
@@ -406,7 +406,7 @@ declare const mutateCTBContentTypeSchema: (nextSchema: {
|
|
|
406
406
|
} | import("json-logic-js").JsonLogicCat<import("json-logic-js").AdditionalOperation> | import("json-logic-js").JsonLogicSubstr<import("json-logic-js").AdditionalOperation> | import("json-logic-js").JsonLogicLog<import("json-logic-js").AdditionalOperation> | null;
|
|
407
407
|
} | undefined;
|
|
408
408
|
column?: Partial<Schema.Attribute.Column> | undefined;
|
|
409
|
-
target: import("@strapi/types/dist/uid").ContentType;
|
|
409
|
+
target: import("@strapi/types/dist/uid/index.js").ContentType;
|
|
410
410
|
inversedBy?: string | undefined;
|
|
411
411
|
mappedBy?: string | undefined;
|
|
412
412
|
configurable?: boolean | undefined;
|
|
@@ -428,7 +428,7 @@ declare const mutateCTBContentTypeSchema: (nextSchema: {
|
|
|
428
428
|
} | import("json-logic-js").JsonLogicCat<import("json-logic-js").AdditionalOperation> | import("json-logic-js").JsonLogicSubstr<import("json-logic-js").AdditionalOperation> | import("json-logic-js").JsonLogicLog<import("json-logic-js").AdditionalOperation> | null;
|
|
429
429
|
} | undefined;
|
|
430
430
|
column?: Partial<Schema.Attribute.Column> | undefined;
|
|
431
|
-
target: import("@strapi/types/dist/uid").ContentType;
|
|
431
|
+
target: import("@strapi/types/dist/uid/index.js").ContentType;
|
|
432
432
|
inversedBy?: string | undefined;
|
|
433
433
|
mappedBy?: string | undefined;
|
|
434
434
|
configurable?: boolean | undefined;
|
|
@@ -450,7 +450,7 @@ declare const mutateCTBContentTypeSchema: (nextSchema: {
|
|
|
450
450
|
} | import("json-logic-js").JsonLogicCat<import("json-logic-js").AdditionalOperation> | import("json-logic-js").JsonLogicSubstr<import("json-logic-js").AdditionalOperation> | import("json-logic-js").JsonLogicLog<import("json-logic-js").AdditionalOperation> | null;
|
|
451
451
|
} | undefined;
|
|
452
452
|
column?: Partial<Schema.Attribute.Column> | undefined;
|
|
453
|
-
target: import("@strapi/types/dist/uid").ContentType;
|
|
453
|
+
target: import("@strapi/types/dist/uid/index.js").ContentType;
|
|
454
454
|
configurable?: boolean | undefined;
|
|
455
455
|
private?: boolean | undefined;
|
|
456
456
|
writable?: boolean | undefined;
|
|
@@ -470,7 +470,7 @@ declare const mutateCTBContentTypeSchema: (nextSchema: {
|
|
|
470
470
|
} | import("json-logic-js").JsonLogicCat<import("json-logic-js").AdditionalOperation> | import("json-logic-js").JsonLogicSubstr<import("json-logic-js").AdditionalOperation> | import("json-logic-js").JsonLogicLog<import("json-logic-js").AdditionalOperation> | null;
|
|
471
471
|
} | undefined;
|
|
472
472
|
column?: Partial<Schema.Attribute.Column> | undefined;
|
|
473
|
-
target: import("@strapi/types/dist/uid").ContentType;
|
|
473
|
+
target: import("@strapi/types/dist/uid/index.js").ContentType;
|
|
474
474
|
configurable?: boolean | undefined;
|
|
475
475
|
private?: boolean | undefined;
|
|
476
476
|
writable?: boolean | undefined;
|
|
@@ -490,7 +490,7 @@ declare const mutateCTBContentTypeSchema: (nextSchema: {
|
|
|
490
490
|
} | import("json-logic-js").JsonLogicCat<import("json-logic-js").AdditionalOperation> | import("json-logic-js").JsonLogicSubstr<import("json-logic-js").AdditionalOperation> | import("json-logic-js").JsonLogicLog<import("json-logic-js").AdditionalOperation> | null;
|
|
491
491
|
} | undefined;
|
|
492
492
|
column?: Partial<Schema.Attribute.Column> | undefined;
|
|
493
|
-
target: import("@strapi/types/dist/uid").ContentType;
|
|
493
|
+
target: import("@strapi/types/dist/uid/index.js").ContentType;
|
|
494
494
|
morphBy?: string | undefined;
|
|
495
495
|
configurable?: boolean | undefined;
|
|
496
496
|
private?: boolean | undefined;
|
|
@@ -511,7 +511,7 @@ declare const mutateCTBContentTypeSchema: (nextSchema: {
|
|
|
511
511
|
} | import("json-logic-js").JsonLogicCat<import("json-logic-js").AdditionalOperation> | import("json-logic-js").JsonLogicSubstr<import("json-logic-js").AdditionalOperation> | import("json-logic-js").JsonLogicLog<import("json-logic-js").AdditionalOperation> | null;
|
|
512
512
|
} | undefined;
|
|
513
513
|
column?: Partial<Schema.Attribute.Column> | undefined;
|
|
514
|
-
target: import("@strapi/types/dist/uid").ContentType;
|
|
514
|
+
target: import("@strapi/types/dist/uid/index.js").ContentType;
|
|
515
515
|
morphBy?: string | undefined;
|
|
516
516
|
configurable?: boolean | undefined;
|
|
517
517
|
private?: boolean | undefined;
|
|
@@ -54,7 +54,40 @@ var ko = {
|
|
|
54
54
|
"plugin.schema.i18n.localized.description-content-type": "로케일별로 콘텐츠를 저장할 수 있습니다.",
|
|
55
55
|
"plugin.schema.i18n.localized.description-field": "필드는 각 로케일에서 서로 다른 값을 가질 수 있습니다.",
|
|
56
56
|
"plugin.schema.i18n.localized.label-content-type": "이 콘텐츠 타입의 지역화(localization) 켜기",
|
|
57
|
-
"plugin.schema.i18n.localized.label-field": "이 필드의 지역화(localization) 켜기"
|
|
57
|
+
"plugin.schema.i18n.localized.label-field": "이 필드의 지역화(localization) 켜기",
|
|
58
|
+
"actions.delete.label": "항목 삭제 ({locale})",
|
|
59
|
+
"actions.delete.dialog.title": "확인",
|
|
60
|
+
"actions.delete.dialog.body": "이 로케일을 삭제하시겠습니까?",
|
|
61
|
+
"actions.delete.error": "문서 로케일을 삭제하는 중 오류가 발생했습니다.",
|
|
62
|
+
"CMEditViewCopyLocale.cancel-text": "아니요, 취소합니다",
|
|
63
|
+
"CMEditViewCopyLocale.dialog.title": "확인",
|
|
64
|
+
"CMEditViewCopyLocale.dialog.body": "현재 콘텐츠가 삭제되고 선택한 로케일의 콘텐츠로 채워집니다:",
|
|
65
|
+
"CMEditViewCopyLocale.dialog.field.label": "로케일",
|
|
66
|
+
"CMEditViewCopyLocale.dialog.field.placeholder": "로케일을 선택하세요...",
|
|
67
|
+
"CMEditViewBulkLocale.publish-title": "여러 로케일 발행",
|
|
68
|
+
"CMEditViewBulkLocale.unpublish-title": "여러 로케일 발행 취소",
|
|
69
|
+
"CMEditViewBulkLocale.status": "상태",
|
|
70
|
+
"CMEditViewBulkLocale.publication-status": "발행 상태",
|
|
71
|
+
"CMEditViewBulkLocale.draft-relation-warning": "일부 로케일이 초안 항목과 연결되어 있습니다. 이를 발행하면 앱에서 링크가 깨질 수 있습니다.",
|
|
72
|
+
"CMEditViewBulkLocale.continue-confirmation": "계속하시겠습니까?",
|
|
73
|
+
"CMEditViewAITranslation.status-aria-label": "AI 번역 상태",
|
|
74
|
+
"CMEditViewAITranslation.status-title": "{enabled, select, true {AI 번역 사용 중} false {AI 번역 사용 안 함} other {AI 번역 사용 안 함}}",
|
|
75
|
+
"CMEditViewAITranslation.status-description": "기본 로케일에서 수정 사항을 저장할 때마다 AI가 모든 로케일의 콘텐츠를 번역합니다.",
|
|
76
|
+
"CMEditViewAITranslation.settings-link": "{enabled, select, true {설정에서 비활성화} false {설정에서 활성화} other {설정에서 활성화}}",
|
|
77
|
+
"CMEditViewAITranslation.job-completed": "AI 번역이 성공적으로 완료되었습니다!",
|
|
78
|
+
"CMEditViewAITranslation.job-failed": "AI 번역에 실패했습니다. 다시 시도해주세요.",
|
|
79
|
+
"CMEditViewLocalePicker.locale.create": "<bold>{locale}</bold> 로케일 생성",
|
|
80
|
+
"CMEditViewLocalePicker.locale.ai-translations": "AI 번역:",
|
|
81
|
+
"CMListView.popover.display-locales.more": "{locales} 외 {count}개",
|
|
82
|
+
"Settings.list.actions.publishAdditionalInfos": "활성 로케일 버전이 발행됩니다 <em>(국제화 플러그인 기준)</em>",
|
|
83
|
+
"Settings.list.actions.unpublishAdditionalInfos": "활성 로케일 버전이 발행 취소됩니다 <em>(국제화 플러그인 기준)</em>",
|
|
84
|
+
"Settings.aiLocalizations.label": "AI 번역",
|
|
85
|
+
"Settings.aiLocalizations.description": "콘텐츠 관리자에서 저장할 때마다 AI가 기본 로케일을 사용하여 다른 모든 로케일을 자동으로 번역합니다.",
|
|
86
|
+
"Settings.locales.default": "기본값",
|
|
87
|
+
"Settings.locales.modal.create.code.error": "로케일을 선택해주세요",
|
|
88
|
+
"Settings.locales.modal.create.name.error.min": "로케일 표시 이름은 50자 미만으로만 가능합니다.",
|
|
89
|
+
"Settings.locales.modal.create.name.error.required": "로케일 표시 이름을 입력해주세요",
|
|
90
|
+
"list-view.table.header.label": "사용 가능"
|
|
58
91
|
};
|
|
59
92
|
|
|
60
93
|
module.exports = ko;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ko.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ko.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -52,7 +52,40 @@ var ko = {
|
|
|
52
52
|
"plugin.schema.i18n.localized.description-content-type": "로케일별로 콘텐츠를 저장할 수 있습니다.",
|
|
53
53
|
"plugin.schema.i18n.localized.description-field": "필드는 각 로케일에서 서로 다른 값을 가질 수 있습니다.",
|
|
54
54
|
"plugin.schema.i18n.localized.label-content-type": "이 콘텐츠 타입의 지역화(localization) 켜기",
|
|
55
|
-
"plugin.schema.i18n.localized.label-field": "이 필드의 지역화(localization) 켜기"
|
|
55
|
+
"plugin.schema.i18n.localized.label-field": "이 필드의 지역화(localization) 켜기",
|
|
56
|
+
"actions.delete.label": "항목 삭제 ({locale})",
|
|
57
|
+
"actions.delete.dialog.title": "확인",
|
|
58
|
+
"actions.delete.dialog.body": "이 로케일을 삭제하시겠습니까?",
|
|
59
|
+
"actions.delete.error": "문서 로케일을 삭제하는 중 오류가 발생했습니다.",
|
|
60
|
+
"CMEditViewCopyLocale.cancel-text": "아니요, 취소합니다",
|
|
61
|
+
"CMEditViewCopyLocale.dialog.title": "확인",
|
|
62
|
+
"CMEditViewCopyLocale.dialog.body": "현재 콘텐츠가 삭제되고 선택한 로케일의 콘텐츠로 채워집니다:",
|
|
63
|
+
"CMEditViewCopyLocale.dialog.field.label": "로케일",
|
|
64
|
+
"CMEditViewCopyLocale.dialog.field.placeholder": "로케일을 선택하세요...",
|
|
65
|
+
"CMEditViewBulkLocale.publish-title": "여러 로케일 발행",
|
|
66
|
+
"CMEditViewBulkLocale.unpublish-title": "여러 로케일 발행 취소",
|
|
67
|
+
"CMEditViewBulkLocale.status": "상태",
|
|
68
|
+
"CMEditViewBulkLocale.publication-status": "발행 상태",
|
|
69
|
+
"CMEditViewBulkLocale.draft-relation-warning": "일부 로케일이 초안 항목과 연결되어 있습니다. 이를 발행하면 앱에서 링크가 깨질 수 있습니다.",
|
|
70
|
+
"CMEditViewBulkLocale.continue-confirmation": "계속하시겠습니까?",
|
|
71
|
+
"CMEditViewAITranslation.status-aria-label": "AI 번역 상태",
|
|
72
|
+
"CMEditViewAITranslation.status-title": "{enabled, select, true {AI 번역 사용 중} false {AI 번역 사용 안 함} other {AI 번역 사용 안 함}}",
|
|
73
|
+
"CMEditViewAITranslation.status-description": "기본 로케일에서 수정 사항을 저장할 때마다 AI가 모든 로케일의 콘텐츠를 번역합니다.",
|
|
74
|
+
"CMEditViewAITranslation.settings-link": "{enabled, select, true {설정에서 비활성화} false {설정에서 활성화} other {설정에서 활성화}}",
|
|
75
|
+
"CMEditViewAITranslation.job-completed": "AI 번역이 성공적으로 완료되었습니다!",
|
|
76
|
+
"CMEditViewAITranslation.job-failed": "AI 번역에 실패했습니다. 다시 시도해주세요.",
|
|
77
|
+
"CMEditViewLocalePicker.locale.create": "<bold>{locale}</bold> 로케일 생성",
|
|
78
|
+
"CMEditViewLocalePicker.locale.ai-translations": "AI 번역:",
|
|
79
|
+
"CMListView.popover.display-locales.more": "{locales} 외 {count}개",
|
|
80
|
+
"Settings.list.actions.publishAdditionalInfos": "활성 로케일 버전이 발행됩니다 <em>(국제화 플러그인 기준)</em>",
|
|
81
|
+
"Settings.list.actions.unpublishAdditionalInfos": "활성 로케일 버전이 발행 취소됩니다 <em>(국제화 플러그인 기준)</em>",
|
|
82
|
+
"Settings.aiLocalizations.label": "AI 번역",
|
|
83
|
+
"Settings.aiLocalizations.description": "콘텐츠 관리자에서 저장할 때마다 AI가 기본 로케일을 사용하여 다른 모든 로케일을 자동으로 번역합니다.",
|
|
84
|
+
"Settings.locales.default": "기본값",
|
|
85
|
+
"Settings.locales.modal.create.code.error": "로케일을 선택해주세요",
|
|
86
|
+
"Settings.locales.modal.create.name.error.min": "로케일 표시 이름은 50자 미만으로만 가능합니다.",
|
|
87
|
+
"Settings.locales.modal.create.name.error.required": "로케일 표시 이름을 입력해주세요",
|
|
88
|
+
"list-view.table.header.label": "사용 가능"
|
|
56
89
|
};
|
|
57
90
|
|
|
58
91
|
export { ko as default };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ko.json.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ko.json.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-localizations.js","sources":["../../../server/src/services/ai-localizations.ts"],"sourcesContent":["import type { Core, Modules, Schema, UID } from '@strapi/types';\nimport { traverseEntity } from '@strapi/utils';\nimport { getService } from '../utils';\n\nconst isLocalizedAttribute = (attribute: Schema.Attribute.Attribute | undefined): boolean => {\n return (attribute?.pluginOptions as any)?.i18n?.localized === true;\n};\n\nconst UNSUPPORTED_ATTRIBUTE_TYPES: Schema.Attribute.Kind[] = [\n 'media',\n 'relation',\n 'boolean',\n 'enumeration',\n];\n\nconst IGNORED_FIELDS = [\n 'id',\n 'documentId',\n 'createdAt',\n 'updatedAt',\n 'publishedAt',\n 'locale',\n 'updatedBy',\n 'createdBy',\n 'localizations',\n];\n\n/**\n * Deep merge where target values take priority over source values.\n * Arrays are merged by index to align repeatable component / dynamic zone items.\n */\nconst deepMerge = (\n source: Record<string, any>,\n target: Record<string, any>\n): Record<string, any> => {\n const result = { ...source };\n\n for (const key of Object.keys(target)) {\n const sourceVal = source[key];\n const targetVal = target[key];\n\n if (Array.isArray(targetVal) && Array.isArray(sourceVal)) {\n result[key] = targetVal.map((item, i) => {\n if (item && typeof item === 'object' && sourceVal[i] && typeof sourceVal[i] === 'object') {\n return deepMerge(sourceVal[i], item);\n }\n return item;\n });\n } else if (\n targetVal &&\n typeof targetVal === 'object' &&\n !Array.isArray(targetVal) &&\n sourceVal &&\n typeof sourceVal === 'object' &&\n !Array.isArray(sourceVal)\n ) {\n result[key] = deepMerge(sourceVal, targetVal);\n } else {\n result[key] = targetVal;\n }\n }\n\n return result;\n};\n\n/**\n * Merges unsupported field types (media, boolean, enumeration, relation)\n * from a source document into the target data object.\n *\n * Uses traverseEntity to walk the source document and extract only unsupported fields,\n * then deep-merges the AI-translated target data on top so translated values take priority.\n */\nconst mergeUnsupportedFields = async (\n targetData: Record<string, any>,\n sourceDoc: Record<string, any> | null,\n schema: Schema.Schema,\n getModel: (uid: UID.Schema) => Schema.Schema | undefined\n): Promise<Record<string, any>> => {\n if (!sourceDoc) {\n return targetData;\n }\n\n // Track paths of relation/media fields so traverseEntity's recursion\n // into those fields doesn't strip internal fields like `id` or `url`.\n const preservedPaths = new Set<string>();\n\n // Use traverseEntity to extract only unsupported fields from the source document.\n // traverseEntity handles component and dynamic zone recursion automatically.\n const unsupportedFieldsOnly = await traverseEntity(\n ({ key, attribute, path }, { remove }) => {\n // If we're inside a relation or media subtree, preserve everything.\n // Use path-based prefix check instead of parent-based check because\n // traverseEntity mutates `parent` across siblings at the same level,\n // which would incorrectly mark sibling fields as inside a preserved subtree.\n const isInsidePreservedSubtree =\n path.raw && Array.from(preservedPaths).some((pp) => path.raw!.startsWith(`${pp}.`));\n if (isInsidePreservedSubtree) {\n preservedPaths.add(path.raw!);\n return;\n }\n\n if (IGNORED_FIELDS.includes(key)) {\n remove(key);\n return;\n }\n\n // Keep fields with no schema attribute (e.g. __component in dynamic zones)\n if (!attribute) {\n return;\n }\n\n // Mark relation and media subtrees as preserved so their internal\n // fields (id, url, etc.) are not removed during recursion\n if (attribute.type === 'media' || attribute.type === 'relation') {\n preservedPaths.add(path.raw!);\n return;\n }\n\n // Keep other unsupported attribute types (boolean, enumeration)\n if (UNSUPPORTED_ATTRIBUTE_TYPES.includes(attribute.type)) {\n return;\n }\n\n // Keep components and dynamic zones — traverseEntity recurses into them\n if (attribute.type === 'component' || attribute.type === 'dynamiczone') {\n return;\n }\n\n // Remove supported (translatable) fields\n remove(key);\n },\n { schema, getModel: getModel as (uid: string) => Schema.Schema },\n sourceDoc\n );\n\n // Deep merge: AI-translated target takes priority over source unsupported fields\n return deepMerge(unsupportedFieldsOnly, targetData);\n};\n\nconst createAILocalizationsService = ({ strapi }: { strapi: Core.Strapi }) => {\n // TODO: add a helper function to get the AI server URL\n const aiServerUrl = process.env.STRAPI_AI_URL || 'https://strapi-ai.apps.strapi.io';\n const aiLocalizationJobsService = getService('ai-localization-jobs');\n\n return {\n // Async to avoid changing the signature later (there will be a db check in the future)\n async isEnabled() {\n if (strapi.ai.admin.isEnabled() === false) {\n return false;\n }\n const settings = getService('settings');\n const aiSettings = await settings.getSettings();\n return aiSettings?.aiLocalizations === true;\n },\n\n /**\n * Checks if there are localizations that need to be generated for the given document,\n * and if so, calls the AI service and saves the results to the database.\n * Works for both single and collection types, on create and update.\n */\n async generateDocumentLocalizations({\n model,\n document,\n }: {\n model: UID.ContentType;\n document: Modules.Documents.AnyDocument;\n }) {\n const isFeatureEnabled = await this.isEnabled();\n if (!isFeatureEnabled) {\n return;\n }\n\n const schema = strapi.getModel(model);\n const localeService = getService('locales');\n\n // No localizations needed for content types with i18n disabled\n const isLocalizedContentType = getService('content-types').isLocalizedContentType(schema);\n if (!isLocalizedContentType) {\n return;\n }\n\n // Don't trigger localizations if the update is on a derived locale, only do it on the default\n const defaultLocale = await localeService.getDefaultLocale();\n if (document?.locale !== defaultLocale) {\n return;\n }\n\n const documentId = document.documentId;\n\n if (!documentId) {\n strapi.log.warn(`AI Localizations: missing documentId for ${schema.uid}`);\n return;\n }\n\n const localizedRoots = new Set();\n\n const translateableContent = await traverseEntity(\n ({ key, attribute, parent, path }, { remove }) => {\n if (IGNORED_FIELDS.includes(key)) {\n remove(key);\n return;\n }\n const hasLocalizedOption = attribute && isLocalizedAttribute(attribute);\n if (attribute && UNSUPPORTED_ATTRIBUTE_TYPES.includes(attribute.type)) {\n remove(key);\n return;\n }\n\n // If this field is localized, keep it (and mark as localized root if component/dz)\n if (hasLocalizedOption) {\n // If it's a component/dynamiczone, add to the set\n if (['component', 'dynamiczone'].includes(attribute.type)) {\n localizedRoots.add(path.raw);\n }\n return; // keep\n }\n\n if (parent && localizedRoots.has(parent.path.raw)) {\n // If parent exists in the localized roots set, keep it\n // If this is also a component/dz, propagate the localized root flag\n if (['component', 'dynamiczone'].includes(attribute?.type ?? '')) {\n localizedRoots.add(path.raw);\n }\n return; // keep\n }\n\n // Otherwise, remove the field\n remove(key);\n },\n { schema, getModel: strapi.getModel.bind(strapi) },\n document\n );\n\n if (Object.keys(translateableContent).length === 0) {\n strapi.log.info(\n `AI Localizations: no translatable content for ${schema.uid} document ${documentId}`\n );\n return;\n }\n\n const localesList = await localeService.find();\n const targetLocales = localesList\n .filter((l) => l.code !== document.locale)\n .map((l) => l.code);\n\n if (targetLocales.length === 0) {\n strapi.log.info(\n `AI Localizations: no target locales for ${schema.uid} document ${documentId}`\n );\n return;\n }\n\n await aiLocalizationJobsService.upsertJobForDocument({\n contentType: model,\n documentId,\n sourceLocale: document.locale,\n targetLocales,\n status: 'processing',\n });\n\n let token: string;\n try {\n const tokenData = await strapi.ai.admin.getAiToken();\n token = tokenData.token;\n } catch (error) {\n await aiLocalizationJobsService.upsertJobForDocument({\n documentId,\n contentType: model,\n sourceLocale: document.locale,\n targetLocales,\n status: 'failed',\n });\n throw new Error('Failed to retrieve AI token', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n /**\n * Provide a schema to the LLM so that we can give it instructions about how to handle each\n * type of attribute. Only keep essential schema data to avoid cluttering the context.\n * Ignore fields that don't need to be localized.\n * TODO: also provide a schema of all the referenced components\n */\n const minimalContentTypeSchema = Object.fromEntries(\n Object.entries(schema.attributes)\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n .filter(([_, attr]) => {\n const isLocalized = isLocalizedAttribute(attr);\n const isSupportedType = !UNSUPPORTED_ATTRIBUTE_TYPES.includes(attr.type);\n return isLocalized && isSupportedType;\n })\n .map(([key, attr]) => {\n const minimalAttribute = { type: attr.type };\n if (attr.type === 'component') {\n (\n minimalAttribute as Schema.Attribute.Component<`${string}.${string}`, boolean>\n ).repeatable = attr.repeatable ?? false;\n }\n return [key, minimalAttribute];\n })\n );\n\n strapi.log.http('Contacting AI Server for localizations generation');\n const response = await fetch(`${aiServerUrl}/i18n/generate-localizations`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({\n content: translateableContent,\n sourceLocale: document.locale,\n targetLocales,\n contentTypeSchema: minimalContentTypeSchema,\n }),\n });\n\n if (!response.ok) {\n strapi.log.error(\n `AI Localizations request failed: ${response.status} ${response.statusText}`\n );\n\n await aiLocalizationJobsService.upsertJobForDocument({\n documentId,\n contentType: model,\n sourceLocale: document.locale,\n targetLocales,\n status: 'failed',\n });\n\n throw new Error(`AI Localizations request failed: ${response.statusText}`);\n }\n\n const aiResult = await response.json();\n\n // Use populate-builder service for deep populate to fetch all nested fields\n const populateBuilderService = strapi.plugin('content-manager').service('populate-builder');\n // @ts-expect-error - populate-builder service returns a callable function\n const deepPopulate = await populateBuilderService(model).populateDeep(Infinity).build();\n const getModelBound = strapi.getModel.bind(strapi);\n\n // Fetch the source document with all fields populated (for new locales that don't exist yet)\n const sourceDocWithAllFields = await strapi.documents(model).findOne({\n documentId,\n locale: document.locale,\n populate: deepPopulate,\n });\n\n try {\n await Promise.all(\n aiResult.localizations.map(async (localization: any) => {\n const { content, locale } = localization;\n\n // Fetch the existing derived locale document with all fields populated\n const derivedDoc = await strapi.documents(model).findOne({\n documentId,\n locale,\n populate: deepPopulate,\n });\n\n // Start with AI-translated content\n let mergedData = structuredClone(content);\n\n // Merge unsupported fields from existing derived doc (if exists) or source doc\n // This preserves media, booleans, enumerations, and relations at all levels\n const sourceForUnsupportedFields = derivedDoc || sourceDocWithAllFields;\n mergedData = await mergeUnsupportedFields(\n mergedData,\n sourceForUnsupportedFields,\n schema,\n getModelBound\n );\n\n await strapi.documents(model).update({\n documentId,\n locale,\n fields: [],\n data: mergedData,\n });\n\n await aiLocalizationJobsService.upsertJobForDocument({\n documentId,\n contentType: model,\n sourceLocale: document.locale,\n targetLocales,\n status: 'completed',\n });\n })\n );\n } catch (error) {\n await aiLocalizationJobsService.upsertJobForDocument({\n documentId,\n contentType: model,\n sourceLocale: document.locale,\n targetLocales,\n status: 'failed',\n });\n strapi.log.error('AI Localizations generation failed', error);\n }\n },\n setupMiddleware() {\n strapi.documents.use(async (context, next) => {\n const result = await next();\n\n // Only trigger for the allowed actions\n if (!['create', 'update'].includes(context.action)) {\n return result;\n }\n\n // Check if AI localizations are enabled before triggering\n const isEnabled = await this.isEnabled();\n if (!isEnabled) {\n return result;\n }\n\n // Don't await since localizations should be done in the background without blocking the request\n strapi\n .plugin('i18n')\n .service('ai-localizations')\n .generateDocumentLocalizations({\n model: context.contentType.uid,\n document: result,\n })\n .catch((error: any) => {\n strapi.log.error('AI Localizations generation failed', error);\n });\n\n return result;\n });\n },\n };\n};\n\nexport { createAILocalizationsService, mergeUnsupportedFields };\n"],"names":["isLocalizedAttribute","attribute","pluginOptions","i18n","localized","UNSUPPORTED_ATTRIBUTE_TYPES","IGNORED_FIELDS","deepMerge","source","target","result","key","Object","keys","sourceVal","targetVal","Array","isArray","map","item","i","mergeUnsupportedFields","targetData","sourceDoc","schema","getModel","preservedPaths","Set","unsupportedFieldsOnly","traverseEntity","path","remove","isInsidePreservedSubtree","raw","from","some","pp","startsWith","add","includes","type","createAILocalizationsService","strapi","aiServerUrl","process","env","STRAPI_AI_URL","aiLocalizationJobsService","getService","isEnabled","ai","admin","settings","aiSettings","getSettings","aiLocalizations","generateDocumentLocalizations","model","document","isFeatureEnabled","localeService","isLocalizedContentType","defaultLocale","getDefaultLocale","locale","documentId","log","warn","uid","localizedRoots","translateableContent","parent","hasLocalizedOption","has","bind","length","info","localesList","find","targetLocales","filter","l","code","upsertJobForDocument","contentType","sourceLocale","status","token","tokenData","getAiToken","error","Error","cause","undefined","minimalContentTypeSchema","fromEntries","entries","attributes","_","attr","isLocalized","isSupportedType","minimalAttribute","repeatable","http","response","fetch","method","headers","Authorization","body","JSON","stringify","content","contentTypeSchema","ok","statusText","aiResult","json","populateBuilderService","plugin","service","deepPopulate","populateDeep","Infinity","build","getModelBound","sourceDocWithAllFields","documents","findOne","populate","Promise","all","localizations","localization","derivedDoc","mergedData","structuredClone","sourceForUnsupportedFields","update","fields","data","setupMiddleware","use","context","next","action","catch"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ai-localizations.js","sources":["../../../server/src/services/ai-localizations.ts"],"sourcesContent":["import type { Core, Modules, Schema, UID } from '@strapi/types';\nimport { traverseEntity } from '@strapi/utils';\nimport { getService } from '../utils';\n\nconst isLocalizedAttribute = (attribute: Schema.Attribute.Attribute | undefined): boolean => {\n return (attribute?.pluginOptions as any)?.i18n?.localized === true;\n};\n\nconst UNSUPPORTED_ATTRIBUTE_TYPES: Schema.Attribute.Kind[] = [\n 'media',\n 'relation',\n 'boolean',\n 'enumeration',\n];\n\nconst IGNORED_FIELDS = [\n 'id',\n 'documentId',\n 'createdAt',\n 'updatedAt',\n 'publishedAt',\n 'locale',\n 'updatedBy',\n 'createdBy',\n 'localizations',\n];\n\n/**\n * Deep merge where target values take priority over source values.\n * Arrays are merged by index to align repeatable component / dynamic zone items.\n */\nconst deepMerge = (\n source: Record<string, any>,\n target: Record<string, any>\n): Record<string, any> => {\n const result = { ...source };\n\n for (const key of Object.keys(target)) {\n const sourceVal = source[key];\n const targetVal = target[key];\n\n if (Array.isArray(targetVal) && Array.isArray(sourceVal)) {\n result[key] = targetVal.map((item, i) => {\n if (item && typeof item === 'object' && sourceVal[i] && typeof sourceVal[i] === 'object') {\n return deepMerge(sourceVal[i], item);\n }\n return item;\n });\n } else if (\n targetVal &&\n typeof targetVal === 'object' &&\n !Array.isArray(targetVal) &&\n sourceVal &&\n typeof sourceVal === 'object' &&\n !Array.isArray(sourceVal)\n ) {\n result[key] = deepMerge(sourceVal, targetVal);\n } else {\n result[key] = targetVal;\n }\n }\n\n return result;\n};\n\n/**\n * Merges unsupported field types (media, boolean, enumeration, relation)\n * from a source document into the target data object.\n *\n * Uses traverseEntity to walk the source document and extract only unsupported fields,\n * then deep-merges the AI-translated target data on top so translated values take priority.\n */\nconst mergeUnsupportedFields = async (\n targetData: Record<string, any>,\n sourceDoc: Record<string, any> | null,\n schema: Schema.Schema,\n getModel: (uid: UID.Schema) => Schema.Schema | undefined\n): Promise<Record<string, any>> => {\n if (!sourceDoc) {\n return targetData;\n }\n\n // Track paths of relation/media fields so traverseEntity's recursion\n // into those fields doesn't strip internal fields like `id` or `url`.\n const preservedPaths = new Set<string>();\n\n // Use traverseEntity to extract only unsupported fields from the source document.\n // traverseEntity handles component and dynamic zone recursion automatically.\n const unsupportedFieldsOnly = await traverseEntity(\n ({ key, attribute, path }, { remove }) => {\n // If we're inside a relation or media subtree, preserve everything.\n // Use path-based prefix check instead of parent-based check because\n // traverseEntity mutates `parent` across siblings at the same level,\n // which would incorrectly mark sibling fields as inside a preserved subtree.\n const isInsidePreservedSubtree =\n path.raw && Array.from(preservedPaths).some((pp) => path.raw!.startsWith(`${pp}.`));\n if (isInsidePreservedSubtree) {\n preservedPaths.add(path.raw!);\n return;\n }\n\n if (IGNORED_FIELDS.includes(key)) {\n remove(key);\n return;\n }\n\n // Keep fields with no schema attribute (e.g. __component in dynamic zones)\n if (!attribute) {\n return;\n }\n\n // Mark relation and media subtrees as preserved so their internal\n // fields (id, url, etc.) are not removed during recursion\n if (attribute.type === 'media' || attribute.type === 'relation') {\n preservedPaths.add(path.raw!);\n return;\n }\n\n // Keep other unsupported attribute types (boolean, enumeration)\n if (UNSUPPORTED_ATTRIBUTE_TYPES.includes(attribute.type)) {\n return;\n }\n\n // Keep components and dynamic zones — traverseEntity recurses into them\n if (attribute.type === 'component' || attribute.type === 'dynamiczone') {\n return;\n }\n\n // Remove supported (translatable) fields\n remove(key);\n },\n { schema, getModel: getModel as (uid: string) => Schema.Schema },\n sourceDoc\n );\n\n // Deep merge: AI-translated target takes priority over source unsupported fields\n return deepMerge(unsupportedFieldsOnly, targetData);\n};\n\nconst createAILocalizationsService = ({ strapi }: { strapi: Core.Strapi }) => {\n // TODO: add a helper function to get the AI server URL\n const aiServerUrl = process.env.STRAPI_AI_URL || 'https://strapi-ai.apps.strapi.io';\n const aiLocalizationJobsService = getService('ai-localization-jobs');\n\n return {\n // Async to avoid changing the signature later (there will be a db check in the future)\n async isEnabled() {\n if (strapi.ai.admin.isEnabled() === false) {\n return false;\n }\n const settings = getService('settings');\n const aiSettings = await settings.getSettings();\n return aiSettings?.aiLocalizations === true;\n },\n\n /**\n * Checks if there are localizations that need to be generated for the given document,\n * and if so, calls the AI service and saves the results to the database.\n * Works for both single and collection types, on create and update.\n */\n async generateDocumentLocalizations({\n model,\n document,\n }: {\n model: UID.ContentType;\n document: Modules.Documents.AnyDocument;\n }) {\n const isFeatureEnabled = await this.isEnabled();\n if (!isFeatureEnabled) {\n return;\n }\n\n const schema = strapi.getModel(model);\n const localeService = getService('locales');\n\n // No localizations needed for content types with i18n disabled\n const isLocalizedContentType = getService('content-types').isLocalizedContentType(schema);\n if (!isLocalizedContentType) {\n return;\n }\n\n // Don't trigger localizations if the update is on a derived locale, only do it on the default\n const defaultLocale = await localeService.getDefaultLocale();\n if (document?.locale !== defaultLocale) {\n return;\n }\n\n const documentId = document.documentId;\n\n if (!documentId) {\n strapi.log.warn(`AI Localizations: missing documentId for ${schema.uid}`);\n return;\n }\n\n const localizedRoots = new Set();\n\n const translateableContent = await traverseEntity(\n ({ key, attribute, parent, path }, { remove }) => {\n if (IGNORED_FIELDS.includes(key)) {\n remove(key);\n return;\n }\n const hasLocalizedOption = attribute && isLocalizedAttribute(attribute);\n if (attribute && UNSUPPORTED_ATTRIBUTE_TYPES.includes(attribute.type)) {\n remove(key);\n return;\n }\n\n // If this field is localized, keep it (and mark as localized root if component/dz)\n if (hasLocalizedOption) {\n // If it's a component/dynamiczone, add to the set\n if (['component', 'dynamiczone'].includes(attribute.type)) {\n localizedRoots.add(path.raw);\n }\n return; // keep\n }\n\n if (parent && localizedRoots.has(parent.path.raw)) {\n // If parent exists in the localized roots set, keep it\n // If this is also a component/dz, propagate the localized root flag\n if (['component', 'dynamiczone'].includes(attribute?.type ?? '')) {\n localizedRoots.add(path.raw);\n }\n return; // keep\n }\n\n // Otherwise, remove the field\n remove(key);\n },\n { schema, getModel: strapi.getModel.bind(strapi) },\n document\n );\n\n if (Object.keys(translateableContent).length === 0) {\n strapi.log.info(\n `AI Localizations: no translatable content for ${schema.uid} document ${documentId}`\n );\n return;\n }\n\n const localesList = await localeService.find();\n const targetLocales = localesList\n .filter((l) => l.code !== document.locale)\n .map((l) => l.code);\n\n if (targetLocales.length === 0) {\n strapi.log.info(\n `AI Localizations: no target locales for ${schema.uid} document ${documentId}`\n );\n return;\n }\n\n await aiLocalizationJobsService.upsertJobForDocument({\n contentType: model,\n documentId,\n sourceLocale: document.locale,\n targetLocales,\n status: 'processing',\n });\n\n let token: string;\n try {\n const tokenData = await strapi.ai.admin.getAiToken();\n token = tokenData.token;\n } catch (error) {\n await aiLocalizationJobsService.upsertJobForDocument({\n documentId,\n contentType: model,\n sourceLocale: document.locale,\n targetLocales,\n status: 'failed',\n });\n throw new Error('Failed to retrieve AI token', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n /**\n * Provide a schema to the LLM so that we can give it instructions about how to handle each\n * type of attribute. Only keep essential schema data to avoid cluttering the context.\n * Ignore fields that don't need to be localized.\n * TODO: also provide a schema of all the referenced components\n */\n const minimalContentTypeSchema = Object.fromEntries(\n Object.entries(schema.attributes)\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n .filter(([_, attr]) => {\n const isLocalized = isLocalizedAttribute(attr);\n const isSupportedType = !UNSUPPORTED_ATTRIBUTE_TYPES.includes(attr.type);\n return isLocalized && isSupportedType;\n })\n .map(([key, attr]) => {\n const minimalAttribute = { type: attr.type };\n if (attr.type === 'component') {\n (\n minimalAttribute as Schema.Attribute.Component<`${string}.${string}`, boolean>\n ).repeatable = attr.repeatable ?? false;\n }\n return [key, minimalAttribute];\n })\n );\n\n strapi.log.http('Contacting AI Server for localizations generation');\n const response = await fetch(`${aiServerUrl}/i18n/generate-localizations`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({\n content: translateableContent,\n sourceLocale: document.locale,\n targetLocales,\n contentTypeSchema: minimalContentTypeSchema,\n }),\n });\n\n if (!response.ok) {\n strapi.log.error(\n `AI Localizations request failed: ${response.status} ${response.statusText}`\n );\n\n await aiLocalizationJobsService.upsertJobForDocument({\n documentId,\n contentType: model,\n sourceLocale: document.locale,\n targetLocales,\n status: 'failed',\n });\n\n throw new Error(`AI Localizations request failed: ${response.statusText}`);\n }\n\n const aiResult = (await response.json()) as {\n localizations: Array<{ content: Record<string, unknown>; locale: string }>;\n };\n\n // Use populate-builder service for deep populate to fetch all nested fields\n const populateBuilderService = strapi.plugin('content-manager').service('populate-builder');\n // @ts-expect-error - populate-builder service returns a callable function\n const deepPopulate = await populateBuilderService(model).populateDeep(Infinity).build();\n const getModelBound = strapi.getModel.bind(strapi);\n\n // Fetch the source document with all fields populated (for new locales that don't exist yet)\n const sourceDocWithAllFields = await strapi.documents(model).findOne({\n documentId,\n locale: document.locale,\n populate: deepPopulate,\n });\n\n try {\n await Promise.all(\n aiResult.localizations.map(async (localization: any) => {\n const { content, locale } = localization;\n\n // Fetch the existing derived locale document with all fields populated\n const derivedDoc = await strapi.documents(model).findOne({\n documentId,\n locale,\n populate: deepPopulate,\n });\n\n // Start with AI-translated content\n let mergedData = structuredClone(content);\n\n // Merge unsupported fields from existing derived doc (if exists) or source doc\n // This preserves media, booleans, enumerations, and relations at all levels\n const sourceForUnsupportedFields = derivedDoc || sourceDocWithAllFields;\n mergedData = await mergeUnsupportedFields(\n mergedData,\n sourceForUnsupportedFields,\n schema,\n getModelBound\n );\n\n await strapi.documents(model).update({\n documentId,\n locale,\n fields: [],\n data: mergedData,\n });\n\n await aiLocalizationJobsService.upsertJobForDocument({\n documentId,\n contentType: model,\n sourceLocale: document.locale,\n targetLocales,\n status: 'completed',\n });\n })\n );\n } catch (error) {\n await aiLocalizationJobsService.upsertJobForDocument({\n documentId,\n contentType: model,\n sourceLocale: document.locale,\n targetLocales,\n status: 'failed',\n });\n strapi.log.error('AI Localizations generation failed', error);\n }\n },\n setupMiddleware() {\n strapi.documents.use(async (context, next) => {\n const result = await next();\n\n // Only trigger for the allowed actions\n if (!['create', 'update'].includes(context.action)) {\n return result;\n }\n\n // Check if AI localizations are enabled before triggering\n const isEnabled = await this.isEnabled();\n if (!isEnabled) {\n return result;\n }\n\n // Don't await since localizations should be done in the background without blocking the request\n strapi\n .plugin('i18n')\n .service('ai-localizations')\n .generateDocumentLocalizations({\n model: context.contentType.uid,\n document: result,\n })\n .catch((error: any) => {\n strapi.log.error('AI Localizations generation failed', error);\n });\n\n return result;\n });\n },\n };\n};\n\nexport { createAILocalizationsService, mergeUnsupportedFields };\n"],"names":["isLocalizedAttribute","attribute","pluginOptions","i18n","localized","UNSUPPORTED_ATTRIBUTE_TYPES","IGNORED_FIELDS","deepMerge","source","target","result","key","Object","keys","sourceVal","targetVal","Array","isArray","map","item","i","mergeUnsupportedFields","targetData","sourceDoc","schema","getModel","preservedPaths","Set","unsupportedFieldsOnly","traverseEntity","path","remove","isInsidePreservedSubtree","raw","from","some","pp","startsWith","add","includes","type","createAILocalizationsService","strapi","aiServerUrl","process","env","STRAPI_AI_URL","aiLocalizationJobsService","getService","isEnabled","ai","admin","settings","aiSettings","getSettings","aiLocalizations","generateDocumentLocalizations","model","document","isFeatureEnabled","localeService","isLocalizedContentType","defaultLocale","getDefaultLocale","locale","documentId","log","warn","uid","localizedRoots","translateableContent","parent","hasLocalizedOption","has","bind","length","info","localesList","find","targetLocales","filter","l","code","upsertJobForDocument","contentType","sourceLocale","status","token","tokenData","getAiToken","error","Error","cause","undefined","minimalContentTypeSchema","fromEntries","entries","attributes","_","attr","isLocalized","isSupportedType","minimalAttribute","repeatable","http","response","fetch","method","headers","Authorization","body","JSON","stringify","content","contentTypeSchema","ok","statusText","aiResult","json","populateBuilderService","plugin","service","deepPopulate","populateDeep","Infinity","build","getModelBound","sourceDocWithAllFields","documents","findOne","populate","Promise","all","localizations","localization","derivedDoc","mergedData","structuredClone","sourceForUnsupportedFields","update","fields","data","setupMiddleware","use","context","next","action","catch"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-localizations.mjs","sources":["../../../server/src/services/ai-localizations.ts"],"sourcesContent":["import type { Core, Modules, Schema, UID } from '@strapi/types';\nimport { traverseEntity } from '@strapi/utils';\nimport { getService } from '../utils';\n\nconst isLocalizedAttribute = (attribute: Schema.Attribute.Attribute | undefined): boolean => {\n return (attribute?.pluginOptions as any)?.i18n?.localized === true;\n};\n\nconst UNSUPPORTED_ATTRIBUTE_TYPES: Schema.Attribute.Kind[] = [\n 'media',\n 'relation',\n 'boolean',\n 'enumeration',\n];\n\nconst IGNORED_FIELDS = [\n 'id',\n 'documentId',\n 'createdAt',\n 'updatedAt',\n 'publishedAt',\n 'locale',\n 'updatedBy',\n 'createdBy',\n 'localizations',\n];\n\n/**\n * Deep merge where target values take priority over source values.\n * Arrays are merged by index to align repeatable component / dynamic zone items.\n */\nconst deepMerge = (\n source: Record<string, any>,\n target: Record<string, any>\n): Record<string, any> => {\n const result = { ...source };\n\n for (const key of Object.keys(target)) {\n const sourceVal = source[key];\n const targetVal = target[key];\n\n if (Array.isArray(targetVal) && Array.isArray(sourceVal)) {\n result[key] = targetVal.map((item, i) => {\n if (item && typeof item === 'object' && sourceVal[i] && typeof sourceVal[i] === 'object') {\n return deepMerge(sourceVal[i], item);\n }\n return item;\n });\n } else if (\n targetVal &&\n typeof targetVal === 'object' &&\n !Array.isArray(targetVal) &&\n sourceVal &&\n typeof sourceVal === 'object' &&\n !Array.isArray(sourceVal)\n ) {\n result[key] = deepMerge(sourceVal, targetVal);\n } else {\n result[key] = targetVal;\n }\n }\n\n return result;\n};\n\n/**\n * Merges unsupported field types (media, boolean, enumeration, relation)\n * from a source document into the target data object.\n *\n * Uses traverseEntity to walk the source document and extract only unsupported fields,\n * then deep-merges the AI-translated target data on top so translated values take priority.\n */\nconst mergeUnsupportedFields = async (\n targetData: Record<string, any>,\n sourceDoc: Record<string, any> | null,\n schema: Schema.Schema,\n getModel: (uid: UID.Schema) => Schema.Schema | undefined\n): Promise<Record<string, any>> => {\n if (!sourceDoc) {\n return targetData;\n }\n\n // Track paths of relation/media fields so traverseEntity's recursion\n // into those fields doesn't strip internal fields like `id` or `url`.\n const preservedPaths = new Set<string>();\n\n // Use traverseEntity to extract only unsupported fields from the source document.\n // traverseEntity handles component and dynamic zone recursion automatically.\n const unsupportedFieldsOnly = await traverseEntity(\n ({ key, attribute, path }, { remove }) => {\n // If we're inside a relation or media subtree, preserve everything.\n // Use path-based prefix check instead of parent-based check because\n // traverseEntity mutates `parent` across siblings at the same level,\n // which would incorrectly mark sibling fields as inside a preserved subtree.\n const isInsidePreservedSubtree =\n path.raw && Array.from(preservedPaths).some((pp) => path.raw!.startsWith(`${pp}.`));\n if (isInsidePreservedSubtree) {\n preservedPaths.add(path.raw!);\n return;\n }\n\n if (IGNORED_FIELDS.includes(key)) {\n remove(key);\n return;\n }\n\n // Keep fields with no schema attribute (e.g. __component in dynamic zones)\n if (!attribute) {\n return;\n }\n\n // Mark relation and media subtrees as preserved so their internal\n // fields (id, url, etc.) are not removed during recursion\n if (attribute.type === 'media' || attribute.type === 'relation') {\n preservedPaths.add(path.raw!);\n return;\n }\n\n // Keep other unsupported attribute types (boolean, enumeration)\n if (UNSUPPORTED_ATTRIBUTE_TYPES.includes(attribute.type)) {\n return;\n }\n\n // Keep components and dynamic zones — traverseEntity recurses into them\n if (attribute.type === 'component' || attribute.type === 'dynamiczone') {\n return;\n }\n\n // Remove supported (translatable) fields\n remove(key);\n },\n { schema, getModel: getModel as (uid: string) => Schema.Schema },\n sourceDoc\n );\n\n // Deep merge: AI-translated target takes priority over source unsupported fields\n return deepMerge(unsupportedFieldsOnly, targetData);\n};\n\nconst createAILocalizationsService = ({ strapi }: { strapi: Core.Strapi }) => {\n // TODO: add a helper function to get the AI server URL\n const aiServerUrl = process.env.STRAPI_AI_URL || 'https://strapi-ai.apps.strapi.io';\n const aiLocalizationJobsService = getService('ai-localization-jobs');\n\n return {\n // Async to avoid changing the signature later (there will be a db check in the future)\n async isEnabled() {\n if (strapi.ai.admin.isEnabled() === false) {\n return false;\n }\n const settings = getService('settings');\n const aiSettings = await settings.getSettings();\n return aiSettings?.aiLocalizations === true;\n },\n\n /**\n * Checks if there are localizations that need to be generated for the given document,\n * and if so, calls the AI service and saves the results to the database.\n * Works for both single and collection types, on create and update.\n */\n async generateDocumentLocalizations({\n model,\n document,\n }: {\n model: UID.ContentType;\n document: Modules.Documents.AnyDocument;\n }) {\n const isFeatureEnabled = await this.isEnabled();\n if (!isFeatureEnabled) {\n return;\n }\n\n const schema = strapi.getModel(model);\n const localeService = getService('locales');\n\n // No localizations needed for content types with i18n disabled\n const isLocalizedContentType = getService('content-types').isLocalizedContentType(schema);\n if (!isLocalizedContentType) {\n return;\n }\n\n // Don't trigger localizations if the update is on a derived locale, only do it on the default\n const defaultLocale = await localeService.getDefaultLocale();\n if (document?.locale !== defaultLocale) {\n return;\n }\n\n const documentId = document.documentId;\n\n if (!documentId) {\n strapi.log.warn(`AI Localizations: missing documentId for ${schema.uid}`);\n return;\n }\n\n const localizedRoots = new Set();\n\n const translateableContent = await traverseEntity(\n ({ key, attribute, parent, path }, { remove }) => {\n if (IGNORED_FIELDS.includes(key)) {\n remove(key);\n return;\n }\n const hasLocalizedOption = attribute && isLocalizedAttribute(attribute);\n if (attribute && UNSUPPORTED_ATTRIBUTE_TYPES.includes(attribute.type)) {\n remove(key);\n return;\n }\n\n // If this field is localized, keep it (and mark as localized root if component/dz)\n if (hasLocalizedOption) {\n // If it's a component/dynamiczone, add to the set\n if (['component', 'dynamiczone'].includes(attribute.type)) {\n localizedRoots.add(path.raw);\n }\n return; // keep\n }\n\n if (parent && localizedRoots.has(parent.path.raw)) {\n // If parent exists in the localized roots set, keep it\n // If this is also a component/dz, propagate the localized root flag\n if (['component', 'dynamiczone'].includes(attribute?.type ?? '')) {\n localizedRoots.add(path.raw);\n }\n return; // keep\n }\n\n // Otherwise, remove the field\n remove(key);\n },\n { schema, getModel: strapi.getModel.bind(strapi) },\n document\n );\n\n if (Object.keys(translateableContent).length === 0) {\n strapi.log.info(\n `AI Localizations: no translatable content for ${schema.uid} document ${documentId}`\n );\n return;\n }\n\n const localesList = await localeService.find();\n const targetLocales = localesList\n .filter((l) => l.code !== document.locale)\n .map((l) => l.code);\n\n if (targetLocales.length === 0) {\n strapi.log.info(\n `AI Localizations: no target locales for ${schema.uid} document ${documentId}`\n );\n return;\n }\n\n await aiLocalizationJobsService.upsertJobForDocument({\n contentType: model,\n documentId,\n sourceLocale: document.locale,\n targetLocales,\n status: 'processing',\n });\n\n let token: string;\n try {\n const tokenData = await strapi.ai.admin.getAiToken();\n token = tokenData.token;\n } catch (error) {\n await aiLocalizationJobsService.upsertJobForDocument({\n documentId,\n contentType: model,\n sourceLocale: document.locale,\n targetLocales,\n status: 'failed',\n });\n throw new Error('Failed to retrieve AI token', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n /**\n * Provide a schema to the LLM so that we can give it instructions about how to handle each\n * type of attribute. Only keep essential schema data to avoid cluttering the context.\n * Ignore fields that don't need to be localized.\n * TODO: also provide a schema of all the referenced components\n */\n const minimalContentTypeSchema = Object.fromEntries(\n Object.entries(schema.attributes)\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n .filter(([_, attr]) => {\n const isLocalized = isLocalizedAttribute(attr);\n const isSupportedType = !UNSUPPORTED_ATTRIBUTE_TYPES.includes(attr.type);\n return isLocalized && isSupportedType;\n })\n .map(([key, attr]) => {\n const minimalAttribute = { type: attr.type };\n if (attr.type === 'component') {\n (\n minimalAttribute as Schema.Attribute.Component<`${string}.${string}`, boolean>\n ).repeatable = attr.repeatable ?? false;\n }\n return [key, minimalAttribute];\n })\n );\n\n strapi.log.http('Contacting AI Server for localizations generation');\n const response = await fetch(`${aiServerUrl}/i18n/generate-localizations`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({\n content: translateableContent,\n sourceLocale: document.locale,\n targetLocales,\n contentTypeSchema: minimalContentTypeSchema,\n }),\n });\n\n if (!response.ok) {\n strapi.log.error(\n `AI Localizations request failed: ${response.status} ${response.statusText}`\n );\n\n await aiLocalizationJobsService.upsertJobForDocument({\n documentId,\n contentType: model,\n sourceLocale: document.locale,\n targetLocales,\n status: 'failed',\n });\n\n throw new Error(`AI Localizations request failed: ${response.statusText}`);\n }\n\n const aiResult = await response.json();\n\n // Use populate-builder service for deep populate to fetch all nested fields\n const populateBuilderService = strapi.plugin('content-manager').service('populate-builder');\n // @ts-expect-error - populate-builder service returns a callable function\n const deepPopulate = await populateBuilderService(model).populateDeep(Infinity).build();\n const getModelBound = strapi.getModel.bind(strapi);\n\n // Fetch the source document with all fields populated (for new locales that don't exist yet)\n const sourceDocWithAllFields = await strapi.documents(model).findOne({\n documentId,\n locale: document.locale,\n populate: deepPopulate,\n });\n\n try {\n await Promise.all(\n aiResult.localizations.map(async (localization: any) => {\n const { content, locale } = localization;\n\n // Fetch the existing derived locale document with all fields populated\n const derivedDoc = await strapi.documents(model).findOne({\n documentId,\n locale,\n populate: deepPopulate,\n });\n\n // Start with AI-translated content\n let mergedData = structuredClone(content);\n\n // Merge unsupported fields from existing derived doc (if exists) or source doc\n // This preserves media, booleans, enumerations, and relations at all levels\n const sourceForUnsupportedFields = derivedDoc || sourceDocWithAllFields;\n mergedData = await mergeUnsupportedFields(\n mergedData,\n sourceForUnsupportedFields,\n schema,\n getModelBound\n );\n\n await strapi.documents(model).update({\n documentId,\n locale,\n fields: [],\n data: mergedData,\n });\n\n await aiLocalizationJobsService.upsertJobForDocument({\n documentId,\n contentType: model,\n sourceLocale: document.locale,\n targetLocales,\n status: 'completed',\n });\n })\n );\n } catch (error) {\n await aiLocalizationJobsService.upsertJobForDocument({\n documentId,\n contentType: model,\n sourceLocale: document.locale,\n targetLocales,\n status: 'failed',\n });\n strapi.log.error('AI Localizations generation failed', error);\n }\n },\n setupMiddleware() {\n strapi.documents.use(async (context, next) => {\n const result = await next();\n\n // Only trigger for the allowed actions\n if (!['create', 'update'].includes(context.action)) {\n return result;\n }\n\n // Check if AI localizations are enabled before triggering\n const isEnabled = await this.isEnabled();\n if (!isEnabled) {\n return result;\n }\n\n // Don't await since localizations should be done in the background without blocking the request\n strapi\n .plugin('i18n')\n .service('ai-localizations')\n .generateDocumentLocalizations({\n model: context.contentType.uid,\n document: result,\n })\n .catch((error: any) => {\n strapi.log.error('AI Localizations generation failed', error);\n });\n\n return result;\n });\n },\n };\n};\n\nexport { createAILocalizationsService, mergeUnsupportedFields };\n"],"names":["isLocalizedAttribute","attribute","pluginOptions","i18n","localized","UNSUPPORTED_ATTRIBUTE_TYPES","IGNORED_FIELDS","deepMerge","source","target","result","key","Object","keys","sourceVal","targetVal","Array","isArray","map","item","i","mergeUnsupportedFields","targetData","sourceDoc","schema","getModel","preservedPaths","Set","unsupportedFieldsOnly","traverseEntity","path","remove","isInsidePreservedSubtree","raw","from","some","pp","startsWith","add","includes","type","createAILocalizationsService","strapi","aiServerUrl","process","env","STRAPI_AI_URL","aiLocalizationJobsService","getService","isEnabled","ai","admin","settings","aiSettings","getSettings","aiLocalizations","generateDocumentLocalizations","model","document","isFeatureEnabled","localeService","isLocalizedContentType","defaultLocale","getDefaultLocale","locale","documentId","log","warn","uid","localizedRoots","translateableContent","parent","hasLocalizedOption","has","bind","length","info","localesList","find","targetLocales","filter","l","code","upsertJobForDocument","contentType","sourceLocale","status","token","tokenData","getAiToken","error","Error","cause","undefined","minimalContentTypeSchema","fromEntries","entries","attributes","_","attr","isLocalized","isSupportedType","minimalAttribute","repeatable","http","response","fetch","method","headers","Authorization","body","JSON","stringify","content","contentTypeSchema","ok","statusText","aiResult","json","populateBuilderService","plugin","service","deepPopulate","populateDeep","Infinity","build","getModelBound","sourceDocWithAllFields","documents","findOne","populate","Promise","all","localizations","localization","derivedDoc","mergedData","structuredClone","sourceForUnsupportedFields","update","fields","data","setupMiddleware","use","context","next","action","catch"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ai-localizations.mjs","sources":["../../../server/src/services/ai-localizations.ts"],"sourcesContent":["import type { Core, Modules, Schema, UID } from '@strapi/types';\nimport { traverseEntity } from '@strapi/utils';\nimport { getService } from '../utils';\n\nconst isLocalizedAttribute = (attribute: Schema.Attribute.Attribute | undefined): boolean => {\n return (attribute?.pluginOptions as any)?.i18n?.localized === true;\n};\n\nconst UNSUPPORTED_ATTRIBUTE_TYPES: Schema.Attribute.Kind[] = [\n 'media',\n 'relation',\n 'boolean',\n 'enumeration',\n];\n\nconst IGNORED_FIELDS = [\n 'id',\n 'documentId',\n 'createdAt',\n 'updatedAt',\n 'publishedAt',\n 'locale',\n 'updatedBy',\n 'createdBy',\n 'localizations',\n];\n\n/**\n * Deep merge where target values take priority over source values.\n * Arrays are merged by index to align repeatable component / dynamic zone items.\n */\nconst deepMerge = (\n source: Record<string, any>,\n target: Record<string, any>\n): Record<string, any> => {\n const result = { ...source };\n\n for (const key of Object.keys(target)) {\n const sourceVal = source[key];\n const targetVal = target[key];\n\n if (Array.isArray(targetVal) && Array.isArray(sourceVal)) {\n result[key] = targetVal.map((item, i) => {\n if (item && typeof item === 'object' && sourceVal[i] && typeof sourceVal[i] === 'object') {\n return deepMerge(sourceVal[i], item);\n }\n return item;\n });\n } else if (\n targetVal &&\n typeof targetVal === 'object' &&\n !Array.isArray(targetVal) &&\n sourceVal &&\n typeof sourceVal === 'object' &&\n !Array.isArray(sourceVal)\n ) {\n result[key] = deepMerge(sourceVal, targetVal);\n } else {\n result[key] = targetVal;\n }\n }\n\n return result;\n};\n\n/**\n * Merges unsupported field types (media, boolean, enumeration, relation)\n * from a source document into the target data object.\n *\n * Uses traverseEntity to walk the source document and extract only unsupported fields,\n * then deep-merges the AI-translated target data on top so translated values take priority.\n */\nconst mergeUnsupportedFields = async (\n targetData: Record<string, any>,\n sourceDoc: Record<string, any> | null,\n schema: Schema.Schema,\n getModel: (uid: UID.Schema) => Schema.Schema | undefined\n): Promise<Record<string, any>> => {\n if (!sourceDoc) {\n return targetData;\n }\n\n // Track paths of relation/media fields so traverseEntity's recursion\n // into those fields doesn't strip internal fields like `id` or `url`.\n const preservedPaths = new Set<string>();\n\n // Use traverseEntity to extract only unsupported fields from the source document.\n // traverseEntity handles component and dynamic zone recursion automatically.\n const unsupportedFieldsOnly = await traverseEntity(\n ({ key, attribute, path }, { remove }) => {\n // If we're inside a relation or media subtree, preserve everything.\n // Use path-based prefix check instead of parent-based check because\n // traverseEntity mutates `parent` across siblings at the same level,\n // which would incorrectly mark sibling fields as inside a preserved subtree.\n const isInsidePreservedSubtree =\n path.raw && Array.from(preservedPaths).some((pp) => path.raw!.startsWith(`${pp}.`));\n if (isInsidePreservedSubtree) {\n preservedPaths.add(path.raw!);\n return;\n }\n\n if (IGNORED_FIELDS.includes(key)) {\n remove(key);\n return;\n }\n\n // Keep fields with no schema attribute (e.g. __component in dynamic zones)\n if (!attribute) {\n return;\n }\n\n // Mark relation and media subtrees as preserved so their internal\n // fields (id, url, etc.) are not removed during recursion\n if (attribute.type === 'media' || attribute.type === 'relation') {\n preservedPaths.add(path.raw!);\n return;\n }\n\n // Keep other unsupported attribute types (boolean, enumeration)\n if (UNSUPPORTED_ATTRIBUTE_TYPES.includes(attribute.type)) {\n return;\n }\n\n // Keep components and dynamic zones — traverseEntity recurses into them\n if (attribute.type === 'component' || attribute.type === 'dynamiczone') {\n return;\n }\n\n // Remove supported (translatable) fields\n remove(key);\n },\n { schema, getModel: getModel as (uid: string) => Schema.Schema },\n sourceDoc\n );\n\n // Deep merge: AI-translated target takes priority over source unsupported fields\n return deepMerge(unsupportedFieldsOnly, targetData);\n};\n\nconst createAILocalizationsService = ({ strapi }: { strapi: Core.Strapi }) => {\n // TODO: add a helper function to get the AI server URL\n const aiServerUrl = process.env.STRAPI_AI_URL || 'https://strapi-ai.apps.strapi.io';\n const aiLocalizationJobsService = getService('ai-localization-jobs');\n\n return {\n // Async to avoid changing the signature later (there will be a db check in the future)\n async isEnabled() {\n if (strapi.ai.admin.isEnabled() === false) {\n return false;\n }\n const settings = getService('settings');\n const aiSettings = await settings.getSettings();\n return aiSettings?.aiLocalizations === true;\n },\n\n /**\n * Checks if there are localizations that need to be generated for the given document,\n * and if so, calls the AI service and saves the results to the database.\n * Works for both single and collection types, on create and update.\n */\n async generateDocumentLocalizations({\n model,\n document,\n }: {\n model: UID.ContentType;\n document: Modules.Documents.AnyDocument;\n }) {\n const isFeatureEnabled = await this.isEnabled();\n if (!isFeatureEnabled) {\n return;\n }\n\n const schema = strapi.getModel(model);\n const localeService = getService('locales');\n\n // No localizations needed for content types with i18n disabled\n const isLocalizedContentType = getService('content-types').isLocalizedContentType(schema);\n if (!isLocalizedContentType) {\n return;\n }\n\n // Don't trigger localizations if the update is on a derived locale, only do it on the default\n const defaultLocale = await localeService.getDefaultLocale();\n if (document?.locale !== defaultLocale) {\n return;\n }\n\n const documentId = document.documentId;\n\n if (!documentId) {\n strapi.log.warn(`AI Localizations: missing documentId for ${schema.uid}`);\n return;\n }\n\n const localizedRoots = new Set();\n\n const translateableContent = await traverseEntity(\n ({ key, attribute, parent, path }, { remove }) => {\n if (IGNORED_FIELDS.includes(key)) {\n remove(key);\n return;\n }\n const hasLocalizedOption = attribute && isLocalizedAttribute(attribute);\n if (attribute && UNSUPPORTED_ATTRIBUTE_TYPES.includes(attribute.type)) {\n remove(key);\n return;\n }\n\n // If this field is localized, keep it (and mark as localized root if component/dz)\n if (hasLocalizedOption) {\n // If it's a component/dynamiczone, add to the set\n if (['component', 'dynamiczone'].includes(attribute.type)) {\n localizedRoots.add(path.raw);\n }\n return; // keep\n }\n\n if (parent && localizedRoots.has(parent.path.raw)) {\n // If parent exists in the localized roots set, keep it\n // If this is also a component/dz, propagate the localized root flag\n if (['component', 'dynamiczone'].includes(attribute?.type ?? '')) {\n localizedRoots.add(path.raw);\n }\n return; // keep\n }\n\n // Otherwise, remove the field\n remove(key);\n },\n { schema, getModel: strapi.getModel.bind(strapi) },\n document\n );\n\n if (Object.keys(translateableContent).length === 0) {\n strapi.log.info(\n `AI Localizations: no translatable content for ${schema.uid} document ${documentId}`\n );\n return;\n }\n\n const localesList = await localeService.find();\n const targetLocales = localesList\n .filter((l) => l.code !== document.locale)\n .map((l) => l.code);\n\n if (targetLocales.length === 0) {\n strapi.log.info(\n `AI Localizations: no target locales for ${schema.uid} document ${documentId}`\n );\n return;\n }\n\n await aiLocalizationJobsService.upsertJobForDocument({\n contentType: model,\n documentId,\n sourceLocale: document.locale,\n targetLocales,\n status: 'processing',\n });\n\n let token: string;\n try {\n const tokenData = await strapi.ai.admin.getAiToken();\n token = tokenData.token;\n } catch (error) {\n await aiLocalizationJobsService.upsertJobForDocument({\n documentId,\n contentType: model,\n sourceLocale: document.locale,\n targetLocales,\n status: 'failed',\n });\n throw new Error('Failed to retrieve AI token', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n /**\n * Provide a schema to the LLM so that we can give it instructions about how to handle each\n * type of attribute. Only keep essential schema data to avoid cluttering the context.\n * Ignore fields that don't need to be localized.\n * TODO: also provide a schema of all the referenced components\n */\n const minimalContentTypeSchema = Object.fromEntries(\n Object.entries(schema.attributes)\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n .filter(([_, attr]) => {\n const isLocalized = isLocalizedAttribute(attr);\n const isSupportedType = !UNSUPPORTED_ATTRIBUTE_TYPES.includes(attr.type);\n return isLocalized && isSupportedType;\n })\n .map(([key, attr]) => {\n const minimalAttribute = { type: attr.type };\n if (attr.type === 'component') {\n (\n minimalAttribute as Schema.Attribute.Component<`${string}.${string}`, boolean>\n ).repeatable = attr.repeatable ?? false;\n }\n return [key, minimalAttribute];\n })\n );\n\n strapi.log.http('Contacting AI Server for localizations generation');\n const response = await fetch(`${aiServerUrl}/i18n/generate-localizations`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({\n content: translateableContent,\n sourceLocale: document.locale,\n targetLocales,\n contentTypeSchema: minimalContentTypeSchema,\n }),\n });\n\n if (!response.ok) {\n strapi.log.error(\n `AI Localizations request failed: ${response.status} ${response.statusText}`\n );\n\n await aiLocalizationJobsService.upsertJobForDocument({\n documentId,\n contentType: model,\n sourceLocale: document.locale,\n targetLocales,\n status: 'failed',\n });\n\n throw new Error(`AI Localizations request failed: ${response.statusText}`);\n }\n\n const aiResult = (await response.json()) as {\n localizations: Array<{ content: Record<string, unknown>; locale: string }>;\n };\n\n // Use populate-builder service for deep populate to fetch all nested fields\n const populateBuilderService = strapi.plugin('content-manager').service('populate-builder');\n // @ts-expect-error - populate-builder service returns a callable function\n const deepPopulate = await populateBuilderService(model).populateDeep(Infinity).build();\n const getModelBound = strapi.getModel.bind(strapi);\n\n // Fetch the source document with all fields populated (for new locales that don't exist yet)\n const sourceDocWithAllFields = await strapi.documents(model).findOne({\n documentId,\n locale: document.locale,\n populate: deepPopulate,\n });\n\n try {\n await Promise.all(\n aiResult.localizations.map(async (localization: any) => {\n const { content, locale } = localization;\n\n // Fetch the existing derived locale document with all fields populated\n const derivedDoc = await strapi.documents(model).findOne({\n documentId,\n locale,\n populate: deepPopulate,\n });\n\n // Start with AI-translated content\n let mergedData = structuredClone(content);\n\n // Merge unsupported fields from existing derived doc (if exists) or source doc\n // This preserves media, booleans, enumerations, and relations at all levels\n const sourceForUnsupportedFields = derivedDoc || sourceDocWithAllFields;\n mergedData = await mergeUnsupportedFields(\n mergedData,\n sourceForUnsupportedFields,\n schema,\n getModelBound\n );\n\n await strapi.documents(model).update({\n documentId,\n locale,\n fields: [],\n data: mergedData,\n });\n\n await aiLocalizationJobsService.upsertJobForDocument({\n documentId,\n contentType: model,\n sourceLocale: document.locale,\n targetLocales,\n status: 'completed',\n });\n })\n );\n } catch (error) {\n await aiLocalizationJobsService.upsertJobForDocument({\n documentId,\n contentType: model,\n sourceLocale: document.locale,\n targetLocales,\n status: 'failed',\n });\n strapi.log.error('AI Localizations generation failed', error);\n }\n },\n setupMiddleware() {\n strapi.documents.use(async (context, next) => {\n const result = await next();\n\n // Only trigger for the allowed actions\n if (!['create', 'update'].includes(context.action)) {\n return result;\n }\n\n // Check if AI localizations are enabled before triggering\n const isEnabled = await this.isEnabled();\n if (!isEnabled) {\n return result;\n }\n\n // Don't await since localizations should be done in the background without blocking the request\n strapi\n .plugin('i18n')\n .service('ai-localizations')\n .generateDocumentLocalizations({\n model: context.contentType.uid,\n document: result,\n })\n .catch((error: any) => {\n strapi.log.error('AI Localizations generation failed', error);\n });\n\n return result;\n });\n },\n };\n};\n\nexport { createAILocalizationsService, mergeUnsupportedFields };\n"],"names":["isLocalizedAttribute","attribute","pluginOptions","i18n","localized","UNSUPPORTED_ATTRIBUTE_TYPES","IGNORED_FIELDS","deepMerge","source","target","result","key","Object","keys","sourceVal","targetVal","Array","isArray","map","item","i","mergeUnsupportedFields","targetData","sourceDoc","schema","getModel","preservedPaths","Set","unsupportedFieldsOnly","traverseEntity","path","remove","isInsidePreservedSubtree","raw","from","some","pp","startsWith","add","includes","type","createAILocalizationsService","strapi","aiServerUrl","process","env","STRAPI_AI_URL","aiLocalizationJobsService","getService","isEnabled","ai","admin","settings","aiSettings","getSettings","aiLocalizations","generateDocumentLocalizations","model","document","isFeatureEnabled","localeService","isLocalizedContentType","defaultLocale","getDefaultLocale","locale","documentId","log","warn","uid","localizedRoots","translateableContent","parent","hasLocalizedOption","has","bind","length","info","localesList","find","targetLocales","filter","l","code","upsertJobForDocument","contentType","sourceLocale","status","token","tokenData","getAiToken","error","Error","cause","undefined","minimalContentTypeSchema","fromEntries","entries","attributes","_","attr","isLocalized","isSupportedType","minimalAttribute","repeatable","http","response","fetch","method","headers","Authorization","body","JSON","stringify","content","contentTypeSchema","ok","statusText","aiResult","json","populateBuilderService","plugin","service","deepPopulate","populateDeep","Infinity","build","getModelBound","sourceDocWithAllFields","documents","findOne","populate","Promise","all","localizations","localization","derivedDoc","mergedData","structuredClone","sourceForUnsupportedFields","update","fields","data","setupMiddleware","use","context","next","action","catch"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
declare const _default: {
|
|
2
|
-
locales: import("@strapi/types/dist/core").Controller;
|
|
3
|
-
'iso-locales': import("@strapi/types/dist/core").Controller;
|
|
2
|
+
locales: import("@strapi/types/dist/core/controller.js").Controller;
|
|
3
|
+
'iso-locales': import("@strapi/types/dist/core/controller.js").Controller;
|
|
4
4
|
'content-types': {
|
|
5
5
|
getNonLocalizedAttributes(ctx: import("koa").Context): Promise<any>;
|
|
6
6
|
getFillFromLocaleData(ctx: import("koa").Context): Promise<any>;
|
|
@@ -10,7 +10,7 @@ declare const _default: {
|
|
|
10
10
|
getSettings(ctx: import("koa").Context): Promise<void>;
|
|
11
11
|
};
|
|
12
12
|
'ai-localization-jobs': ({ strapi }: {
|
|
13
|
-
strapi: import("@strapi/types/dist/core").Strapi;
|
|
13
|
+
strapi: import("@strapi/types/dist/core/strapi.js").Strapi;
|
|
14
14
|
}) => {
|
|
15
15
|
getJobForSingleType(ctx: any): Promise<any>;
|
|
16
16
|
getJobForCollectionType(ctx: any): Promise<any>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
declare const _default: () => {
|
|
2
2
|
register: ({ strapi }: {
|
|
3
|
-
strapi: import("@strapi/types/dist/core").Strapi;
|
|
3
|
+
strapi: import("@strapi/types/dist/core/strapi.js").Strapi;
|
|
4
4
|
}) => Promise<void>;
|
|
5
5
|
bootstrap: () => Promise<void>;
|
|
6
6
|
routes: {
|
|
@@ -22,12 +22,12 @@ declare const _default: () => {
|
|
|
22
22
|
};
|
|
23
23
|
'content-api': () => {
|
|
24
24
|
type: "content-api";
|
|
25
|
-
routes: import("@strapi/types/dist/core").RouteInput[];
|
|
25
|
+
routes: import("@strapi/types/dist/core/route.js").RouteInput[];
|
|
26
26
|
};
|
|
27
27
|
};
|
|
28
28
|
controllers: {
|
|
29
|
-
locales: import("@strapi/types/dist/core").Controller;
|
|
30
|
-
'iso-locales': import("@strapi/types/dist/core").Controller;
|
|
29
|
+
locales: import("@strapi/types/dist/core/controller.js").Controller;
|
|
30
|
+
'iso-locales': import("@strapi/types/dist/core/controller.js").Controller;
|
|
31
31
|
'content-types': {
|
|
32
32
|
getNonLocalizedAttributes(ctx: import("koa").Context): Promise<any>;
|
|
33
33
|
getFillFromLocaleData(ctx: import("koa").Context): Promise<any>;
|
|
@@ -37,7 +37,7 @@ declare const _default: () => {
|
|
|
37
37
|
getSettings(ctx: import("koa").Context): Promise<void>;
|
|
38
38
|
};
|
|
39
39
|
'ai-localization-jobs': ({ strapi }: {
|
|
40
|
-
strapi: import("@strapi/types/dist/core").Strapi;
|
|
40
|
+
strapi: import("@strapi/types/dist/core/strapi.js").Strapi;
|
|
41
41
|
}) => {
|
|
42
42
|
getJobForSingleType(ctx: any): Promise<any>;
|
|
43
43
|
getJobForCollectionType(ctx: any): Promise<any>;
|
|
@@ -125,7 +125,7 @@ declare const _default: () => {
|
|
|
125
125
|
sendDidUpdateI18nLocalesEvent: () => Promise<void>;
|
|
126
126
|
};
|
|
127
127
|
localizations: () => {
|
|
128
|
-
syncNonLocalizedAttributes: (sourceEntry: any, model: import("@strapi/types/dist/schema").ContentType) => Promise<void>;
|
|
128
|
+
syncNonLocalizedAttributes: (sourceEntry: any, model: import("@strapi/types/dist/schema/index.js").ContentType) => Promise<void>;
|
|
129
129
|
};
|
|
130
130
|
locales: () => {
|
|
131
131
|
find: (params?: any) => Promise<any[]>;
|
|
@@ -141,9 +141,9 @@ declare const _default: () => {
|
|
|
141
141
|
initDefaultLocale: () => Promise<void>;
|
|
142
142
|
};
|
|
143
143
|
sanitize: ({ strapi }: {
|
|
144
|
-
strapi: import("@strapi/types/dist/core").Strapi;
|
|
144
|
+
strapi: import("@strapi/types/dist/core/strapi.js").Strapi;
|
|
145
145
|
}) => {
|
|
146
|
-
sanitizeLocalizationFields: import("lodash").CurriedFunction2<import("@strapi/types/dist/struct").ContentTypeSchema | import("@strapi/types/dist/struct").ComponentSchema, import("@strapi/types/dist/data").Entity<import("@strapi/types/dist/uid").Schema, string>, Promise<import("@strapi/utils/dist/types").Data>>;
|
|
146
|
+
sanitizeLocalizationFields: import("lodash").CurriedFunction2<import("@strapi/types/dist/struct/schema.js").ContentTypeSchema | import("@strapi/types/dist/struct/schema.js").ComponentSchema, import("@strapi/types/dist/data/entity.js").Entity<import("@strapi/types/dist/uid/index.js").Schema, string>, Promise<import("@strapi/utils/dist/types").Data>>;
|
|
147
147
|
};
|
|
148
148
|
'iso-locales': () => {
|
|
149
149
|
getIsoLocales: () => {
|
|
@@ -161,17 +161,17 @@ declare const _default: () => {
|
|
|
161
161
|
getNestedPopulateOfNonLocalizedAttributes: (modelUID: any) => string[];
|
|
162
162
|
};
|
|
163
163
|
'ai-localizations': ({ strapi }: {
|
|
164
|
-
strapi: import("@strapi/types/dist/core").Strapi;
|
|
164
|
+
strapi: import("@strapi/types/dist/core/strapi.js").Strapi;
|
|
165
165
|
}) => {
|
|
166
166
|
isEnabled(): Promise<boolean>;
|
|
167
167
|
generateDocumentLocalizations({ model, document, }: {
|
|
168
|
-
model: import("@strapi/types/dist/uid").ContentType;
|
|
169
|
-
document: import("@strapi/types/dist/modules/documents").AnyDocument;
|
|
168
|
+
model: import("@strapi/types/dist/uid/index.js").ContentType;
|
|
169
|
+
document: import("@strapi/types/dist/modules/documents/index.js").AnyDocument;
|
|
170
170
|
}): Promise<void>;
|
|
171
171
|
setupMiddleware(): void;
|
|
172
172
|
};
|
|
173
173
|
'ai-localization-jobs': ({ strapi }: {
|
|
174
|
-
strapi: import("@strapi/types/dist/core").Strapi;
|
|
174
|
+
strapi: import("@strapi/types/dist/core/strapi.js").Strapi;
|
|
175
175
|
}) => {
|
|
176
176
|
upsertJobForDocument({ documentId, contentType, sourceLocale, targetLocales, status, }: {
|
|
177
177
|
documentId: string;
|
|
@@ -184,7 +184,7 @@ declare const _default: () => {
|
|
|
184
184
|
getJobByContentType(contentType: string): Promise<any>;
|
|
185
185
|
};
|
|
186
186
|
settings: ({ strapi }: {
|
|
187
|
-
strapi: import("@strapi/types/dist/core").Strapi;
|
|
187
|
+
strapi: import("@strapi/types/dist/core/strapi.js").Strapi;
|
|
188
188
|
}) => {
|
|
189
189
|
getSettings: () => Promise<import("yup/lib/object").AssertsShape<{
|
|
190
190
|
aiLocalizations: import("yup").BooleanSchema<boolean, Record<string, any>, boolean>;
|
|
@@ -192,10 +192,10 @@ declare const _default: () => {
|
|
|
192
192
|
setSettings: (value: import("./validation/settings").Settings) => Promise<void>;
|
|
193
193
|
};
|
|
194
194
|
'fill-from-locale': ({ strapi }: {
|
|
195
|
-
strapi: import("@strapi/types/dist/core").Strapi;
|
|
195
|
+
strapi: import("@strapi/types/dist/core/strapi.js").Strapi;
|
|
196
196
|
}) => {
|
|
197
|
-
fetchRawDocument(model: import("@strapi/types/dist/uid").ContentType, sourceLocale: string, documentId?: string): Promise<import("@strapi/types/dist/modules/documents").AnyDocument | null>;
|
|
198
|
-
transformDocument(document: Record<string, unknown>, model: import("@strapi/types/dist/uid").ContentType, targetLocale: string, userAbility: any): Promise<Record<string, unknown>>;
|
|
197
|
+
fetchRawDocument(model: import("@strapi/types/dist/uid/index.js").ContentType, sourceLocale: string, documentId?: string): Promise<import("@strapi/types/dist/modules/documents/index.js").AnyDocument | null>;
|
|
198
|
+
transformDocument(document: Record<string, unknown>, model: import("@strapi/types/dist/uid/index.js").ContentType, targetLocale: string, userAbility: any): Promise<Record<string, unknown>>;
|
|
199
199
|
};
|
|
200
200
|
};
|
|
201
201
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-localizations.d.ts","sourceRoot":"","sources":["../../../../server/src/services/ai-localizations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAiEhE;;;;;;GAMG;AACH,QAAA,MAAM,sBAAsB,GAC1B,YAAY,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC/B,WAAW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,EACrC,QAAQ,MAAM,CAAC,MAAM,EACrB,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,GAAG,SAAS,KACvD,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CA4D7B,CAAC;AAEF,QAAA,MAAM,4BAA4B,GAAI,YAAY;IAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAA;CAAE;;IAgBrE;;;;OAIG;wDAIA;QACD,KAAK,EAAE,GAAG,CAAC,WAAW,CAAC;QACvB,QAAQ,EAAE,OAAO,CAAC,SAAS,CAAC,WAAW,CAAC;KACzC;;
|
|
1
|
+
{"version":3,"file":"ai-localizations.d.ts","sourceRoot":"","sources":["../../../../server/src/services/ai-localizations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAiEhE;;;;;;GAMG;AACH,QAAA,MAAM,sBAAsB,GAC1B,YAAY,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC/B,WAAW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,EACrC,QAAQ,MAAM,CAAC,MAAM,EACrB,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,GAAG,SAAS,KACvD,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CA4D7B,CAAC;AAEF,QAAA,MAAM,4BAA4B,GAAI,YAAY;IAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAA;CAAE;;IAgBrE;;;;OAIG;wDAIA;QACD,KAAK,EAAE,GAAG,CAAC,WAAW,CAAC;QACvB,QAAQ,EAAE,OAAO,CAAC,SAAS,CAAC,WAAW,CAAC;KACzC;;CA2QJ,CAAC;AAEF,OAAO,EAAE,4BAA4B,EAAE,sBAAsB,EAAE,CAAC"}
|
|
@@ -6,7 +6,7 @@ export declare const createFillFromLocaleService: ({ strapi }: {
|
|
|
6
6
|
* Fetch the raw populated document for the given locale without any transformation.
|
|
7
7
|
* The caller is responsible for sanitizing the output before passing it to transformDocument.
|
|
8
8
|
*/
|
|
9
|
-
fetchRawDocument(model: UID.ContentType, sourceLocale: string, documentId?: string): Promise<import("@strapi/types/dist/modules/documents").AnyDocument | null>;
|
|
9
|
+
fetchRawDocument(model: UID.ContentType, sourceLocale: string, documentId?: string): Promise<import("@strapi/types/dist/modules/documents/index.js").AnyDocument | null>;
|
|
10
10
|
/**
|
|
11
11
|
* Transform a (sanitized) document: strip internal fields, resolve relations to the target
|
|
12
12
|
* locale, and skip relations to content types the user cannot read.
|
|
@@ -45,7 +45,7 @@ declare const _default: {
|
|
|
45
45
|
sendDidUpdateI18nLocalesEvent: () => Promise<void>;
|
|
46
46
|
};
|
|
47
47
|
localizations: () => {
|
|
48
|
-
syncNonLocalizedAttributes: (sourceEntry: any, model: import("@strapi/types/dist/schema").ContentType) => Promise<void>;
|
|
48
|
+
syncNonLocalizedAttributes: (sourceEntry: any, model: import("@strapi/types/dist/schema/index.js").ContentType) => Promise<void>;
|
|
49
49
|
};
|
|
50
50
|
locales: () => {
|
|
51
51
|
find: (params?: any) => Promise<any[]>;
|
|
@@ -61,9 +61,9 @@ declare const _default: {
|
|
|
61
61
|
initDefaultLocale: () => Promise<void>;
|
|
62
62
|
};
|
|
63
63
|
sanitize: ({ strapi }: {
|
|
64
|
-
strapi: import("@strapi/types/dist/core").Strapi;
|
|
64
|
+
strapi: import("@strapi/types/dist/core/strapi.js").Strapi;
|
|
65
65
|
}) => {
|
|
66
|
-
sanitizeLocalizationFields: import("lodash").CurriedFunction2<import("@strapi/types/dist/struct").ContentTypeSchema | import("@strapi/types/dist/struct").ComponentSchema, import("@strapi/types/dist/data").Entity<import("@strapi/types/dist/uid").Schema, string>, Promise<import("@strapi/utils/dist/types").Data>>;
|
|
66
|
+
sanitizeLocalizationFields: import("lodash").CurriedFunction2<import("@strapi/types/dist/struct/schema.js").ContentTypeSchema | import("@strapi/types/dist/struct/schema.js").ComponentSchema, import("@strapi/types/dist/data/entity.js").Entity<import("@strapi/types/dist/uid/index.js").Schema, string>, Promise<import("@strapi/utils/dist/types").Data>>;
|
|
67
67
|
};
|
|
68
68
|
'iso-locales': () => {
|
|
69
69
|
getIsoLocales: () => {
|
|
@@ -81,17 +81,17 @@ declare const _default: {
|
|
|
81
81
|
getNestedPopulateOfNonLocalizedAttributes: (modelUID: any) => string[];
|
|
82
82
|
};
|
|
83
83
|
'ai-localizations': ({ strapi }: {
|
|
84
|
-
strapi: import("@strapi/types/dist/core").Strapi;
|
|
84
|
+
strapi: import("@strapi/types/dist/core/strapi.js").Strapi;
|
|
85
85
|
}) => {
|
|
86
86
|
isEnabled(): Promise<boolean>;
|
|
87
87
|
generateDocumentLocalizations({ model, document, }: {
|
|
88
|
-
model: import("@strapi/types/dist/uid").ContentType;
|
|
89
|
-
document: import("@strapi/types/dist/modules/documents").AnyDocument;
|
|
88
|
+
model: import("@strapi/types/dist/uid/index.js").ContentType;
|
|
89
|
+
document: import("@strapi/types/dist/modules/documents/index.js").AnyDocument;
|
|
90
90
|
}): Promise<void>;
|
|
91
91
|
setupMiddleware(): void;
|
|
92
92
|
};
|
|
93
93
|
'ai-localization-jobs': ({ strapi }: {
|
|
94
|
-
strapi: import("@strapi/types/dist/core").Strapi;
|
|
94
|
+
strapi: import("@strapi/types/dist/core/strapi.js").Strapi;
|
|
95
95
|
}) => {
|
|
96
96
|
upsertJobForDocument({ documentId, contentType, sourceLocale, targetLocales, status, }: {
|
|
97
97
|
documentId: string;
|
|
@@ -104,7 +104,7 @@ declare const _default: {
|
|
|
104
104
|
getJobByContentType(contentType: string): Promise<any>;
|
|
105
105
|
};
|
|
106
106
|
settings: ({ strapi }: {
|
|
107
|
-
strapi: import("@strapi/types/dist/core").Strapi;
|
|
107
|
+
strapi: import("@strapi/types/dist/core/strapi.js").Strapi;
|
|
108
108
|
}) => {
|
|
109
109
|
getSettings: () => Promise<import("yup/lib/object").AssertsShape<{
|
|
110
110
|
aiLocalizations: import("yup").BooleanSchema<boolean, Record<string, any>, boolean>;
|
|
@@ -112,10 +112,10 @@ declare const _default: {
|
|
|
112
112
|
setSettings: (value: import("../validation/settings").Settings) => Promise<void>;
|
|
113
113
|
};
|
|
114
114
|
'fill-from-locale': ({ strapi }: {
|
|
115
|
-
strapi: import("@strapi/types/dist/core").Strapi;
|
|
115
|
+
strapi: import("@strapi/types/dist/core/strapi.js").Strapi;
|
|
116
116
|
}) => {
|
|
117
|
-
fetchRawDocument(model: import("@strapi/types/dist/uid").ContentType, sourceLocale: string, documentId?: string): Promise<import("@strapi/types/dist/modules/documents").AnyDocument | null>;
|
|
118
|
-
transformDocument(document: Record<string, unknown>, model: import("@strapi/types/dist/uid").ContentType, targetLocale: string, userAbility: any): Promise<Record<string, unknown>>;
|
|
117
|
+
fetchRawDocument(model: import("@strapi/types/dist/uid/index.js").ContentType, sourceLocale: string, documentId?: string): Promise<import("@strapi/types/dist/modules/documents/index.js").AnyDocument | null>;
|
|
118
|
+
transformDocument(document: Record<string, unknown>, model: import("@strapi/types/dist/uid/index.js").ContentType, targetLocale: string, userAbility: any): Promise<Record<string, unknown>>;
|
|
119
119
|
};
|
|
120
120
|
};
|
|
121
121
|
export default _default;
|
|
@@ -2,7 +2,7 @@ import type { Core, Data } from '@strapi/types';
|
|
|
2
2
|
declare const sanitize: ({ strapi }: {
|
|
3
3
|
strapi: Core.Strapi;
|
|
4
4
|
}) => {
|
|
5
|
-
sanitizeLocalizationFields: import("lodash").CurriedFunction2<import("@strapi/types/dist/struct").ContentTypeSchema | import("@strapi/types/dist/struct").ComponentSchema, Data.Entity<import("@strapi/types/dist/uid").Schema, string>, Promise<import("@strapi/utils/dist/types").Data>>;
|
|
5
|
+
sanitizeLocalizationFields: import("lodash").CurriedFunction2<import("@strapi/types/dist/struct/schema.js").ContentTypeSchema | import("@strapi/types/dist/struct/schema.js").ComponentSchema, Data.Entity<import("@strapi/types/dist/uid/index.js").Schema, string>, Promise<import("@strapi/utils/dist/types").Data>>;
|
|
6
6
|
};
|
|
7
7
|
type SanitizeService = typeof sanitize;
|
|
8
8
|
export default sanitize;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@strapi/i18n",
|
|
3
|
-
"version": "5.50.
|
|
3
|
+
"version": "5.50.2",
|
|
4
4
|
"description": "Create read and update content in different languages, both from the Admin Panel and from the API",
|
|
5
5
|
"homepage": "https://strapi.io",
|
|
6
6
|
"bugs": {
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"build:types:server": "run -T tsc -p server/tsconfig.build.json --emitDeclarationOnly",
|
|
53
53
|
"build:types:admin": "run -T tsc -p admin/tsconfig.build.json --emitDeclarationOnly",
|
|
54
54
|
"clean": "run -T rimraf ./dist",
|
|
55
|
-
"lint": "run -T eslint .",
|
|
55
|
+
"lint": "run -T eslint . --max-warnings=0",
|
|
56
56
|
"test:front": "run -T cross-env IS_EE=true jest --config ./jest.config.front.js",
|
|
57
57
|
"test:ts:front": "run -T tsc -p admin/tsconfig.json",
|
|
58
58
|
"test:unit": "run -T jest",
|
|
@@ -61,9 +61,9 @@
|
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
63
|
"@reduxjs/toolkit": "1.9.7",
|
|
64
|
-
"@strapi/design-system": "2.2.
|
|
65
|
-
"@strapi/icons": "2.2.
|
|
66
|
-
"@strapi/utils": "5.50.
|
|
64
|
+
"@strapi/design-system": "2.2.3",
|
|
65
|
+
"@strapi/icons": "2.2.3",
|
|
66
|
+
"@strapi/utils": "5.50.2",
|
|
67
67
|
"lodash": "4.18.1",
|
|
68
68
|
"qs": "6.15.3",
|
|
69
69
|
"react-intl": "6.6.2",
|
|
@@ -72,13 +72,18 @@
|
|
|
72
72
|
"zod": "3.25.67"
|
|
73
73
|
},
|
|
74
74
|
"devDependencies": {
|
|
75
|
-
"@strapi/admin": "5.50.
|
|
76
|
-
"@strapi/admin-test-utils": "5.50.
|
|
77
|
-
"@strapi/content-manager": "5.50.
|
|
78
|
-
"@strapi/database": "5.50.
|
|
79
|
-
"@strapi/types": "5.50.
|
|
75
|
+
"@strapi/admin": "5.50.2",
|
|
76
|
+
"@strapi/admin-test-utils": "5.50.2",
|
|
77
|
+
"@strapi/content-manager": "5.50.2",
|
|
78
|
+
"@strapi/database": "5.50.2",
|
|
79
|
+
"@strapi/types": "5.50.2",
|
|
80
|
+
"@testing-library/dom": "10.4.1",
|
|
81
|
+
"@testing-library/jest-dom": "6.9.1",
|
|
80
82
|
"@testing-library/react": "16.3.2",
|
|
81
83
|
"@testing-library/user-event": "14.6.1",
|
|
84
|
+
"@types/jest": "29.5.2",
|
|
85
|
+
"@types/node": "20.19.41",
|
|
86
|
+
"jest": "29.6.0",
|
|
82
87
|
"koa": "2.16.4",
|
|
83
88
|
"msw": "2.13.4",
|
|
84
89
|
"react": "18.3.1",
|