diff --git a/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/components/dot-uve-toolbar/dot-uve-toolbar.component.ts b/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/components/dot-uve-toolbar/dot-uve-toolbar.component.ts index 164c4454b1c2..c5f450940203 100644 --- a/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/components/dot-uve-toolbar/dot-uve-toolbar.component.ts +++ b/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/components/dot-uve-toolbar/dot-uve-toolbar.component.ts @@ -298,10 +298,10 @@ export class DotUveToolbarComponent { const languageHasTranslation = currentLanguage.translated; if (!languageHasTranslation) { - // Show confirmation dialog to create a new translation + // Emit to the shell, which creates the language version and reloads. const page = this.#store.pageAsset()?.page; if (page) { - this.createNewTranslation(currentLanguage, page); + this.translatePage.emit({ page, newLanguage: currentLanguage.id }); } return; @@ -396,39 +396,6 @@ export class DotUveToolbarComponent { }); } - /* - * Asks the user for confirmation to create a new translation for a given language. - * - * @param {DotLanguage} language - The language to create a new translation for. - * @private - * - * @return {void} - */ - private createNewTranslation(language: DotLanguage, page: DotCMSPage): void { - this.#confirmationService.confirm({ - header: this.#dotMessageService.get( - 'editpage.language-change-missing-lang-populate.confirm.header' - ), - message: this.#dotMessageService.get( - 'editpage.language-change-missing-lang-populate.confirm.message', - language.language - ), - rejectIcon: 'hidden', - acceptIcon: 'hidden', - key: 'shell-confirm-dialog', - accept: () => { - this.translatePage.emit({ - page: page, - newLanguage: language.id - }); - }, - reject: () => { - // If is rejected, bring back the current language on selector - this.$languageSelector()?.value.set(this.#store.pageLanguage()); - } - }); - } - /** * Gets the minimum allowed date for the calendar component. * Sets hours/minutes/seconds/milliseconds to 0 to avoid collisions with preview date diff --git a/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/edit-ema-editor.component.ts b/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/edit-ema-editor.component.ts index ea3aeba2aebe..a6d13e69b645 100644 --- a/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/edit-ema-editor.component.ts +++ b/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/edit-ema-editor.component.ts @@ -51,7 +51,6 @@ import { DotCMSContentType, DotCMSContentlet, DotCMSTempFile, - DotLanguage, DotTreeNode, FeaturedFlags, SeoMetaTags, @@ -421,7 +420,7 @@ export class EditEmaEditorComponent implements OnDestroy, AfterViewInit { const { page, currentLanguage } = this.uveStore.pageTranslateProps(); if (currentLanguage && !currentLanguage?.translated) { - this.createNewTranslation(currentLanguage, page); + this.translatePage({ page, newLanguage: currentLanguage.id }); } }); @@ -1688,30 +1687,99 @@ export class EditEmaEditorComponent implements OnDestroy, AfterViewInit { }); } - private createNewTranslation(language: DotLanguage, page: DotCMSPage): void { - this.confirmationService.confirm({ - header: this.dotMessageService.get( - 'editpage.language-change-missing-lang-populate.confirm.header' - ), - message: this.dotMessageService.get( - 'editpage.language-change-missing-lang-populate.confirm.message', - language.language - ), - rejectIcon: 'hidden', - acceptIcon: 'hidden', - key: 'shell-confirm-dialog', - accept: () => { - this.translatePage({ page, newLanguage: language.id }); - }, - reject: () => { - // If is rejected, bring back the current language on selector - this.#goBackToCurrentLanguage(); + /** + * Create the page's language version on switch. + * + * Fires a programmatic workflow NEW action that copies the source page's field + * values into a new version in the target language, then re-renders via `pageLoad`. + */ + translatePage(event: { page: DotCMSPage; newLanguage: number }) { + this.#autoCreateTranslation(event.page, event.newLanguage); + } + + #autoCreateTranslation(page: DotCMSPage, newLanguage: number): void { + // Resolve the real content type so the payload is built from its actual + // field definitions instead of guessing which page properties to copy. + this.dotContentTypeService + .getContentType(page.contentType) + .pipe( + switchMap((contentType) => { + const data = this.#buildTranslationData(contentType, page, newLanguage); + + return this.dotWorkflowActionsFireService.newContentlet( + page.contentType, + data + ); + }), + take(1), + takeUntilDestroyed(this.destroyRef) + ) + .subscribe({ + next: () => { + const languageName = + this.uveStore.pageLanguages().find((lang) => lang.id === newLanguage) + ?.language ?? ''; + + this.messageService.add({ + severity: 'success', + summary: this.dotMessageService.get('Workflow-Action'), + detail: this.dotMessageService.get( + 'editpage.language-change-missing-lang-populate.success', + languageName + ), + life: 3000 + }); + + this.uveStore.pageLoad({ language_id: newLanguage.toString() }); + }, + error: (error: HttpErrorResponse) => { + this.dotHttpErrorManagerService.handle(error); + // On failure, return to the language we came from. + this.#goBackToCurrentLanguage(); + } + }); + } + + /** + * Build the new-version payload from the content type's actual field definitions. + * + * Copies each defined field's value from the source page, preserves `identifier` + * (so it is a new language version of the same content, not a new one) and + * overrides `languageId`. Layout/divider fields carry no value on the page object, + * so they are skipped naturally. + */ + #buildTranslationData( + contentType: DotCMSContentType, + page: DotCMSPage, + newLanguage: number + ): Record { + const source = page as unknown as Record; + const data: Record = {}; + + (contentType.fields ?? []).forEach((field) => { + const key = field.variable; + + if (!key) { + return; } + + const value = source[key]; + + // Only copy primitive field values that exist on the source page. + if (value === null || value === undefined || typeof value === 'object') { + return; + } + + data[key] = String(value); }); - } - translatePage(event: { page: DotCMSPage; newLanguage: number }) { - this.dialog.translatePage(event); + data.identifier = page.identifier; + data.languageId = newLanguage.toString(); + // Wait for the new version to be indexed before pageLoad re-checks the + // `translated` flag — otherwise indexing lag could re-trigger the effect. + data.indexPolicy = 'WAIT_FOR'; + + return data; } /** diff --git a/dotCMS/src/main/webapp/WEB-INF/messages/Language.properties b/dotCMS/src/main/webapp/WEB-INF/messages/Language.properties index 0e0f18270990..631e465cf8ee 100644 --- a/dotCMS/src/main/webapp/WEB-INF/messages/Language.properties +++ b/dotCMS/src/main/webapp/WEB-INF/messages/Language.properties @@ -6280,6 +6280,7 @@ locale.error.message=Locale ID already exists. editpage.language-change-missing-lang-populate.confirm.header=Create New Language Version? editpage.language-change-missing-lang-populate.confirm.message=Page does not exist in the selected language. Create a new version in {0}? +editpage.language-change-missing-lang-populate.success=A new page version was created in {0}. editpage.viewing.variant=Viewing {0} Variant editpage.editing.variant=Editing {0} Variant editpage.file.upload.not.image=The file dropped was not an image.