fix(languages): show error instead of silently no-oping when adding a duplicate locale
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
addLocale() always cleared the input, even when LocaleSyncService rejected the code because it was already supported - same silent-failure shape as the widgets JSON bug fixed earlier this session. Now checks locales() first and shows an inline error, leaving the input untouched, instead of clearing it like the add succeeded. Verified live: typing an existing locale code and clicking Add now shows 'This language is already supported.' Navigation-section was also audited (id generation, label locale-migration, reorder swap, grouped-footer read-only fallback) - no defects found, it's solid as-is. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -13,7 +13,11 @@
|
|||||||
/>
|
/>
|
||||||
<app-button variant="primary" (click)="addLocale()">{{ 'builder.addLanguage' | translate }}</app-button>
|
<app-button variant="primary" (click)="addLocale()">{{ 'builder.addLanguage' | translate }}</app-button>
|
||||||
</div>
|
</div>
|
||||||
|
@if (addLocaleError(); as addError) {
|
||||||
|
<p class="editor-error">{{ addError }}</p>
|
||||||
|
} @else {
|
||||||
<small class="field-desc">{{ 'builder.newLanguageDesc' | translate }}</small>
|
<small class="field-desc">{{ 'builder.newLanguageDesc' | translate }}</small>
|
||||||
|
}
|
||||||
|
|
||||||
<div class="stack-list">
|
<div class="stack-list">
|
||||||
@for (code of locales(); track code) {
|
@for (code of locales(); track code) {
|
||||||
|
|||||||
@@ -37,15 +37,25 @@ export class ProjectEditorLanguagesSectionComponent {
|
|||||||
|
|
||||||
updateNewLocale(value: string): void {
|
updateNewLocale(value: string): void {
|
||||||
this.newLocale.set(value);
|
this.newLocale.set(value);
|
||||||
|
if (this.addLocaleError()) {
|
||||||
|
this.addLocaleError.set(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readonly addLocaleError = signal<string | null>(null);
|
||||||
|
|
||||||
addLocale(): void {
|
addLocale(): void {
|
||||||
const code = this.newLocale().trim();
|
const code = this.newLocale().trim().toLowerCase();
|
||||||
if (!code) {
|
if (!code) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (this.locales().includes(code)) {
|
||||||
|
this.addLocaleError.set(this.translate.t('builder.languageAlreadyAdded'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.facade.addLocale(code);
|
this.facade.addLocale(code);
|
||||||
this.newLocale.set('');
|
this.newLocale.set('');
|
||||||
|
this.addLocaleError.set(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
removeLocale(code: string): void {
|
removeLocale(code: string): void {
|
||||||
|
|||||||
@@ -679,6 +679,7 @@ export const en: Translations = {
|
|||||||
catalogNavTopCarousel: 'Top category carousel',
|
catalogNavTopCarousel: 'Top category carousel',
|
||||||
catalogNavTopCarouselDesc: 'Horizontally scrollable category chips above the catalog grid.',
|
catalogNavTopCarouselDesc: 'Horizontally scrollable category chips above the catalog grid.',
|
||||||
newLanguageDesc: 'ISO language code to add as a supported storefront language (e.g. de, fr).',
|
newLanguageDesc: 'ISO language code to add as a supported storefront language (e.g. de, fr).',
|
||||||
|
languageAlreadyAdded: 'This language is already supported.',
|
||||||
languagesTabDesc: 'Languages available to shoppers. The default language is used as a fallback everywhere.',
|
languagesTabDesc: 'Languages available to shoppers. The default language is used as a fallback everywhere.',
|
||||||
linkLabelDesc: 'Text shown for this navigation link.',
|
linkLabelDesc: 'Text shown for this navigation link.',
|
||||||
linkUrlDesc: 'Path or URL this navigation link points to.',
|
linkUrlDesc: 'Path or URL this navigation link points to.',
|
||||||
|
|||||||
@@ -679,6 +679,7 @@ export const hy: Translations = {
|
|||||||
catalogNavTopCarousel: 'Վերևի կատեգորիաների կարուսել',
|
catalogNavTopCarousel: 'Վերևի կատեգորիաների կարուսել',
|
||||||
catalogNavTopCarouselDesc: 'Հորիզոնական թերթվող կատեգորիաների chip-եր կատալոգի ցանցի վերևում։',
|
catalogNavTopCarouselDesc: 'Հորիզոնական թերթվող կատեգորիաների chip-եր կատալոգի ցանցի վերևում։',
|
||||||
newLanguageDesc: 'ISO լեզվի կոդ՝ որպես աջակցվող լեզու ավելացնելու համար (օր․՝ de, fr)։',
|
newLanguageDesc: 'ISO լեզվի կոդ՝ որպես աջակցվող լեզու ավելացնելու համար (օր․՝ de, fr)։',
|
||||||
|
languageAlreadyAdded: 'Այս լեզուն արդեն ավելացված է։',
|
||||||
languagesTabDesc: 'Գնորդներին հասանելի լեզուներ։ Լռելյայն լեզուն օգտագործվում է որպես պահուստային ամենուր։',
|
languagesTabDesc: 'Գնորդներին հասանելի լեզուներ։ Լռելյայն լեզուն օգտագործվում է որպես պահուստային ամենուր։',
|
||||||
linkLabelDesc: 'Այս նավիգացիոն հղման համար ցուցադրվող տեքստը։',
|
linkLabelDesc: 'Այս նավիգացիոն հղման համար ցուցադրվող տեքստը։',
|
||||||
linkUrlDesc: 'Ուղին կամ URL-ը, որին ուղղորդում է այս նավիգացիոն հղումը։',
|
linkUrlDesc: 'Ուղին կամ URL-ը, որին ուղղորդում է այս նավիգացիոն հղումը։',
|
||||||
|
|||||||
@@ -679,6 +679,7 @@ export const ru: Translations = {
|
|||||||
catalogNavTopCarousel: 'Карусель категорий сверху',
|
catalogNavTopCarousel: 'Карусель категорий сверху',
|
||||||
catalogNavTopCarouselDesc: 'Горизонтально прокручиваемые чипы категорий над сеткой каталога.',
|
catalogNavTopCarouselDesc: 'Горизонтально прокручиваемые чипы категорий над сеткой каталога.',
|
||||||
newLanguageDesc: 'Код языка ISO для добавления в поддерживаемые языки витрины (например, de, fr).',
|
newLanguageDesc: 'Код языка ISO для добавления в поддерживаемые языки витрины (например, de, fr).',
|
||||||
|
languageAlreadyAdded: 'Этот язык уже добавлен.',
|
||||||
languagesTabDesc: 'Языки, доступные покупателям. Язык по умолчанию используется как резервный везде.',
|
languagesTabDesc: 'Языки, доступные покупателям. Язык по умолчанию используется как резервный везде.',
|
||||||
linkLabelDesc: 'Текст, отображаемый для этой ссылки навигации.',
|
linkLabelDesc: 'Текст, отображаемый для этой ссылки навигации.',
|
||||||
linkUrlDesc: 'Путь или URL, на который ведёт эта ссылка навигации.',
|
linkUrlDesc: 'Путь или URL, на который ведёт эта ссылка навигации.',
|
||||||
|
|||||||
@@ -677,6 +677,7 @@ export interface Translations {
|
|||||||
catalogNavTopCarousel: string;
|
catalogNavTopCarousel: string;
|
||||||
catalogNavTopCarouselDesc: string;
|
catalogNavTopCarouselDesc: string;
|
||||||
newLanguageDesc: string;
|
newLanguageDesc: string;
|
||||||
|
languageAlreadyAdded: string;
|
||||||
languagesTabDesc: string;
|
languagesTabDesc: string;
|
||||||
linkLabelDesc: string;
|
linkLabelDesc: string;
|
||||||
linkUrlDesc: string;
|
linkUrlDesc: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user