fix(i18n): route dirty-guard and html-editor strings through TranslateService
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
window.confirm/window.prompt calls in projectEditorDirtyGuard and MarketplaceHtmlEditorComponent, and the hardcoded Preview/Code toggle label in its template, bypassed the app's translation pipeline. Add builder.confirmLeaveUnsaved, promptLinkUrl, promptImageUrl, htmlEditorCode and htmlEditorPreview keys (en/ru/hy), resolve them via TranslateService.t() before passing to confirm/prompt, and use TranslatePipe for the toggle button label.
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
@for (item of toolbar; track item.id) {
|
@for (item of toolbar; track item.id) {
|
||||||
<button type="button" (click)="runCommand(item)">{{ item.label }}</button>
|
<button type="button" (click)="runCommand(item)">{{ item.label }}</button>
|
||||||
}
|
}
|
||||||
<button type="button" (click)="toggleCode()">{{ showCode() ? 'Preview' : 'Code' }}</button>
|
<button type="button" (click)="toggleCode()">{{ (showCode() ? 'builder.htmlEditorPreview' : 'builder.htmlEditorCode') | translate }}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<textarea
|
<textarea
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, OnChanges, Output, SimpleChanges, ViewChild, signal } from '@angular/core';
|
import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, OnChanges, Output, SimpleChanges, ViewChild, inject, signal } from '@angular/core';
|
||||||
|
import { TranslateService } from '../../../../i18n/translate.service';
|
||||||
|
import { TranslatePipe } from '../../../../i18n/translate.pipe';
|
||||||
|
|
||||||
export interface HtmlEditorToolbarCommand {
|
export interface HtmlEditorToolbarCommand {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -23,12 +25,14 @@ export const HTML_EDITOR_TOOLBAR: HtmlEditorToolbarCommand[] = [
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'app-marketplace-html-editor',
|
selector: 'app-marketplace-html-editor',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [],
|
imports: [TranslatePipe],
|
||||||
templateUrl: './marketplace-html-editor.component.html',
|
templateUrl: './marketplace-html-editor.component.html',
|
||||||
styleUrls: ['./marketplace-html-editor.component.scss'],
|
styleUrls: ['./marketplace-html-editor.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class MarketplaceHtmlEditorComponent implements OnChanges, AfterViewInit {
|
export class MarketplaceHtmlEditorComponent implements OnChanges, AfterViewInit {
|
||||||
|
private readonly translate = inject(TranslateService);
|
||||||
|
|
||||||
@Input() html = '';
|
@Input() html = '';
|
||||||
@Output() htmlChange = new EventEmitter<string>();
|
@Output() htmlChange = new EventEmitter<string>();
|
||||||
@ViewChild('surface', { static: true }) surface!: ElementRef<HTMLDivElement>;
|
@ViewChild('surface', { static: true }) surface!: ElementRef<HTMLDivElement>;
|
||||||
@@ -58,13 +62,13 @@ export class MarketplaceHtmlEditorComponent implements OnChanges, AfterViewInit
|
|||||||
runCommand(item: HtmlEditorToolbarCommand): void {
|
runCommand(item: HtmlEditorToolbarCommand): void {
|
||||||
this.surface.nativeElement.focus();
|
this.surface.nativeElement.focus();
|
||||||
if (item.command === 'createLink') {
|
if (item.command === 'createLink') {
|
||||||
const url = window.prompt('URL');
|
const url = window.prompt(this.translate.t('builder.promptLinkUrl'));
|
||||||
if (!url) {
|
if (!url) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
document.execCommand('createLink', false, url);
|
document.execCommand('createLink', false, url);
|
||||||
} else if (item.command === 'insertImage') {
|
} else if (item.command === 'insertImage') {
|
||||||
const url = window.prompt('Image URL');
|
const url = window.prompt(this.translate.t('builder.promptImageUrl'));
|
||||||
if (!url) {
|
if (!url) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,13 @@ import { inject } from '@angular/core';
|
|||||||
import { CanDeactivateFn } from '@angular/router';
|
import { CanDeactivateFn } from '@angular/router';
|
||||||
import { ProjectEditorFacade } from '../facade/project-editor.facade';
|
import { ProjectEditorFacade } from '../facade/project-editor.facade';
|
||||||
import { ProjectEditorPageComponent } from '../pages/project-editor-page.component';
|
import { ProjectEditorPageComponent } from '../pages/project-editor-page.component';
|
||||||
|
import { TranslateService } from '../../../i18n/translate.service';
|
||||||
|
|
||||||
export const projectEditorDirtyGuard: CanDeactivateFn<ProjectEditorPageComponent> = () => {
|
export const projectEditorDirtyGuard: CanDeactivateFn<ProjectEditorPageComponent> = () => {
|
||||||
const facade = inject(ProjectEditorFacade);
|
const facade = inject(ProjectEditorFacade);
|
||||||
if (!facade.dirty()) {
|
if (!facade.dirty()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return window.confirm('You have unsaved changes. Leave anyway?');
|
const translate = inject(TranslateService);
|
||||||
|
return window.confirm(translate.t('builder.confirmLeaveUnsaved'));
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -517,6 +517,11 @@ export const en: Translations = {
|
|||||||
unsavedChanges: 'Unsaved changes',
|
unsavedChanges: 'Unsaved changes',
|
||||||
save: 'Save',
|
save: 'Save',
|
||||||
publish: 'Publish',
|
publish: 'Publish',
|
||||||
|
confirmLeaveUnsaved: 'You have unsaved changes. Leave anyway?',
|
||||||
|
promptLinkUrl: 'URL',
|
||||||
|
promptImageUrl: 'Image URL',
|
||||||
|
htmlEditorCode: 'Code',
|
||||||
|
htmlEditorPreview: 'Preview',
|
||||||
},
|
},
|
||||||
staticPages: {
|
staticPages: {
|
||||||
notFound: 'Page not found',
|
notFound: 'Page not found',
|
||||||
|
|||||||
@@ -517,6 +517,11 @@ export const hy: Translations = {
|
|||||||
unsavedChanges: 'Չպահված փոփոխություններ',
|
unsavedChanges: 'Չպահված փոփոխություններ',
|
||||||
save: 'Պահպանել',
|
save: 'Պահպանել',
|
||||||
publish: 'Հրապարակել',
|
publish: 'Հրապարակել',
|
||||||
|
confirmLeaveUnsaved: 'Կան չպահված փոփոխություններ։ Այնուամենայնիվ դուրս գա՞լ։',
|
||||||
|
promptLinkUrl: 'URL',
|
||||||
|
promptImageUrl: 'Նկարի URL',
|
||||||
|
htmlEditorCode: 'Կոդ',
|
||||||
|
htmlEditorPreview: 'Նախադիտում',
|
||||||
},
|
},
|
||||||
staticPages: {
|
staticPages: {
|
||||||
notFound: 'Էջը չի գտնվել',
|
notFound: 'Էջը չի գտնվել',
|
||||||
|
|||||||
@@ -517,6 +517,11 @@ export const ru: Translations = {
|
|||||||
unsavedChanges: 'Есть несохранённые изменения',
|
unsavedChanges: 'Есть несохранённые изменения',
|
||||||
save: 'Сохранить',
|
save: 'Сохранить',
|
||||||
publish: 'Опубликовать',
|
publish: 'Опубликовать',
|
||||||
|
confirmLeaveUnsaved: 'Есть несохранённые изменения. Всё равно уйти?',
|
||||||
|
promptLinkUrl: 'URL',
|
||||||
|
promptImageUrl: 'URL изображения',
|
||||||
|
htmlEditorCode: 'Код',
|
||||||
|
htmlEditorPreview: 'Предпросмотр',
|
||||||
},
|
},
|
||||||
staticPages: {
|
staticPages: {
|
||||||
notFound: 'Страница не найдена',
|
notFound: 'Страница не найдена',
|
||||||
|
|||||||
@@ -515,6 +515,11 @@ export interface Translations {
|
|||||||
unsavedChanges: string;
|
unsavedChanges: string;
|
||||||
save: string;
|
save: string;
|
||||||
publish: string;
|
publish: string;
|
||||||
|
confirmLeaveUnsaved: string;
|
||||||
|
promptLinkUrl: string;
|
||||||
|
promptImageUrl: string;
|
||||||
|
htmlEditorCode: string;
|
||||||
|
htmlEditorPreview: string;
|
||||||
};
|
};
|
||||||
staticPages: {
|
staticPages: {
|
||||||
notFound: string;
|
notFound: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user