2026-02-26 23:09:20 +04:00
import { Translations } from './translations' ;
export const ru : Translations = {
header : {
home : 'Главная' ,
search : 'Поиск' ,
about : 'О нас' ,
contacts : 'Контакты' ,
searchPlaceholder : 'Искать...' ,
catalog : 'Каталог' ,
2026-07-09 01:13:54 +04:00
wishlist : 'Избранное' ,
compare : 'Сравнение' ,
2026-07-09 02:29:12 +04:00
openMenu : 'Открыть меню' ,
closeMenu : 'Закрыть меню' ,
2026-02-26 23:09:20 +04:00
} ,
footer : {
description : 'Современный маркетплейс для комфортных покупок' ,
company : 'Компания' ,
aboutUs : 'О нас' ,
contacts : 'Контакты' ,
requisites : 'Реквизиты' ,
support : 'Поддержка' ,
faq : 'FAQ' ,
delivery : 'Доставка' ,
guarantee : 'Гарантия' ,
legal : 'Правовая информация' ,
offer : 'Оферта' ,
privacy : 'Конфиденциальность' ,
returns : 'Возврат' ,
info : 'Информация' ,
aboutCompany : 'О компании' ,
documents : 'Документы' ,
paymentRules : 'Правила оплаты' ,
returnPolicy : 'Политика возврата' ,
publicOffer : 'Публичная оферта' ,
help : 'Помощь' ,
payment : 'Оплата' ,
allRightsReserved : 'В с е права защищены.' ,
} ,
home : {
welcomeTo : 'Добро пожаловать в {{brand}}' ,
subtitle : 'Найдите всё, что нужно, в одном месте' ,
startSearch : 'Начать поиск' ,
loading : 'Загружаем категории...' ,
errorTitle : 'Что-то пошло не так' ,
retry : 'Попробовать снова' ,
categoriesTitle : 'Категории товаров' ,
categoriesSubtitle : 'Выберите интересующую категорию' ,
categoriesEmpty : 'Категории скоро появятся' ,
categoriesEmptyDesc : 'Мы работаем над наполнением каталога' ,
dexarHeroTitle : 'Здесь ты найдёшь всё' ,
dexarHeroSubtitle : 'Тысячи товаров в одном месте' ,
dexarHeroTagline : 'просто и удобно' ,
goToCatalog : 'Перейти в каталог' ,
findProduct : 'Найти товар' ,
loadingDexar : 'Загрузка категорий...' ,
catalogTitle : 'Каталог товаров' ,
emptyCategoriesDexar : 'Категории пока отсутствуют' ,
categoriesSoonDexar : 'Скоро здесь появятся категории товаров' ,
itemsCount : '{{count}} товаров' ,
} ,
cart : {
title : 'Корзина' ,
clear : 'Очистить' ,
empty : 'Корзина пуста' ,
emptyDesc : 'Добавьте товары, чтобы начать покупки' ,
goShopping : 'Перейти к покупкам' ,
total : 'Итого' ,
items : 'Товары' ,
deliveryLabel : 'Доставка' ,
2026-06-21 23:13:01 +04:00
deliveryMethod : 'Способ доставки' ,
selectDelivery : 'Выберите способ доставки' ,
deliveryPlace : 'Место' ,
deliveryTime : 'Срок доставки' ,
digitalDelivery : 'Цифровая доставка' ,
deliveryRequired : 'Выберите доставку для всех товаров с доставкой перед оформлением заказа.' ,
2026-02-26 23:09:20 +04:00
toPay : 'К оплате' ,
agreeWith : 'Я согласен с ' ,
publicOffer : 'публичной офертой' ,
returnPolicy : 'политикой возврата' ,
guaranteeTerms : 'условиями гарантии' ,
privacyPolicy : 'политикой конфиденциальности' ,
and : 'и' ,
checkout : 'Оформить заказ' ,
2026-06-29 00:06:18 +04:00
payViaQr : 'Оплатить через QR' ,
payViaCard : 'Оплатить картой' ,
2026-02-26 23:09:20 +04:00
close : 'Закрыть' ,
creatingPayment : 'Создание платежа...' ,
waitFewSeconds : 'Подождите несколько секунд' ,
scanQr : 'Сканируйте QR-код для оплаты' ,
amountToPay : 'Сумма к оплате:' ,
waitingPayment : 'Ожидание оплаты...' ,
copied : '✓ Скопировано' ,
copyLink : 'Скопировать ссылку' ,
openNewTab : 'Открыть в новой вкладке' ,
paymentSuccess : 'Поздравляем! Оплата прошла успешно!' ,
paymentSuccessDesc : 'Введите ваши контактные данные, и мы отправим вам покупку в течение нескольких минут' ,
sending : 'Отправка...' ,
send : 'Отправить' ,
2026-06-02 00:57:36 +04:00
paymentError : 'Н е удалось создать платеж' ,
paymentErrorDesc : 'Сейчас не получилось подготовить QR-код для оплаты. Попробуйте еще раз через минуту.' ,
retryPayment : 'Попробовать снова' ,
2026-02-26 23:09:20 +04:00
paymentTimeout : 'Время ожидания истекло' ,
paymentTimeoutDesc : 'Мы не получили подтверждение оплаты в течение 3 минут.' ,
autoClose : 'Окно закроется автоматически...' ,
confirmClear : 'Вы уверены, что хотите очистить корзину?' ,
2026-07-09 02:29:12 +04:00
removeItem : 'Удалить товар' ,
2026-07-19 23:39:14 +04:00
increaseQuantity : 'Увеличить количество' ,
decreaseQuantity : 'Уменьшить количество' ,
2026-07-09 02:29:12 +04:00
paymentQrAlt : 'QR-код для оплаты' ,
2026-02-26 23:09:20 +04:00
acceptTerms : 'Пожалуйста, примите условия оферты, политику возврата и возврата для подтверждения оформления заказа.' ,
copyError : 'Ошибка копирования:' ,
emailSuccess : 'Email успешно отправлен! Проверьте свою почту.' ,
emailError : 'Произошла ошибка при отправке email. Пожалуйста, попробуйте снова.' ,
phoneRequired : 'Номер телефона обязателен' ,
phoneMoreDigits : 'Введите ещё {{count}} цифр' ,
phoneTooMany : 'Слишком много цифр' ,
emailRequired : 'Email обязателен' ,
emailTooShort : 'Email слишком короткий (минимум 5 символов)' ,
emailTooLong : 'Email слишком длинный (максимум 100 символов)' ,
emailNeedsAt : 'Email должен содержать @' ,
emailNeedsDomain : 'Email должен содержать домен (.com, .ru и т.д.)' ,
emailInvalid : 'Некорректный формат email' ,
2026-03-24 00:09:11 +04:00
loginRequired : 'Войдите для оформления' ,
loginRequiredDesc : 'Для оформления заказа войдите через Telegram' ,
loginWithTelegram : 'Войти через Telegram' ,
orScanQr : 'Или отсканируйте QR-код' ,
2026-02-26 23:09:20 +04:00
} ,
search : {
title : 'Поиск товаров' ,
placeholder : 'Введите название товара...' ,
2026-07-10 13:25:31 +04:00
searchBarAria : 'Поисковая строка' ,
2026-02-26 23:09:20 +04:00
resultsCount : 'Найдено товаров:' ,
searching : 'Поиск...' ,
retry : 'Попробовать снова' ,
noResults : 'Ничего не найдено' ,
noResultsFor : 'По запросу "{{query}}" товары не найдены' ,
noResultsHint : 'Попробуйте изменить запрос или используйте другие ключевые слова' ,
2026-07-10 13:25:31 +04:00
emptyResultsAria : 'Пустые результаты поиска' ,
popularCategories : 'Популярные категории' ,
recommendedProducts : 'Рекомендуемые товары' ,
aiSuggestionHint : 'AI-подсказка (в будущем)' ,
suggestionType : {
product : 'Товар' ,
category : 'Категория' ,
brand : 'Бренд' ,
collection : 'Подборка' ,
seller : 'Продавец' ,
'static-page' : 'Страница' ,
ai : 'AI' ,
} ,
2026-02-26 23:09:20 +04:00
addToCart : 'В корзину' ,
loadingMore : 'Загрузка...' ,
allLoaded : 'В с е результаты загружены' ,
emptyState : 'Введите запрос для поиска товаров' ,
2026-07-05 01:10:56 +04:00
minLength : 'Введите минимум {{count}} символа для поиска' ,
2026-02-26 23:09:20 +04:00
of : 'из' ,
} ,
category : {
retry : 'Попробовать снова' ,
addToCart : 'В корзину' ,
loadingMore : 'Загрузка...' ,
allLoaded : 'В с е товары загружены' ,
2026-07-25 23:54:08 +04:00
emptyTitle : 'Здесь пока пусто' ,
2026-02-26 23:09:20 +04:00
emptyDesc : 'В этой категории ещё нет товаров, но скоро они появятся' ,
goHome : 'Н а главную' ,
loading : 'Загрузка товаров...' ,
} ,
2026-07-05 01:36:21 +04:00
catalog : {
title : 'Каталог' ,
breadcrumb : 'Навигация по каталогу' ,
allCategories : 'В с е категории' ,
products : 'Товары' ,
loading : 'Загрузка каталога...' ,
loadingProducts : 'Загрузка товаров...' ,
errorTitle : 'Каталог недоступен' ,
error : 'Н е удалось загрузить каталог. Попробуйте позже.' ,
retry : 'Попробовать снова' ,
categoryHint : 'Выберите категорию, чтобы продолжить' ,
productHint : 'Товары в выбранной категории' ,
emptyTitle : 'Здесь пока пусто' ,
emptyCategories : 'В этом разделе пока нет дочерних категорий.' ,
emptyProducts : 'В этой категории пока нет товаров.' ,
addToCart : 'В корзину' ,
categoriesCount : '{{count}} категорий' ,
productsCount : '{{count}} товаров' ,
2026-07-09 01:40:22 +04:00
entriesCount : '{{count}} позиций' ,
categoryBannerPlaceholder : 'Баннер категории подготовлен для медиа и описания из backend.' ,
navigationPlaceholder : 'Макет навигации подготовлен для конфигурации из backend/bootstrap.' ,
removeSavedSearch : 'Удалить сохраненный поиск' ,
resetFilters : 'Сбросить' ,
filtersTitle : 'Фильтры' ,
2026-07-09 02:57:48 +04:00
from : 'От' ,
to : 'До' ,
2026-07-09 01:40:22 +04:00
minValue : 'От {{value}}' ,
maxValue : 'До {{value}}' ,
enabled : 'Включено' ,
searchPlaceholder : 'Поиск товаров, брендов и категорий' ,
searchSubmit : 'Найти' ,
2026-07-09 02:29:12 +04:00
clearSearch : 'Очистить' ,
2026-07-09 01:40:22 +04:00
suggestionsTitle : 'Подсказки' ,
2026-07-09 02:29:12 +04:00
popularSearchesTitle : 'Популярные запросы' ,
2026-07-09 01:40:22 +04:00
recentSearchesTitle : 'Недавние запросы' ,
searchHistoryTitle : 'История поиска' ,
clearHistory : 'Очистить' ,
searchNoResultsHint : 'Ничего не найдено. Попробуйте более общий запрос.' ,
2026-07-09 02:29:12 +04:00
searchProductsFound : 'Найдено товаров: {{total}}' ,
searchResultsSummary : '{{total}} результатов по запросу "{{query}}"' ,
2026-07-10 15:55:38 +04:00
loadMore : 'Показать еще' ,
2026-07-09 01:40:22 +04:00
sortBy : 'Сортировать по' ,
2026-07-09 01:46:32 +04:00
sortRelevance : 'Рекомендуемые' ,
2026-07-09 01:40:22 +04:00
sortLatest : 'Новизне' ,
sortPriceAsc : 'Цене: по возрастанию' ,
sortPriceDesc : 'Цене: по убыванию' ,
sortRating : 'Рейтингу' ,
sortPopular : 'Популярности' ,
sortDiscount : 'Скидке' ,
layoutGrid : 'Сетка' ,
layoutLargeGrid : 'Крупная сетка' ,
layoutCompactGrid : 'Компактная сетка' ,
2026-07-10 15:55:38 +04:00
layoutGrid2 : '2 колонки' ,
layoutGrid3 : '3 колонки' ,
layoutGrid4 : '4 колонки' ,
layoutCompact : 'Компактно' ,
2026-07-09 01:40:22 +04:00
layoutList : 'Список' ,
noResults : 'Нет результатов' ,
itemsCount : '{{count}} товаров' ,
emptyResultsTitle : 'Результаты не найдены' ,
emptyResultsDescription : 'Попробуйте изменить фильтры, сортировку или поисковый запрос.' ,
previousPage : 'Назад' ,
nextPage : 'Вперед' ,
pageOf : 'Страница {{page}} / {{total}}' ,
2026-07-09 01:46:32 +04:00
emptyCategoryTitle : 'В этой категории пока нет товаров' ,
emptyCategoryMessage : 'Попробуйте перейти в родительские категории или вернуться в общий каталог.' ,
2026-07-10 15:55:38 +04:00
goToParentCategory : 'Перейти в родительскую категорию' ,
2026-07-09 01:46:32 +04:00
browseCategories : 'Смотреть категории' ,
2026-07-10 15:55:38 +04:00
offlineTitle : 'Нет подключения' ,
offlineMessage : 'Подключитесь к сети, чтобы продолжить просмотр каталога.' ,
2026-07-09 01:46:32 +04:00
noFilterMatchTitle : 'Нет товаров, соответствующих выбранным фильтрам.' ,
noFilterMatchMessage : 'Попробуйте расширить диапазон цены, атрибуты или бренды.' ,
clearFilters : 'Очистить фильтры' ,
openFilters : 'Открыть фильтры' ,
applyFilters : 'Применить' ,
close : 'Закрыть' ,
filtersDrawerAria : 'Панель фильтров' ,
sortSheetAria : 'Параметры сортировки' ,
mobileToolbarAria : 'Мобильная панель каталога' ,
gridCycle : 'Сетка' ,
filtersPanelAria : 'Фильтры каталога' ,
2026-07-09 01:40:22 +04:00
filterPrice : 'Цена' ,
filterAvailability : 'Наличие' ,
filterInStock : 'В наличии' ,
filterLowStock : 'Мало в наличии' ,
filterOutOfStock : 'Нет в наличии' ,
filterRating : 'Рейтинг' ,
filterStars : '{{count}} звезд' ,
filterBrand : 'Бренд' ,
filterCategory : 'Категория' ,
filterCategoryValue : 'Категория {{value}}' ,
filterSubcategory : 'Подкатегория' ,
filterDiscount : 'Скидка' ,
filterNew : 'Новинки' ,
filterColor : 'Цвет' ,
filterSize : 'Размер' ,
filterAttributes : 'Атрибуты' ,
2026-07-19 22:04:13 +04:00
favorite : 'В избранное' ,
compare : 'Сравнить' ,
share : 'Поделиться' ,
quickView : 'Быстрый просмотр' ,
stockHigh : 'В наличии' ,
stockMedium : 'Ограниченно' ,
stockLow : 'Почти распродано' ,
stockOut : 'Нет в наличии' ,
2026-07-09 01:40:22 +04:00
} ,
productDetails : {
loading : 'Загрузка товара...' ,
errorTitle : 'Товар недоступен' ,
retry : 'Попробовать снова' ,
missingTitle : 'Товар не найден' ,
missingDescription : 'Этот товар не существует или больше недоступен.' ,
backToCatalog : 'Вернуться в каталог' ,
tabsAria : 'Вкладки товара' ,
mediaAria : 'Медиа товара' ,
ratingStarsAria : 'Рейтинг в звездах' ,
selectRatingAria : 'Выберите оценку' ,
fix(storefront): premium UX polish for product, compare, wishlist
- delivery-information, product-actions, product-description,
product-gallery, product-information, related-products,
variant-selector: normalize hardcoded hex colors to design tokens
(--text-primary, --text-secondary, --border-color, --bg-primary/
--bg-secondary, --primary-color/--primary-hover); stock status and
discount badge now use semantic --success-color/--warning-color/
--error-color instead of near-duplicate literal hex
- product-actions: add aria-pressed to wishlist/compare toggle
buttons; add hover/active/disabled states to action buttons
- product-gallery: add aria-current + aria-label to active thumbnail
button; add focus-visible ring and hover state on thumbnails and
toolbar buttons
- variant-selector: add aria-pressed to colour/size option buttons;
add a visible checkmark glyph on the selected colour swatch so
selection isn't color-only; add hover states
- product-tabs: add role="tab"/aria-selected to tab buttons
- star-selector: add per-star aria-label (new starsLabel i18n key
added to en/hy/ru + translations.ts interface)
- question-list: add aria-expanded to the ask-question disclosure
toggle; swap plain empty-state <p> for app-empty-state; add
hover/disabled states to pager buttons
- review-list: swap plain empty-state <p> for app-empty-state; add
hover/disabled states to pager and load-more buttons
- question-card, question-form, review-form: normalize accepted/
success/error colors to semantic tokens; add focus-visible and
hover/disabled states to inputs and submit buttons
- compare-table: add scope="col"/scope="row" to table headers; make
header row and attribute column sticky for easier comparison on
long tables
- compare-page: add hover/focus states to the remove-from-compare
chip button
Build verified green via `npm run build`.
Out of scope / skipped:
- src/app/pages/item-detail/* is dead code (not referenced by any
route or component) - left untouched
- wishlist page and product-details-container were already fully
composed with shared skeleton/empty-state/button components from
the RC-Visual-02 pass - no changes needed
- stars.component display-only rating glyphs use a light gray not an
exact token match - left as-is to avoid an unintended visual shift
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 11:47:57 +04:00
starsLabel : 'звёзд' ,
2026-07-09 01:40:22 +04:00
reviewsEmpty : 'Пока нет отзывов.' ,
questionsEmpty : 'Пока нет вопросов.' ,
askQuestion : 'Задать вопрос' ,
hideQuestionForm : 'Скрыть форму вопроса' ,
questionFormTitle : 'Задать вопрос' ,
questionFormPlaceholder : 'Спросите о размере, доставке, совместимости или использовании' ,
questionFormAnonymous : 'Задать анонимно' ,
submitQuestion : 'Отправить вопрос' ,
reviewFormTitle : 'Оставить отзыв' ,
reviewRatingLabel : 'Оценка' ,
reviewTitleLabel : 'Заголовок' ,
reviewTitlePlaceholder : 'Короткий заголовок' ,
reviewTextLabel : 'Отзыв' ,
reviewTextPlaceholder : 'Опишите ваш опыт использования' ,
reviewAnonymous : 'Отправить анонимно' ,
reviewUploadPlaceholder : 'Загрузка фото запланирована в следующем спринте.' ,
2026-07-10 13:10:35 +04:00
reviewRatingRequired : 'Выберите оценку.' ,
reviewTextRequired : 'Добавьте текст отзыва.' ,
reviewSuccess : 'Отзыв успешно отправлен.' ,
2026-07-09 01:40:22 +04:00
submitReview : 'Отправить отзыв' ,
submitting : 'Отправка...' ,
2026-07-10 13:10:35 +04:00
loadMore : 'Показать еще' ,
showingOf : 'Показано {{shown}} из {{total}}' ,
questionsSubmissionFuture : 'Отправку вопросов можно включить позже без изменения компонента.' ,
specificationsGeneral : 'Общие' ,
actionsAria : 'Действия с товаром' ,
buyNow : 'Купить сейчас' ,
wishlist : 'В избранное' ,
compare : 'Сравнить' ,
share : 'Поделиться' ,
notifyMe : 'Сообщить о наличии' ,
zoom : 'Увеличить' ,
fullscreen : 'Полный экран' ,
pdfDocument : 'PDF документ товара' ,
manualDocument : 'Инструкция товара' ,
warrantyDocument : 'Гарантийный документ' ,
openDocument : 'Открыть документ' ,
2026-07-09 01:40:22 +04:00
specificationsEmpty : 'Характеристики пока не указаны.' ,
warrantyTitle : 'Гарантия и возврат' ,
warrantyItem1 : 'Условия гарантии определяются продавцом и местным законодательством.' ,
warrantyItem2 : 'Возможность возврата зависит от состояния и категории товара.' ,
warrantyItem3 : 'Подробная инструкция по возврату доступна после покупки.' ,
verifiedPurchase : 'Подтвержденная покупка' ,
officialSeller : 'Официальный продавец' ,
acceptedAnswer : 'Принятый ответ' ,
like : 'Нравится' ,
dislike : 'Н е нравится' ,
reviewsCountLabel : '{{count}} отзывов' ,
previous : 'Назад' ,
next : 'Вперед' ,
pageOf : 'Страница {{page}} / {{total}}' ,
2026-07-05 01:36:21 +04:00
} ,
2026-02-26 23:09:20 +04:00
subcategories : {
loading : 'Загрузка подкатегорий...' ,
retry : 'Попробовать снова' ,
2026-07-25 23:54:08 +04:00
emptyTitle : 'Подкатегорий пока нет' ,
2026-02-26 23:09:20 +04:00
emptyDesc : 'В этом разделе ещё нет подкатегорий, но скоро они появятся' ,
goHome : 'Н а главную' ,
2026-03-24 00:09:11 +04:00
itemsInCategory : 'Товары в этой категории' ,
2026-07-05 01:09:55 +04:00
childrenCount : '{{count}} категорий' ,
productsCount : '{{count}} товаров' ,
includesProducts : 'Есть товары' ,
2026-02-26 23:09:20 +04:00
} ,
itemDetail : {
loading : 'Загрузка...' ,
loadingDexar : 'Загрузка товара...' ,
back : 'Вернуться' ,
backHome : 'Вернуться на главную' ,
noImage : 'Нет изображения' ,
stock : 'Наличие:' ,
inStock : 'В наличии' ,
lowStock : 'Осталось немного' ,
lastItems : 'Последние штуки' ,
mediumStock : 'Заканчивается' ,
addToCart : 'Добавить в корзину' ,
description : 'Описание' ,
2026-02-28 16:13:14 +04:00
specifications : 'Характеристики' ,
2026-02-26 23:09:20 +04:00
reviews : 'Отзывы' ,
yourReview : 'Ваш отзыв' ,
leaveReview : 'Оставить отзыв' ,
rating : 'Оценка:' ,
reviewPlaceholder : 'Поделитесь своими впечатлениями о товаре...' ,
reviewPlaceholderDexar : 'Поделитесь впечатлениями о товаре...' ,
anonymous : 'Анонимно' ,
submitting : 'Отправка...' ,
submit : 'Отправить' ,
reviewSuccess : 'Спасибо за ваш отзыв!' ,
reviewError : 'Ошибка отправки. Попробуйте позже.' ,
defaultUser : 'Пользователь' ,
defaultUserDexar : 'Аноним' ,
noReviews : 'Пока нет отзывов. Станьте первым!' ,
qna : 'Вопросы и ответы' ,
photo : 'Фото' ,
reviewsCount : 'отзывов' ,
today : 'Сегодня' ,
yesterday : 'Вчера' ,
daysAgo : 'дн. назад' ,
weeksAgo : 'нед. назад' ,
2026-03-24 00:09:11 +04:00
colour : 'Цвет' ,
size : 'Размер' ,
2026-07-05 01:07:53 +04:00
relatedProducts : 'Похожие товары' ,
2026-02-26 23:09:20 +04:00
} ,
app : {
connecting : 'Подключение к серверу...' ,
serverUnavailable : 'Сервер недоступен' ,
serverError : 'Н е удалось подключиться к серверу. Проверьте подключение к интернету.' ,
retryConnection : 'Повторить попытку' ,
pageTitle : 'Маркетплейс товаров и услуг' ,
fix(storefront): WCAG 2.1 AA accessibility fixes
RC A11Y-01 audit pass, storefront + shared app-shell chrome only. Builds
on RC-Visual-02/RC-Premium-01/RC STORE-01 without redoing that work.
- Skip link: added first-focusable "skip to main content" link (app.html,
styles.scss .skip-link/.sr-only), targeting new #main-content landmark.
New app.skipToContent i18n key in en/ru/hy.
- Header: mobile menu items stayed keyboard-focusable and screen-reader
reachable while visually collapsed (max-height:0 with no visibility
toggle) - fixed with visibility:hidden + matched transition-delay.
Desktop search input (readonly, click-to-navigate) had no keyboard
activation - added aria-label + (keydown.enter).
- Cart payment/bank-payment modals: custom (non-app-dialog) UI had no
focus trap, no Escape handling, and never returned focus to the
triggering element - ported app-dialog's confirmed-correct
focus-trap/Escape/return-focus pattern directly onto cart.component.ts.
Added role="dialog"/aria-modal/aria-label to both panels and
role="status"|"alert"/aria-live to every payment-status screen so
screen readers announce state changes (creating/waiting/success/
error/timeout).
- Search combobox: suggestion listbox had no role="combobox" wiring on
the input and suggestion buttons weren't role="option" - added
aria-autocomplete, aria-controls, aria-activedescendant, aria-selected
so the existing arrow-key navigation is announced to screen readers.
- Product tabs: tablist/tab pattern was incomplete (no role="tablist",
no tabpanel) - added role="tablist" + ids to product-tabs.component,
role="tabpanel"/aria-labelledby to the content panel in
product-details-container.
- Review form: rating/text validation errors weren't associated with
their controls (no aria-describedby, no role="alert") - fixed; added
aria-required to the review textarea.
- delivery-selector: added aria-required to the delivery <select> when
a selection is mandatory.
- Shared app-icon component: doc comment claimed "decorative by default
(aria-hidden)" but no aria-hidden was ever applied - fixed to actually
set aria-hidden="true" when undecorated, and role="img"/aria-label
when ariaLabel is passed. Shared component, affects every icon-only
usage app-wide, no visual change.
- Color contrast: --text-light fails WCAG AA 4.5:1 for normal text in
every theme (dexar 3.39:1, lavero/novo 2.54:1 against white). The two
in-scope usages (company-details org-short/basis, review-form
upload-placeholder) switched to --text-secondary (4.55:1-7.56:1,
passes), same visual family, no layout change.
Flagged, not fixed (design-system decisions, not polish):
- --border-color fails WCAG 1.4.11 3:1 for UI-component boundaries in
every theme (dexar 1.42:1, lavero/novo 1.24:1 vs white) - pervasive
token used by hundreds of borders app-wide; needs theme-owner sign-off.
- --success-color/--warning-color/--error-color/--info-color used as
plain text-on-white in several places (product-information,
question-card, review-form, compare-page) fail 4.5:1 (2.15-3.76:1) -
genuine brand semantic colors, changing them to pass would visibly
shift the palette; needs a deliberate token decision.
- Header mobile-menu max-height/padding transition (pre-existing,
unrelated to this fix) flagged by design lint as layout-thrashing;
left as-is per the "no layout/business-logic changes" constraint.
Verified: npx tsc --noEmit clean; npm run build green (only the
pre-existing bundle-budget warning, unrelated to this pass).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-24 08:46:18 +04:00
skipToContent : 'Перейти к основному содержимому' ,
2026-02-26 23:09:20 +04:00
} ,
2026-07-09 02:29:12 +04:00
platform : {
loadingPage : 'Загрузка страницы платформы...' ,
emptyConfig : 'Конфигурация страницы не найдена.' ,
} ,
backoffice : {
title : 'Песочница Backoffice' ,
subtitle : 'Домен управления бизнес-данными (mock для платформенного фундамента).' ,
loading : 'Загрузка данных backoffice...' ,
products : 'Товары' ,
categories : 'Категории' ,
otherDomains : 'Другие домены' ,
sku : 'SKU' ,
titleColumn : 'Название' ,
price : 'Цена' ,
status : 'Статус' ,
itemsCount : 'шт.' ,
orders : 'Заказы' ,
customers : 'Клиенты' ,
inventory : 'Склад' ,
media : 'Медиа' ,
settings : 'Настройки' ,
notAvailable : 'н/д' ,
} ,
builder : {
feat(builder): redesign marketplace builder experience and navigation
Renamed the experience consistently to Marketplace Builder everywhere
visible (page title/subtitle, breadcrumbs, sidebar, dashboard quick
action/shortcut copy) - internal ProjectEditor class/selector names
kept as-is to avoid regressions. builder.title/subtitle no longer say
'bootstrap-config editing surface' to end users.
New business-oriented IA (builder-groups.model.ts): 12 existing
ProjectEditorSectionIds regrouped into 8 groups (Marketplace, Branding
and Design, Homepage, Content, Languages, Marketplace Features,
Navigation and Search, Preview) - every existing section mapped to
exactly one group, none dropped, no group points at a page that
doesn't exist.
New Builder landing page at /edit (was a redirect straight into the
General form): readiness percent, recommended next step, one overview
card per group (purpose + real complete/in-progress/not-started/unknown
status, icon+text never color-alone), a Marketplace Readiness
checklist, quick links. All derived from real facade/schema signals
(required-field fill state, modifiedSections, staticPages, catalog
counts via BackofficeDataService) or explicitly marked unknown
(the "preview reviewed" check has no tracking - shown as unknown,
never guessed).
Section pages (/edit/:section) now share one consistent header:
breadcrumb (Builder > Group > Section), draft/published + modified
badges, and a contextual help panel (what is this / where visible /
what happens if you skip it) sourced per group. Sidebar nav rewritten
as grouped, icon-led sections with per-section and per-group status
indicators; layout converted from a top pill-tab bar to a responsive
sidebar (desktop 280px, tablet 72px icon rail, mobile drawer with
Escape-to-close), matching the Sprint 1 admin shell pattern. Section
form components themselves untouched.
Routes: 'edit' is now its own landing route instead of redirecting to
'edit/general'; /builder and /project-editor redirect to 'edit'.
Sprint 1/2 destinations that pointed at edit/general now point at the
new edit landing page.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 09:43:03 +04:00
title : 'Конструктор маркетплейса' ,
subtitle : 'Соберите свой маркетплейс шаг за шагом.' ,
2026-07-10 13:43:53 +04:00
general : 'Общие' ,
2026-07-09 02:29:12 +04:00
branding : 'Брендинг' ,
2026-07-10 13:43:53 +04:00
theme : 'Тема' ,
header : 'Хедер' ,
footer : 'Футер' ,
homepage : 'Главная страница' ,
widgets : 'Виджеты' ,
2026-07-10 13:52:01 +04:00
staticPages : 'Статические страницы' ,
2026-07-10 13:43:53 +04:00
marketplaceFeatures : 'Функции маркетплейса' ,
preview : 'Превью' ,
2026-07-09 02:29:12 +04:00
brandName : 'Название бренда' ,
2026-07-10 13:43:53 +04:00
marketplaceName : 'Название маркетплейса' ,
domain : 'Домен' ,
descriptionLabel : 'Описание' ,
defaultLanguage : 'Язык по умолчанию' ,
supportedLanguages : 'Поддерживаемые языки' ,
logo : 'Логотип' ,
smallLogo : 'Малый логотип' ,
favicon : 'Favicon' ,
2026-07-17 15:22:45 +04:00
socialImage : 'Изображение для соцсетей' ,
gallery : 'Галерея' ,
addGalleryImage : 'Добавить изображение' ,
2026-07-17 15:29:55 +04:00
headerLayout : 'Расположение шапки' ,
headerLayoutDefault : 'По умолчанию' ,
headerLayoutCentered : 'По центру' ,
headerSticky : 'Липкая шапка' ,
2026-07-10 13:43:53 +04:00
marketplaceTitle : 'Заголовок маркетплейса' ,
primaryColor : 'Основной цвет' ,
secondaryColor : 'Вторичный цвет' ,
backgroundColor : 'Фон' ,
surfaceColor : 'Поверхность' ,
textColor : 'Текст' ,
successColor : 'Success' ,
warningColor : 'Warning' ,
dangerColor : 'Danger' ,
showLogo : 'Логотип' ,
showSearch : 'Поиск' ,
showCategories : 'Категории' ,
showLanguages : 'Языки' ,
showCart : 'Корзина' ,
showProfile : 'Профиль' ,
showWishlist : 'Избранное' ,
showCompare : 'Сравнение' ,
showRegion : 'Регион' ,
companyName : 'Информация о компании' ,
address : 'Адрес' ,
phone : 'Телефон' ,
email : 'Email' ,
copyright : 'Копирайт' ,
paymentIcons : 'Иконки оплаты' ,
socialLinks : 'Социальные ссылки' ,
2026-07-16 02:06:26 +04:00
footerLogo : 'Логотип в футере' ,
addPaymentIcon : 'Добавить иконку оплаты' ,
removePaymentIcon : 'Удалить' ,
iconAltLabel : 'Подпись иконки' ,
addSocialLink : 'Добавить соцсеть' ,
removeSocialLink : 'Удалить' ,
socialLinkLabel : 'Платформа' ,
socialLinkUrl : 'URL' ,
invalidUrl : 'Введите корректный URL, начинающийся с http:// или https://.' ,
2026-07-10 13:52:01 +04:00
createPage : 'Создать страницу' ,
deletePage : 'Удалить страницу' ,
pageId : 'ID страницы' ,
slug : 'Slug' ,
iconLabel : 'Иконка' ,
showInFooter : 'Показывать в футере' ,
showInHeader : 'Показывать в хедере' ,
showInSitemap : 'Показывать в sitemap' ,
requiresAuthentication : 'Требует авторизацию' ,
footerGroup : 'Группа футера' ,
orderLabel : 'Порядок' ,
translationTitle : 'Заголовок перевода' ,
htmlPreview : 'HTML' ,
2026-07-15 04:11:18 +04:00
seoSection : 'SEO' ,
seoTitle : 'SEO заголовок' ,
seoDescription : 'SEO описание' ,
seoKeywords : 'Ключевые слова' ,
seoCanonical : 'Canonical URL' ,
seoOgTitle : 'OG заголовок' ,
seoOgDescription : 'OG описание' ,
seoOgImage : 'OG изображение' ,
2026-07-10 13:43:53 +04:00
visible : 'Видимость' ,
layoutLabel : 'Layout' ,
columns : 'Колонки' ,
height : 'Высота' ,
overlay : 'Overlay' ,
autoplay : 'Autoplay' ,
cardsPerRow : 'Карточек в ряд' ,
filtersLabel : 'Фильтры' ,
showBadges : 'Показывать badges' ,
showRating : 'Показывать рейтинг' ,
showPrice : 'Показывать цену' ,
widgetJson : 'JSON виджета' ,
reviews : 'Отзывы' ,
questions : 'Вопросы' ,
comments : 'Комментарии' ,
recommendations : 'Рекомендации' ,
recentlyViewed : 'Недавно просмотренные' ,
searchSuggestions : 'Поисковые подсказки' ,
searchHistory : 'История поиска' ,
livePreview : 'Живое превью' ,
2026-07-17 09:00:47 +04:00
previewChangesTitle : 'Изменения с последней публикации' ,
previewNoIssues : 'Нет проблем валидации.' ,
previewNoChanges : 'Нет изменений с последней публикации.' ,
previewChangeField : 'Поле' ,
previewChangeBefore : 'До' ,
previewChangeAfter : 'После' ,
2026-07-13 08:10:00 +04:00
languagesTab : 'Языки' ,
addLanguage : 'Добавить язык' ,
removeLanguage : 'Удалить' ,
setDefaultLanguage : 'Сделать языком по умолчанию' ,
defaultLanguageLabel : 'По умолчанию' ,
2026-07-13 08:57:42 +04:00
navigationTab : 'Навигация' ,
navigationHeader : 'Навигация в шапке' ,
navigationFooter : 'Навигация в подвале' ,
navigationFooterGrouped : 'Навигация подвала сгруппирована по колонкам и пока недоступна для редактирования здесь — используйте вкладку "Подвал".' ,
addLink : 'Добавить ссылку' ,
2026-07-17 10:18:08 +04:00
insertPageLink : 'Вставить ссылку на страницу' ,
linkedToPage : 'Связано с о страницей' ,
2026-07-13 08:57:42 +04:00
removeLink : 'Удалить' ,
linkLabel : 'Название' ,
linkUrl : 'URL' ,
2026-07-10 13:43:53 +04:00
exportBootstrap : 'Экспорт bootstrap' ,
importBootstrap : 'Импорт bootstrap' ,
exportedBootstrap : 'Экспортированный bootstrap' ,
importSource : 'Источник импорта' ,
importError : 'Импорт не удался. Некорректный JSON bootstrap.' ,
2026-07-09 02:29:12 +04:00
featureFlags : 'Фичи-флаги' ,
2026-07-13 10:51:05 +04:00
validationMissingLogo : 'В брендинге отсутствует логотип.' ,
validationNoLanguages : 'Н е настроены языки.' ,
2026-07-17 19:00:17 +04:00
validationDefaultLocaleNotSupported : 'Язык по умолчанию отсутствует в списке поддерживаемых языков.' ,
2026-07-13 10:51:05 +04:00
validationInvalidUrl : 'Некорректный URL маркетплейса.' ,
validationDuplicateSlugs : 'Две или более статические страницы имеют одинаковый slug.' ,
validationEmptyHomepage : 'Н а главной странице нет секций.' ,
validationMissingWidget : 'В секции главной страницы есть виджет без типа.' ,
validationDuplicateNavLinks : 'Две или более ссылки в навигации шапки дублируются.' ,
validationInvalidColors : 'Один или несколько цветов темы указаны некорректно.' ,
2026-07-14 12:21:33 +04:00
validationMissingTranslations : 'Часть контента не переведена на один из поддерживаемых языков.' ,
validationInvalidLayouts : 'Один или несколько макетов ссылаются на неизвестный тип раскладки.' ,
feat(project-editor): centralize schema-driven validation
Milestone 2 of the Configuration Engine sprint.
- Add schema/validators/primitives: pure isValidHexColor/HttpUrl/Email,
validateJson, validateCss, extractStyleBlocks, normalizeRoute. One function
per concern, no duplicated validator logic.
- Refactor ProjectValidator to compose the primitives and tag every issue with
section + fieldKey + severity ('error' blocks publish, 'warning' advisory).
Preserves all existing codes/messages; adds duplicate-routes, invalid-css,
invalid-widget-config checks.
- Facade: issuesByField, issuesBySection, blockingIssues, hasBlockingIssues;
publish() now gates on severity==='error' instead of any issue.
- i18n: add validationInvalidJson/Css/DuplicateRoutes/InvalidWidgetConfig to
the Translations interface + en/ru/hy.
- Specs: primitives + ProjectValidator (25 passing total).
Gate: tsc --noEmit, npm test (25/25), arch:check, build all green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 01:58:36 +04:00
validationInvalidJson : 'Конфигурация не является допустимым JSON.' ,
validationInvalidCss : 'Статическая страница содержит недопустимый CSS.' ,
validationDuplicateRoutes : 'Две или более страницы используют один и тот же маршрут.' ,
validationInvalidWidgetConfig : 'У виджета отсутствует обязательное поле (id, type, version или props).' ,
2026-07-17 16:57:43 +04:00
validationInvalidContactEmail : 'Контактный email компании указан некорректно.' ,
validationInvalidSocialLinkUrl : 'У одной или нескольких социальных ссылок в футере некорректный URL.' ,
validationIncompletePaymentIcon : 'У иконки оплаты в футере отсутствует изображение или альтернативный текст.' ,
2026-07-17 02:13:34 +04:00
undo : 'Отменить' ,
redo : 'Повторить' ,
2026-07-13 15:00:03 +04:00
statusDraft : 'Черновик' ,
statusPublished : 'Опубликовано' ,
unsavedChanges : 'Есть несохранённые изменения' ,
save : 'Сохранить' ,
publish : 'Опубликовать' ,
2026-07-13 15:57:54 +04:00
confirmLeaveUnsaved : 'Есть несохранённые изменения. Всё равно уйти?' ,
2026-07-25 20:43:43 +04:00
confirmPublish : 'Это сразу применит текущие изменения на витрине магазина вместо того, что покупатели видят сейчас. Продолжить?' ,
confirmRemoveLanguage : 'Это удалит язык и весь переведённый на него контент. Покупатели, использующие этот язык, увидят язык по умолчанию. Продолжить?' ,
2026-07-13 15:57:54 +04:00
promptLinkUrl : 'URL' ,
promptImageUrl : 'URL изображения' ,
2026-07-17 10:00:33 +04:00
promptEmbedUrl : 'URL для встраивания' ,
htmlEditorInvalidHtml : 'В этом HTML есть незакрытый или несовпадающий тег. Исправьте перед возвратом к визуальному редактору.' ,
2026-07-13 15:57:54 +04:00
htmlEditorCode : 'Код' ,
htmlEditorPreview : 'Предпросмотр' ,
2026-07-14 09:50:03 +04:00
lastSaved : 'Последнее сохранение' ,
draftRestored : 'Локальный черновик восстановлен из предыдущей сессии.' ,
dismiss : 'Скрыть' ,
resetDraft : 'Сбросить черновик' ,
resetSection : 'Сбросить секцию' ,
confirmResetDraft : 'Это отменит все неопубликованные изменения и восстановит последнюю опубликованную конфигурацию. Продолжить?' ,
confirmResetSection : 'Это отменит неопубликованные изменения только в этой секции. Продолжить?' ,
2026-07-14 16:05:09 +04:00
marketplaceNameDesc : 'Название, которое видят покупатели на витрине и во вкладке браузера.' ,
domainDesc : 'Домен, по которому покупатели заходят на маркетплейс. Изменение поля не переносит DNS.' ,
descriptionFieldDesc : 'Краткое описание для поисковых систем и превью в соцсетях.' ,
defaultLanguageDesc : 'Язык, который показывается, если у покупателя нет сохранённого предпочтения.' ,
supportedLanguagesDesc : 'Коды языков через запятую, между которыми может переключаться покупатель (например, en, ru, hy).' ,
logoDesc : 'URL полного логотипа, отображается в шапке на десктопе.' ,
smallLogoDesc : 'URL компактного логотипа для ограниченного пространства (например, мобильная шапка).' ,
faviconDesc : 'URL иконки вкладки браузера. Должен быть небольшим квадратным изображением.' ,
2026-07-17 15:22:45 +04:00
socialImageDesc : 'Изображение по умолчанию при публикации маркетплейса в соцсетях (Open Graph).' ,
galleryDesc : 'Дополнительные брендовые изображения для будущего использования в витрине.' ,
2026-07-17 15:29:55 +04:00
headerLayoutDesc : 'Как расположен контент шапки: по умолчанию (логотип слева, навигация разнесена) или по центру.' ,
headerStickyDesc : 'Закреплять шапку вверху экрана при прокрутке.' ,
2026-07-14 16:05:09 +04:00
marketplaceTitleDesc : 'Заголовок страницы для поисковых систем и вкладок браузера.' ,
primaryColorDesc : 'Основной цвет бренда для главных кнопок и акцентов. Должен быть корректным hex-цветом.' ,
secondaryColorDesc : 'Дополнительный цвет бренда для второстепенных элементов. Должен быть корректным hex-цветом.' ,
backgroundColorDesc : 'Цвет фона страницы по умолчанию. Должен быть корректным hex-цветом.' ,
surfaceColorDesc : 'Цвет фона карточек и приподнятых поверхностей. Должен быть корректным hex-цветом.' ,
textColorDesc : 'Цвет основного текста. Должен быть корректным hex-цветом.' ,
successColorDesc : 'Цвет для сообщений о б успехе и положительных состояний. Должен быть корректным hex-цветом.' ,
warningColorDesc : 'Цвет для предупреждающих сообщений. Должен быть корректным hex-цветом.' ,
dangerColorDesc : 'Цвет для ошибок и разрушительных действий. Должен быть корректным hex-цветом.' ,
themeModeLabel : 'Цветовой режим' ,
themeModeDesc : 'Определяет, отображается ли витрина в светлой, тёмной теме или по системным настройкам покупателя.' ,
themeModeLight : 'Светлый' ,
themeModeLightDesc : 'Всегда использовать светлую тему.' ,
themeModeDark : 'Тёмный' ,
themeModeDarkDesc : 'Всегда использовать тёмную тему.' ,
themeModeSystem : 'Системный' ,
themeModeSystemDesc : 'Использовать системные/браузерные настройки цветовой темы устройства покупателя.' ,
siteLayoutLabel : 'Макет сайта' ,
siteLayoutDesc : 'Общий режим оформления страниц на витрине.' ,
siteLayoutDefault : 'По умолчанию' ,
siteLayoutDefaultDesc : 'Стандартный макет с верхней навигацией.' ,
siteLayoutSidebarLeft : 'Боковая панель (слева)' ,
siteLayoutSidebarLeftDesc : 'Добавляет левую боковую панель, обычно для навигации по категориям.' ,
siteLayoutCarouselHome : 'Карусель на главной' ,
siteLayoutCarouselHomeDesc : 'Главная страница начинается с полноширинной карусели/hero-блока.' ,
siteLayoutMinimal : 'Минимальный' ,
siteLayoutMinimalDesc : 'Упрощённое оформление с минимумом элементов навигации.' ,
showLogoDesc : 'Показывать логотип маркетплейса в шапке.' ,
showSearchDesc : 'Показывать строку поиска в шапке.' ,
showCategoriesDesc : 'Показывать вход в меню категорий в шапке.' ,
showLanguagesDesc : 'Показывать переключатель языка в шапке.' ,
showCartDesc : 'Показывать иконку/ссылку корзины в шапке.' ,
showProfileDesc : 'Показывать вход в профиль/аккаунт в шапке.' ,
showWishlistDesc : 'Показывать вход в избранное в шапке.' ,
showCompareDesc : 'Показывать вход в сравнение товаров в шапке.' ,
showRegionDesc : 'Показывать выбор региона/страны в шапке.' ,
companyNameDesc : 'Юридическое название компании, показывается в футере и на статических страницах.' ,
addressDesc : 'Юридический/фактический адрес компании, показывается в футере.' ,
phoneDesc : 'Контактный телефон, показывается в футере.' ,
emailDesc : 'Контактный email, показывается в футере.' ,
copyrightDesc : 'Строка копирайта внизу каждой страницы.' ,
paymentIconsDesc : 'По одной иконке оплаты на строку (URL изображения и подпись), показываются в футере.' ,
socialLinksDesc : 'По одной социальной ссылке на строку (платформа и URL), показываются в футере.' ,
2026-07-16 02:06:26 +04:00
footerLogoDesc : 'Логотип, отображаемый в футере, если отличается от логотипа в шапке.' ,
iconAltLabelDesc : 'Альтернативный текст для иконки оплаты (для доступности).' ,
socialLinkUrlDesc : 'Полный URL профиля в соцсети, должен начинаться с http:// или https://.' ,
2026-07-14 16:05:09 +04:00
staticPagesFieldDesc : 'Статические страницы (о компании, условия, политика и т.д.), на которые ссылается футер.' ,
2026-07-19 13:58:57 +04:00
additionalPhones : 'Дополнительные номера телефонов' ,
additionalPhonesDesc : 'Добавьте номера, если поддерживаете клиентов в разных странах.' ,
addPhone : 'Добавить номер' ,
removePhone : 'Удалить номер' ,
additionalEmails : 'Дополнительные адреса email' ,
additionalEmailsDesc : 'Добавьте адреса для разных регионов или отделов.' ,
addEmail : 'Добавить email' ,
removeEmail : 'Удалить email' ,
footerColumns : 'Колонки подвала' ,
footerColumnsDesc : 'Группируйте ссылки по колонкам, как в настоящем подвале сайта. Перетаскивайте колонки и ссылки, чтобы изменить порядок.' ,
footerColumnTitlePlaceholder : 'Название колонки, напр. Компания' ,
footerLinkLabelPlaceholder : 'Текст ссылки' ,
footerLinkExistingPage : 'Существующая страница' ,
footerLinkCustomUrl : 'Свой URL' ,
addColumn : 'Добавить колонку' ,
removeColumn : 'Удалить колонку' ,
addColumnLink : 'Добавить ссылку' ,
removeColumnLink : 'Удалить ссылку' ,
2026-07-14 16:05:09 +04:00
sectionVisibleDesc : 'Показывать ли эту секцию главной страницы покупателям.' ,
layoutStrategyLabel : 'Стратегия раскладки' ,
layoutStrategyDesc : 'Как располагаются виджеты внутри этой секции.' ,
layoutStrategyStack : 'Стопка' ,
layoutStrategyStackDesc : 'Виджеты располагаются друг под другом вертикально.' ,
layoutStrategyGrid : 'Сетка' ,
layoutStrategyGridDesc : 'Виджеты располагаются в многоколоночной сетке.' ,
layoutStrategyHero : 'Hero' ,
layoutStrategyHeroDesc : 'Один крупный полноширинный промо-блок.' ,
layoutStrategyCarousel : 'Карусель' ,
layoutStrategyCarouselDesc : 'Виджеты прокручиваются горизонтально как карусель.' ,
layoutStrategySplit : 'Разделение' ,
layoutStrategySplitDesc : 'Контент делится на две колонки рядом друг с другом.' ,
sectionColumnsDesc : 'Количество колонок, если стратегия раскладки их поддерживает.' ,
widgetLayoutDesc : 'Название варианта раскладки в свободной форме, понятное этому виджету (например, "full-bleed", "boxed").' ,
widgetHeightDesc : 'Предпочтительная высота виджета (например, "480px" или "60vh").' ,
widgetOverlayDesc : 'Показывать тёмную подложку под текстом hero для читаемости.' ,
widgetAutoplayDesc : 'Автоматически прокручивать слайды hero без участия покупателя.' ,
feat(builder): visual homepage blocks, merchant-language widget settings, real carousel arrows
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
P0 user feedback: homepage builder showed raw section.id like 'section-hero'/'section-categories'; hero widget exposed 'full-bleed'/'boxed' and raw px/vh as free text with no explanation; Overlay/Autoplay toggles made no sense without a slides concept; product carousel widgets rendered arrows nowhere near a working carousel.
Homepage section (sections list -> visual blocks):
- Replaced raw section.id display with a merchant-facing block catalog (icon + name + one-line explanation) for hero/categories/featured-products/product-carousel/recently-viewed/banner/partners/custom-html
- Added block catalog picker to append new blocks (was fixed at whatever the seed data had - task asked 'what if we add manually? not fixed 3')
- Added duplicate and remove per block, alongside the existing drag-to-reorder
- Verified in browser: labels render correctly, add-block and duplicate both confirmed working end-to-end
Widgets section (hero widget):
- 'Layout' free-text replaced with a select (Full width / Boxed) instead of typing 'full-bleed'/'boxed' blind
- 'Height' free-text replaced with a select (Compact/Medium/Tall/Full screen) mapped to real vh values
- New Slides editor: title/subtitle pairs an admin can add/remove: this is the actual multi-slide data the Overlay/Autoplay toggles were referring to with nothing to point at before
- HeroWidgetData contract gains slides[]/autoplay; HeroWidgetComponent now renders a real rotator (dots, click-to-jump, autoplay interval) when more than one slide exists - previously autoplay/overlay props existed but there was no slideshow behavior anywhere to control
Carousel arrows root cause and fix:
- widget-manifest.json offers 'carousel' as a layout option for product-collection/product-carousel widgets, and the admin UI let you select it, but ProductCarouselWidgetComponent always rendered a static CSS grid regardless - there was no carousel implementation to have arrows in the first place
- Now renders a real horizontally-scrollable strip with working prev/next buttons (native scrollBy, disabled at each end) when section.layout.strategy === 'carousel'; falls back to the existing grid otherwise
- Confirmed src/app/components/items-carousel (a PrimeNG p-carousel) is dead code, not wired into any route or widget - not the source of the reported bug
New builder.* i18n keys (en/ru/hy), zero duplicate-key collisions verified via scan
2026-07-19 14:14:29 +04:00
heroLayoutFullBleed : 'Н а всю ширину (край в край)' ,
heroLayoutBoxed : 'В рамке (с отступами страницы)' ,
heroHeightCompact : 'Компактная' ,
heroHeightMedium : 'Средняя' ,
heroHeightTall : 'Высокая' ,
heroHeightFullScreen : 'Н а весь экран' ,
heroSlides : 'Слайды' ,
heroSlidesHint : 'Добавьте ещё слайды, чтобы получился слайд-шоу. Поля выше — это слайд 1. Автопрокрутка и точки появляются только при более чем одном слайде.' ,
heroSlideTitlePlaceholder : 'Заголовок слайда' ,
heroSlideSubtitlePlaceholder : 'Подзаголовок слайда' ,
addSlide : 'Добавить слайд' ,
removeSlide : 'Удалить слайд' ,
2026-07-14 16:05:09 +04:00
widgetColumnsDesc : 'Количество плиток категорий в ряду.' ,
widgetCardsPerRowDesc : 'Количество карточек товаров в ряду.' ,
widgetFiltersDesc : 'Показывать элементы управления фильтрами рядом с подборкой товаров.' ,
widgetShowBadgesDesc : 'Показывать бейджи, например "Новинка" или "Скидка", на карточках товаров.' ,
widgetShowRatingDesc : 'Показывать рейтинг звёздами на карточках товаров.' ,
widgetShowPriceDesc : 'Показывать цену на карточках товаров.' ,
widgetJsonDesc : 'Сырые свойства виджета в формате JSON. Используется, если для этого типа виджета нет отдельного редактора.' ,
2026-07-17 18:14:58 +04:00
widgetJsonInvalid : 'Некорректный JSON — сохранена последняя корректная версия.' ,
2026-07-14 16:05:09 +04:00
wishlistFeatureDesc : 'Разрешить покупателям сохранять товары в избранное.' ,
compareFeatureDesc : 'Разрешить покупателям сравнивать несколько товаров одновременно.' ,
reviewsFeatureDesc : 'Разрешить покупателям оставлять и читать отзывы о товарах.' ,
questionsFeatureDesc : 'Разрешить покупателям задавать вопросы о товарах и читать ответы.' ,
commentsFeatureDesc : 'Включить общие комментарии к контенту маркетплейса.' ,
recommendationsFeatureDesc : 'Показывать блоки рекомендованных товаров на витрине.' ,
recentlyViewedFeatureDesc : 'Показывать покупателям список "недавно просмотренные".' ,
searchSuggestionsDesc : 'Показывать живые подсказки поиска по мере ввода запроса.' ,
searchHistoryDesc : 'Запоминать и показывать недавние поисковые запросы покупателя.' ,
catalogNavigationModeLabel : 'Режим навигации каталога' ,
catalogNavigationModeDesc : 'Как покупатели перемещаются по категориям в каталоге.' ,
catalogNavDefault : 'По умолчанию' ,
catalogNavDefaultDesc : 'Стандартная навигация по категориям через хлебные крошки.' ,
catalogNavLeftCategory : 'Левая навигация по категориям' ,
catalogNavLeftCategoryDesc : 'Постоянное дерево категорий в левой боковой панели.' ,
catalogNavMegaCategory : 'М е г а -меню категорий' ,
catalogNavMegaCategoryDesc : 'Развёрнутый выпадающий список с подкатегориями и избранными товарами.' ,
catalogNavTopCarousel : 'Карусель категорий сверху' ,
catalogNavTopCarouselDesc : 'Горизонтально прокручиваемые чипы категорий над сеткой каталога.' ,
fix(builder): WCAG 2.1 AA accessibility fixes
RC A11Y-01 audit pass, Builder (project-editor) + content-management static
pages editor. Builds on 4ebc15f's composition pass without redoing it.
- Skip link: Builder's /edit and /edit/:section routes render outside the
storefront app-shell (isAdminRoute() branch has no skip link/landmark, only
a bare router-outlet, unlike the storefront's app.html) - added a
"skip to content" link targeting a new #builder-main-content landmark on
project-editor-page.component, reusing the existing adminShell.skipToContent
key and global .skip-link style. Nav landmark already had aria-label
(builder.appName) from the prior pass, verified correct.
- Save bar: added role="status"/aria-live="polite" to the save/publish status
block and role="status" to the draft-restored notice so save/publish state
changes and draft recovery are announced to screen readers (previously
silent DOM updates).
- Media picker (shared, used by both Builder and static-pages editor): upload
error message had no aria-live wiring - added role="alert".
- HTML editor (marketplace-html-editor): the contenteditable rich-text surface
had no accessible role/name - added role="textbox", aria-multiline="true",
aria-label.
- Drag-and-drop keyboard fallback (WCAG 2.1.1): homepage-section's block list
and footer-section's column list + per-column link list use Angular CDK
drag-drop (cdkDrag/cdkDropList), which has no built-in keyboard reordering.
Added move-up/move-down icon buttons (disabled at the first/last boundary),
matching the existing pattern already used by widgets-section and
navigation-section.
- Color picker: the swatch <input type="color"> had no accessible name (only
the paired text input was labelled via app-form-field) - added explicit
ariaLabel bindings to all 8 color-picker instances in theme-section.
- Languages: the new-locale code input relied on a placeholder ("de") as its
only accessible name - added ariaLabel + new builder.newLanguageLabel i18n
key (en/ru/hy).
- Undefined CSS var --color-primary (never defined anywhere, silently used its
hardcoded hex fallback and never responded to tenant theming - same
recurring bug class as 4ebc15f) - remapped to the real --primary-color token
in marketplace-html-editor, homepage-section, and section.shared (7 usages).
- role="alert" added to all 11 validation-error <p class="editor-error">
occurrences across footer/homepage/languages/navigation/preview/widgets
sections and the static-pages editor, so field/section validation messages
are announced.
- scope="col" added to preview-section's change-summary table headers.
Flagged, not fixed (design-system decisions, matching the storefront pass's
precedent):
- Save bar's --warning-color/--error-color/--info-color text fail WCAG AA
4.5:1 in some themes - same genuine brand semantic colors flagged (not
fixed) in fb1afb7's storefront pass; needs a deliberate token decision,
not a Builder-specific issue.
- locale-tabs (app-locale-tabs, shared) has role="tablist"/"tab" and
aria-selected but no roving-tabindex/arrow-key navigation - matches the
same partial-tablist pattern already accepted for product-tabs in the
storefront pass; all tabs remain natively Tab-focusable, so this meets
4.1.2/2.1.1 without the full ARIA authoring-practice pattern.
Verified: npx tsc --noEmit clean; npm run build green (only the pre-existing
bundle-budget warning, unrelated to this pass).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-24 09:01:38 +04:00
newLanguageLabel : 'Код нового языка' ,
2026-07-14 16:05:09 +04:00
newLanguageDesc : 'Код языка ISO для добавления в поддерживаемые языки витрины (например, de, fr).' ,
2026-07-17 18:31:01 +04:00
languageAlreadyAdded : 'Этот язык уже добавлен.' ,
2026-07-14 16:05:09 +04:00
languagesTabDesc : 'Языки, доступные покупателям. Язык по умолчанию используется как резервный везде.' ,
linkLabelDesc : 'Текст, отображаемый для этой ссылки навигации.' ,
linkUrlDesc : 'Путь или URL, на который ведёт эта ссылка навигации.' ,
linkVisibleDesc : 'Показывать ли эту ссылку навигации покупателям.' ,
feat(builder): redesign marketplace builder experience and navigation
Renamed the experience consistently to Marketplace Builder everywhere
visible (page title/subtitle, breadcrumbs, sidebar, dashboard quick
action/shortcut copy) - internal ProjectEditor class/selector names
kept as-is to avoid regressions. builder.title/subtitle no longer say
'bootstrap-config editing surface' to end users.
New business-oriented IA (builder-groups.model.ts): 12 existing
ProjectEditorSectionIds regrouped into 8 groups (Marketplace, Branding
and Design, Homepage, Content, Languages, Marketplace Features,
Navigation and Search, Preview) - every existing section mapped to
exactly one group, none dropped, no group points at a page that
doesn't exist.
New Builder landing page at /edit (was a redirect straight into the
General form): readiness percent, recommended next step, one overview
card per group (purpose + real complete/in-progress/not-started/unknown
status, icon+text never color-alone), a Marketplace Readiness
checklist, quick links. All derived from real facade/schema signals
(required-field fill state, modifiedSections, staticPages, catalog
counts via BackofficeDataService) or explicitly marked unknown
(the "preview reviewed" check has no tracking - shown as unknown,
never guessed).
Section pages (/edit/:section) now share one consistent header:
breadcrumb (Builder > Group > Section), draft/published + modified
badges, and a contextual help panel (what is this / where visible /
what happens if you skip it) sourced per group. Sidebar nav rewritten
as grouped, icon-led sections with per-section and per-group status
indicators; layout converted from a top pill-tab bar to a responsive
sidebar (desktop 280px, tablet 72px icon rail, mobile drawer with
Escape-to-close), matching the Sprint 1 admin shell pattern. Section
form components themselves untouched.
Routes: 'edit' is now its own landing route instead of redirecting to
'edit/general'; /builder and /project-editor redirect to 'edit'.
Sprint 1/2 destinations that pointed at edit/general now point at the
new edit landing page.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 09:43:03 +04:00
appName : 'Конструктор маркетплейса' ,
2026-07-19 08:25:29 +04:00
backToDashboard : 'Назад в панель управления' ,
2026-07-19 08:53:10 +04:00
languagesSummaryDesc : 'Языки, на которых доступен ваш маркетплейс. Первый — тот, что покупатели видят по умолчанию.' ,
manageLanguages : 'Управлять языками' ,
2026-07-19 08:48:22 +04:00
htmlToolBold : 'Жирный' ,
htmlToolItalic : 'Курсив' ,
htmlToolUnderline : 'Подчёркнутый' ,
htmlToolHeading : 'Заголовок' ,
htmlToolSubheading : 'Подзаголовок' ,
htmlToolBulletList : 'Маркированный список' ,
htmlToolNumberedList : 'Нумерованный список' ,
htmlToolLink : 'Вставить ссылку' ,
htmlToolImage : 'Вставить изображение' ,
htmlToolTable : 'Вставить таблицу' ,
htmlToolDivider : 'Разделительная линия' ,
htmlToolCodeBlock : 'Блок кода' ,
htmlToolEmbed : 'Встроить видео' ,
feat(builder): redesign marketplace builder experience and navigation
Renamed the experience consistently to Marketplace Builder everywhere
visible (page title/subtitle, breadcrumbs, sidebar, dashboard quick
action/shortcut copy) - internal ProjectEditor class/selector names
kept as-is to avoid regressions. builder.title/subtitle no longer say
'bootstrap-config editing surface' to end users.
New business-oriented IA (builder-groups.model.ts): 12 existing
ProjectEditorSectionIds regrouped into 8 groups (Marketplace, Branding
and Design, Homepage, Content, Languages, Marketplace Features,
Navigation and Search, Preview) - every existing section mapped to
exactly one group, none dropped, no group points at a page that
doesn't exist.
New Builder landing page at /edit (was a redirect straight into the
General form): readiness percent, recommended next step, one overview
card per group (purpose + real complete/in-progress/not-started/unknown
status, icon+text never color-alone), a Marketplace Readiness
checklist, quick links. All derived from real facade/schema signals
(required-field fill state, modifiedSections, staticPages, catalog
counts via BackofficeDataService) or explicitly marked unknown
(the "preview reviewed" check has no tracking - shown as unknown,
never guessed).
Section pages (/edit/:section) now share one consistent header:
breadcrumb (Builder > Group > Section), draft/published + modified
badges, and a contextual help panel (what is this / where visible /
what happens if you skip it) sourced per group. Sidebar nav rewritten
as grouped, icon-led sections with per-section and per-group status
indicators; layout converted from a top pill-tab bar to a responsive
sidebar (desktop 280px, tablet 72px icon rail, mobile drawer with
Escape-to-close), matching the Sprint 1 admin shell pattern. Section
form components themselves untouched.
Routes: 'edit' is now its own landing route instead of redirecting to
'edit/general'; /builder and /project-editor redirect to 'edit'.
Sprint 1/2 destinations that pointed at edit/general now point at the
new edit landing page.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 09:43:03 +04:00
breadcrumbRoot : 'Конструктор маркетплейса' ,
statusComplete : 'Готово' ,
statusInProgress : 'В процессе' ,
statusNotStarted : 'Н е начато' ,
statusUnknown : 'Пока не отслеживается' ,
draftBadge : 'Черновик' ,
publishedBadge : 'Опубликовано' ,
modifiedBadge : 'Есть несохранённые изменения' ,
helpToggleShow : 'Что это такое?' ,
helpToggleHide : 'Скрыть подсказку' ,
helpWhatIsThis : 'Что это' ,
helpWhySkip : 'Зачем это настраивать' ,
helpWhereVisible : 'Где это видят покупатели' ,
helpWhatIfSkip : 'Что будет, если пропустить' ,
helpWhenReturn : 'Когда возвращаться к этому разделу' ,
openSidebar : 'Открыть меню разделов' ,
closeSidebar : 'Закрыть меню разделов' ,
overviewTitle : 'Конструктор маркетплейса' ,
overviewSubtitle : 'Соберите свой маркетплейс шаг за шагом' ,
overviewReadinessLabel : 'Маркетплейс настроен на {{percent}}%' ,
overviewReadinessHint : 'Основано на обязательных полях, которые вы уже заполнили.' ,
overviewNextStepLabel : 'Рекомендуемый следующий шаг' ,
overviewNextStepFallback : 'В с е обязательные шаги выполнены — можно опубликовать маркетплейс.' ,
overviewQuickLinksTitle : 'Быстрые ссылки' ,
overviewSectionsTitle : 'Разделы конструктора' ,
overviewOpenSection : 'Открыть раздел' ,
overviewReadinessTitle : 'Готовность маркетплейса' ,
readinessLogoUploaded : 'Логотип загружен' ,
readinessHomepageConfigured : 'Главная страница настроена' ,
readinessThemeConfigured : 'Тема настроена' ,
readinessLanguagesConfigured : 'Языки настроены' ,
readinessContentPagesAdded : 'Добавлены информационные страницы' ,
readinessPreviewReviewed : 'Просмотр проверен' ,
readinessPublished : 'Маркетплейс опубликован' ,
readinessCategoriesExist : 'Есть категории' ,
readinessProductsExist : 'Есть товары' ,
groupMarketplaceLabel : 'Маркетплейс' ,
groupMarketplaceDescription : 'Название, адрес и основная информация о вашем маркетплейсе.' ,
groupMarketplacePurpose : 'Базовая информация, которая определяет ваш маркетплейс: название, домен и язык по умолчанию.' ,
groupMarketplaceWhere : 'Название и адрес видны во вкладке браузера, поисковой выдаче и на всех страницах магазина.' ,
groupMarketplaceSkip : 'Без названия и адреса маркетплейс не будет выглядеть завершённым для покупателей.' ,
groupBrandingLabel : 'Брендинг и оформление' ,
groupBrandingDescription : 'Логотип, цвета, шапка и подвал — визуальный стиль вашего магазина.' ,
groupBrandingPurpose : 'Настройте, как выглядит ваш маркетплейс: логотип, цветовую палитру и элементы шапки/подвала сайта.' ,
groupBrandingWhere : 'Изменения видны на каждой странице, которую видят покупатели.' ,
groupBrandingSkip : 'Маркетплейс будет использовать оформление по умолчанию, не отражающее ваш бренд.' ,
groupHomepageLabel : 'Главная страница' ,
groupHomepageDescription : 'Баннеры, витрины и виджеты, которые покупатели видят первыми.' ,
groupHomepagePurpose : 'Соберите главную страницу из блоков: приветственный баннер, подборки категорий и товаров, акции.' ,
groupHomepageWhere : 'Это первая страница, которую видит покупатель, открыв ваш маркетплейс.' ,
groupHomepageSkip : 'Главная страница останется пустой или будет использовать макет по умолчанию.' ,
groupContentLabel : 'Контент' ,
groupContentDescription : 'О компании, контакты, доставка, возврат и другие информационные страницы.' ,
groupContentPurpose : 'Добавьте страницы, которым покупатели доверяют: о компании, контакты, условия доставки и возврата.' ,
groupContentWhere : 'Ссылки на эти страницы обычно показываются в подвале сайта.' ,
groupContentSkip : 'У покупателей не будет ответов на вопросы о доставке, возврате и контактах — это снижает доверие.' ,
groupLanguagesLabel : 'Языки' ,
groupLanguagesDescription : 'Н а каких языках работает ваш маркетплейс.' ,
groupLanguagesPurpose : 'Выберите язык по умолчанию и добавьте дополнительные языки для покупателей из других регионов.' ,
groupLanguagesWhere : 'Переключатель языка виден в шапке сайта на каждой странице.' ,
groupLanguagesSkip : 'Маркетплейс будет доступен только на одном языке по умолчанию.' ,
groupFeaturesLabel : 'Функции маркетплейса' ,
groupFeaturesDescription : 'Список желаний, сравнение, отзывы, оформление заказа без регистрации и другое.' ,
groupFeaturesPurpose : 'Включите или отключите функции для покупателей: список желаний, сравнение товаров, гостевой заказ.' ,
groupFeaturesWhere : 'Влияет на страницы каталога, товара и оформления заказа.' ,
groupFeaturesSkip : 'Маркетплейс будет использовать функции по умолчанию.' ,
groupNavigationLabel : 'Навигация и поиск' ,
groupNavigationDescription : 'Меню сайта и то, как покупатели находят товары.' ,
groupNavigationPurpose : 'Настройте пункты меню и то, как устроена навигация по каталогу.' ,
groupNavigationWhere : 'Видно в шапке сайта на каждой странице.' ,
groupNavigationSkip : 'Покупатели будут использовать навигацию по умолчанию.' ,
groupPreviewLabel : 'Просмотр' ,
groupPreviewDescription : 'Посмотрите, как маркетплейс выглядит на десктопе, планшете и телефоне.' ,
groupPreviewPurpose : 'Проверьте маркетплейс глазами покупателя перед публикацией — на разных экранах.' ,
groupPreviewWhere : 'Это предпросмотр — покупатели е г о не видят.' ,
groupPreviewSkip : 'Вы можете опубликовать изменения непроверенными.' ,
feat(builder): implement professional brand management experience
New BrandOverviewComponent, mounted at the top of the existing
Branding section page (no route/schema/business-logic changes):
- Completion ring + recommended next step + last-modified timestamp,
computed from real facade signals (branding.logoUrl/faviconUrl/
socialImageUrl, theme.palette, theme.typography, lastSavedAt) -
nothing fabricated.
- Brand Health checklist (6 items: logo, favicon, colors, typography,
social image, accessibility) - icon+text, never color alone.
- Color palette preview: 10 swatches from the real ThemePaletteConfig
(primary/secondary/accent/success/warning/danger/backgrounds/text/
border), each with a readable label.
- Real WCAG contrast check (contrast.util.ts, relative-luminance
formula) between configured text and background colors - shows an
inline warning when below 4.5:1, never blocks publishing.
- Typography live preview using the configured heading/body font
families and base size.
- Social share preview card (Open Graph-style) using the existing
socialImageUrl + seo.default.title/description, with an explicit
empty state when no image is set yet.
Scope cut from the full brief given this session's cost already well
over budget entering this sprint - see Known limitations in the final
report (no multi-variant logo/favicon management, no live responsive
device preview, no new media library/asset picker; all reuse the
existing single-logo/single-favicon fields and image-field upload
component as-is).
Could not verify live in-browser this sprint: port 4200 is held by
another chat's dev server. Verified via `tsc --noEmit` (clean) and
manual template/binding review only; one binding (`--pct` custom-
property style binding) was replaced with a plain computed string to
remove an unverifiable risk rather than ship it unverified.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 10:13:35 +04:00
brandOverviewTitle : 'Идентичность бренда' ,
brandOverviewSubtitle : 'Логотип, цвета и шрифты, которые видят покупатели на каждой странице.' ,
brandOverviewComplete : 'Бренд полностью настроен.' ,
brandLastModified : 'Последнее изменение' ,
brandFaviconUploaded : 'Иконка сайта загружена' ,
brandColorsSelected : 'Цвета бренда выбраны' ,
brandTypographyConfigured : 'Шрифты настроены' ,
brandSocialImageUploaded : 'Изображение для соцсетей загружено' ,
brandAccessibilityPassed : 'Контрастность текста в норме' ,
brandColorsPreviewTitle : 'Цвета маркетплейса' ,
brandTypographyPreviewTitle : 'Шрифты' ,
brandSocialPreviewTitle : 'Как это выглядит при публикации ссылки' ,
brandTypeSampleHeading : 'Пример заголовка' ,
brandTypeSampleBody : 'Пример основного текста, который видят покупатели.' ,
brandContrastWarning : 'Текст на фоне читается плохо — рассмотрите более контрастные цвета. Публикацию это не блокирует.' ,
brandSocialEmpty : 'Изображение для соцсетей ещё не загружено — при публикации ссылки покупатели увидят пустую карточку.' ,
brandAccentColor : 'Акцентный' ,
brandBorderColor : 'Границы' ,
feat(builder): implement visual homepage builder
New HomepageOverviewComponent (Tasks 1+8), mounted at the top of the
existing Homepage section page: completion ring, active/hidden section
counts, recommended next step, last-modified timestamp, and a 6-item
Homepage Health checklist (hero/categories/products/promotion/
newsletter/any-sections) - all derived from the real page.sections/
widgets data already in the facade, nothing fabricated.
Existing page-level drag-and-drop reordering (homepage-section's
CdkDragDrop over page.sections) was already implemented pre-Sprint 5 -
left as-is per "build on top of, do not replace."
Widgets section (Task 2) rewritten from a bare list into visual cards:
per-widget icon + humanized type label (hero/categories/product-
collection), a visible/hidden toggle and badge, up/down move buttons
(keyboard-accessible reorder within a section - see Known limitations
for why this replaces pointer drag for widgets specifically), duplicate,
and remove (with confirm). The existing per-type field editors (hero/
categories/product-collection) are unchanged; the raw-JSON fallback for
unknown widget types now sits behind a collapsed "Advanced settings"
disclosure instead of being the default view.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 10:24:13 +04:00
homepageOverviewTitle : 'Главная страница' ,
homepageOverviewSubtitle : 'Из чего состоит главная страница вашего маркетплейса.' ,
homepageOverviewComplete : 'Главная страница полностью настроена.' ,
homepageActiveSections : 'Активные блоки' ,
homepageDisabledSections : 'Скрытые блоки' ,
homepageHealthHero : 'Приветственный баннер добавлен' ,
homepageHealthCategories : 'Витрина категорий добавлена' ,
homepageHealthProducts : 'Витрина товаров добавлена' ,
homepageHealthPromotion : 'Блок акции добавлен' ,
homepageHealthNewsletter : 'Форма подписки добавлена' ,
homepageHealthAnySections : 'Н а странице есть хотя бы один блок' ,
widgetTypeHero : 'Приветственный баннер' ,
widgetTypeCategories : 'Витрина категорий' ,
widgetTypeProducts : 'Витрина товаров' ,
widgetHidden : 'Скрыт' ,
widgetVisible : 'Показывать' ,
widgetMoveUp : 'Переместить выше' ,
widgetMoveDown : 'Переместить ниже' ,
widgetDuplicate : 'Дублировать' ,
widgetRemove : 'Удалить' ,
widgetRemoveConfirm : 'Удалить этот блок с главной страницы?' ,
widgetAdvancedSettings : 'Дополнительные настройки' ,
fix(builder): composition audit fixes for project editor sections
- Reset-section button: raw <button> with hardcoded colors -> app-button variant="danger"
- section.shared.scss: raw button/input/select colors switched to CSS theme vars (--primary-color, --bg-primary, --bg-secondary, --error-color) instead of bare hex
- save-bar scss referenced nonexistent CSS vars (--surface, --border, --warning, --danger, --muted-foreground, --info-bg, --info) that always fell back to hardcoded hex; renamed to the real theme vars (--bg-primary, --border-color, --warning-color, --error-color, --text-secondary, --info-color) so the save bar is actually theme-aware
- footer/homepage/widgets section scss: nonexistent --danger-color var renamed to --error-color
- static-pages-editor: replaced dead `.editor-section-card` wrapper class (removed from shared stylesheet in the Sprint 30 redesign, never migrated here) with app-section-card, restoring the card chrome every sibling editor section has
- widgets-section: empty state (no widgets) rendered nothing; added app-empty-state
- homepage-section: empty state (no homepage page) rendered nothing; added app-empty-state
- navigation-section: header/footer nav move-up/move-down buttons had no accessible name (bare uarr/darr glyphs); added aria-label
- Added builder.widgetsEmptyTitle/Desc and builder.homepageEmptyTitle/Desc i18n keys (en/ru/hy)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 10:47:37 +04:00
widgetsEmptyTitle : 'Пока нет виджетов' ,
widgetsEmptyDesc : 'Добавьте блок на главную страницу во вкладке «Главная», и е г о настройки появятся здесь.' ,
homepageEmptyTitle : 'Главная страница не настроена' ,
homepageEmptyDesc : 'В вашем магазине пока не настроена главная страница. Обратитесь в поддержку, чтобы её создать.' ,
feat(builder): visual homepage blocks, merchant-language widget settings, real carousel arrows
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
P0 user feedback: homepage builder showed raw section.id like 'section-hero'/'section-categories'; hero widget exposed 'full-bleed'/'boxed' and raw px/vh as free text with no explanation; Overlay/Autoplay toggles made no sense without a slides concept; product carousel widgets rendered arrows nowhere near a working carousel.
Homepage section (sections list -> visual blocks):
- Replaced raw section.id display with a merchant-facing block catalog (icon + name + one-line explanation) for hero/categories/featured-products/product-carousel/recently-viewed/banner/partners/custom-html
- Added block catalog picker to append new blocks (was fixed at whatever the seed data had - task asked 'what if we add manually? not fixed 3')
- Added duplicate and remove per block, alongside the existing drag-to-reorder
- Verified in browser: labels render correctly, add-block and duplicate both confirmed working end-to-end
Widgets section (hero widget):
- 'Layout' free-text replaced with a select (Full width / Boxed) instead of typing 'full-bleed'/'boxed' blind
- 'Height' free-text replaced with a select (Compact/Medium/Tall/Full screen) mapped to real vh values
- New Slides editor: title/subtitle pairs an admin can add/remove: this is the actual multi-slide data the Overlay/Autoplay toggles were referring to with nothing to point at before
- HeroWidgetData contract gains slides[]/autoplay; HeroWidgetComponent now renders a real rotator (dots, click-to-jump, autoplay interval) when more than one slide exists - previously autoplay/overlay props existed but there was no slideshow behavior anywhere to control
Carousel arrows root cause and fix:
- widget-manifest.json offers 'carousel' as a layout option for product-collection/product-carousel widgets, and the admin UI let you select it, but ProductCarouselWidgetComponent always rendered a static CSS grid regardless - there was no carousel implementation to have arrows in the first place
- Now renders a real horizontally-scrollable strip with working prev/next buttons (native scrollBy, disabled at each end) when section.layout.strategy === 'carousel'; falls back to the existing grid otherwise
- Confirmed src/app/components/items-carousel (a PrimeNG p-carousel) is dead code, not wired into any route or widget - not the source of the reported bug
New builder.* i18n keys (en/ru/hy), zero duplicate-key collisions verified via scan
2026-07-19 14:14:29 +04:00
homepageBlocksHint : 'Это блоки, которые покупатели видят на главной странице сверху вниз. Перетаскивайте за ручку, чтобы изменить порядок.' ,
2026-07-27 10:00:42 +04:00
livePreviewTitle : 'Живой предпросмотр' ,
livePreviewHint : 'Наведите курсор на поле, чтобы увидеть, что оно меняет.' ,
livePreviewEmpty : 'Пока нечего показать.' ,
livePreviewButtonLabel : 'В магазин' ,
usedByLabel : 'Используется в:' ,
usedByHeader : 'Шапка сайта' ,
usedByFooter : 'Подвал сайта' ,
usedBySeo : 'Результаты поиска' ,
usedByButtons : 'Кнопки' ,
usedByLinks : 'Ссылки' ,
usedByBadges : 'Значки' ,
usedByPageBackground : 'Фон страницы' ,
feat: Page Editor UX Phase 2 - unsaved changes panel, property search, reset property, empty states
- ProjectEditorFacade.resetField(key): field-level revert-to-original, reusing getByPath + a new immutable setByPath (write-side counterpart, scalar/object dot-paths only).
- app-form-field gains showReset/resetLabel/(resetClicked) - a reusable per-field reset affordance, wired on branding logo/title and theme primary/background color.
- Save bar: unsaved-changes count is now clickable, expanding a field-level diff list (reuses facade.changeSummary(), already built for the Preview tab) with jump-to-section links.
- BuilderPropertySearchComponent: filters EditorSchemaService.all() by translated label/hint, jumps to the owning section - no new registry, reuses the existing schema.
- navigation-section: app-empty-state (existing component) added for empty header/footer link lists.
- Reset Section and Draft/Published badge were already implemented; not touched.
- New copy added as translation keys (en/ru/hy).
2026-07-27 11:12:35 +04:00
resetField : 'Сбросить' ,
propertySearchLabel : 'Поиск настроек' ,
propertySearchPlaceholder : 'Поиск настроек…' ,
propertySearchResultsLabel : 'Результаты поиска' ,
propertySearchNoResults : 'Совпадений не найдено.' ,
unsavedChangesPanelTitle : 'Несохранённые изменения' ,
navigationHeaderEmptyTitle : 'В шапке пока нет ссылок' ,
navigationHeaderEmptyDesc : 'Добавьте ссылку, чтобы покупатели могли перемещаться из шапки сайта.' ,
navigationFooterEmptyTitle : 'В подвале пока нет ссылок' ,
navigationFooterEmptyDesc : 'Добавьте ссылку, чтобы покупатели могли перемещаться из подвала сайта.' ,
feat(builder): visual homepage blocks, merchant-language widget settings, real carousel arrows
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
P0 user feedback: homepage builder showed raw section.id like 'section-hero'/'section-categories'; hero widget exposed 'full-bleed'/'boxed' and raw px/vh as free text with no explanation; Overlay/Autoplay toggles made no sense without a slides concept; product carousel widgets rendered arrows nowhere near a working carousel.
Homepage section (sections list -> visual blocks):
- Replaced raw section.id display with a merchant-facing block catalog (icon + name + one-line explanation) for hero/categories/featured-products/product-carousel/recently-viewed/banner/partners/custom-html
- Added block catalog picker to append new blocks (was fixed at whatever the seed data had - task asked 'what if we add manually? not fixed 3')
- Added duplicate and remove per block, alongside the existing drag-to-reorder
- Verified in browser: labels render correctly, add-block and duplicate both confirmed working end-to-end
Widgets section (hero widget):
- 'Layout' free-text replaced with a select (Full width / Boxed) instead of typing 'full-bleed'/'boxed' blind
- 'Height' free-text replaced with a select (Compact/Medium/Tall/Full screen) mapped to real vh values
- New Slides editor: title/subtitle pairs an admin can add/remove: this is the actual multi-slide data the Overlay/Autoplay toggles were referring to with nothing to point at before
- HeroWidgetData contract gains slides[]/autoplay; HeroWidgetComponent now renders a real rotator (dots, click-to-jump, autoplay interval) when more than one slide exists - previously autoplay/overlay props existed but there was no slideshow behavior anywhere to control
Carousel arrows root cause and fix:
- widget-manifest.json offers 'carousel' as a layout option for product-collection/product-carousel widgets, and the admin UI let you select it, but ProductCarouselWidgetComponent always rendered a static CSS grid regardless - there was no carousel implementation to have arrows in the first place
- Now renders a real horizontally-scrollable strip with working prev/next buttons (native scrollBy, disabled at each end) when section.layout.strategy === 'carousel'; falls back to the existing grid otherwise
- Confirmed src/app/components/items-carousel (a PrimeNG p-carousel) is dead code, not wired into any route or widget - not the source of the reported bug
New builder.* i18n keys (en/ru/hy), zero duplicate-key collisions verified via scan
2026-07-19 14:14:29 +04:00
addBlockHint : 'Добавить блок на главную страницу:' ,
dragToReorder : 'Перетащите, чтобы изменить порядок' ,
blockRemoveConfirm : 'Удалить этот блок с главной страницы?' ,
blockHero : 'Приветственный баннер' ,
blockHeroDesc : 'Крупный баннер вверху главной страницы с заголовком и кнопкой призыва к действию.' ,
blockCategories : 'Категории' ,
blockCategoriesDesc : 'Сетка плиток категорий, чтобы покупатели могли просматривать разделы.' ,
blockFeaturedProducts : 'Рекомендуемые товары' ,
blockFeaturedProductsDesc : 'Сетка отобранных вручную или самых продаваемых товаров.' ,
blockProductCarousel : 'Карусель товаров' ,
blockProductCarouselDesc : 'Горизонтально прокручиваемый ряд товаров с о стрелками для просмотра других.' ,
blockRecentlyViewed : 'Недавно просмотренные' ,
blockRecentlyViewedDesc : 'Показывает каждому покупателю товары, которые он недавно смотрел.' ,
blockBanner : 'Промо-баннер' ,
blockBannerDesc : 'Одно изображение с заголовком и кнопкой — для акций или объявлений.' ,
blockPartners : 'Логотипы партнёров' ,
blockPartnersDesc : 'Ряд логотипов брендов или партнёров для доверия.' ,
blockCustomHtml : 'Свой блок' ,
blockCustomHtmlDesc : 'Произвольный HTML для всего, что не покрывают другие блоки.' ,
2026-07-09 02:29:12 +04:00
} ,
2026-07-14 12:21:33 +04:00
dashboard : {
title : 'Панель управления' ,
subtitle : 'Обзор вашего маркетплейса' ,
cardMarketplaceStatus : 'Статус маркетплейса' ,
cardProjectName : 'Название проекта' ,
cardCurrentTheme : 'Текущая тема' ,
cardLanguages : 'Языки' ,
cardCategoriesCount : 'Категории' ,
cardProductsCount : 'Товары' ,
cardOrders : 'Заказы' ,
cardRevenue : 'Выручка' ,
cardLastPublish : 'Последняя публикация' ,
cardLastDraftSave : 'Последнее сохранение черновика' ,
cardBootstrapVersion : 'Версия конфигурации' ,
cardActiveLayout : 'Активный макет' ,
cardEnabledWidgets : 'Активные виджеты' ,
stateLoading : 'Загрузка...' ,
stateEmpty : 'Пока нет данных' ,
stateError : 'Н е удалось загрузить карточку' ,
statePendingBackend : 'Ожидает интеграции с бэкендом' ,
never : 'Никогда' ,
quickActionsTitle : 'Быстрые действия' ,
feat(builder): redesign marketplace builder experience and navigation
Renamed the experience consistently to Marketplace Builder everywhere
visible (page title/subtitle, breadcrumbs, sidebar, dashboard quick
action/shortcut copy) - internal ProjectEditor class/selector names
kept as-is to avoid regressions. builder.title/subtitle no longer say
'bootstrap-config editing surface' to end users.
New business-oriented IA (builder-groups.model.ts): 12 existing
ProjectEditorSectionIds regrouped into 8 groups (Marketplace, Branding
and Design, Homepage, Content, Languages, Marketplace Features,
Navigation and Search, Preview) - every existing section mapped to
exactly one group, none dropped, no group points at a page that
doesn't exist.
New Builder landing page at /edit (was a redirect straight into the
General form): readiness percent, recommended next step, one overview
card per group (purpose + real complete/in-progress/not-started/unknown
status, icon+text never color-alone), a Marketplace Readiness
checklist, quick links. All derived from real facade/schema signals
(required-field fill state, modifiedSections, staticPages, catalog
counts via BackofficeDataService) or explicitly marked unknown
(the "preview reviewed" check has no tracking - shown as unknown,
never guessed).
Section pages (/edit/:section) now share one consistent header:
breadcrumb (Builder > Group > Section), draft/published + modified
badges, and a contextual help panel (what is this / where visible /
what happens if you skip it) sourced per group. Sidebar nav rewritten
as grouped, icon-led sections with per-section and per-group status
indicators; layout converted from a top pill-tab bar to a responsive
sidebar (desktop 280px, tablet 72px icon rail, mobile drawer with
Escape-to-close), matching the Sprint 1 admin shell pattern. Section
form components themselves untouched.
Routes: 'edit' is now its own landing route instead of redirecting to
'edit/general'; /builder and /project-editor redirect to 'edit'.
Sprint 1/2 destinations that pointed at edit/general now point at the
new edit landing page.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 09:43:03 +04:00
actionEditProject : 'Конструктор маркетплейса' ,
2026-07-14 12:21:33 +04:00
actionCategories : 'Категории' ,
actionProducts : 'Товары' ,
actionStaticPages : 'Статические страницы' ,
actionTransactions : 'Транзакции' ,
actionOrders : 'Заказы' ,
actionMediaLibrary : 'Медиатека' ,
2026-07-15 20:25:12 +04:00
actionUsers : 'Пользователи и права' ,
actionMonitoring : 'Мониторинг' ,
actionAnalytics : 'Аналитика' ,
2026-07-14 12:21:33 +04:00
actionPreviewMarketplace : 'Просмотр маркетплейса' ,
activityTitle : 'Недавняя активность' ,
feat(admin): redesign dashboard into professional SaaS homepage
Replaced the placeholder dashboard with a real business homepage built
on 6 new reusable widget components (DashboardSection, DashboardCard,
DashboardMetric, DashboardStatusRow, DashboardTimeline,
DashboardShortcutCard), all wired through shared app-card/app-skeleton/
app-empty-state.
Sections: Welcome (tenant, env badge, current user, last publish/save -
all real facade signals, never blank), Quick Actions (large cards: add
product, create category, open builder, edit homepage, media, orders),
Draft Status (real dirty/modifiedFields/publish/discard from
ProjectEditorFacade), Marketplace Health (9 checks - config, product/
category counts, missing translations, draft, static-pages-unpublished,
homepage/theme configured, all real; images-without-alt shown as
'not tracked yet' rather than fabricated), Recent Activity (existing
localStorage-backed history service, loading/empty states), Useful
Shortcuts, Documentation (honest coming-soon list, no dead links).
12-column responsive grid: 3-across cards on desktop, 2-column on
tablet, single column on mobile, no horizontal scroll. Keyboard/focus/
ARIA per shortcut card and status row; health status never conveyed by
color alone (icon + text every time).
AdminDashboardHealthCheck (boolean 'healthy' shape) and its facade
signal are untouched - AdminMonitoringPageComponent also consumes them.
New richer status data lives in a separate homeHealthChecks signal/
AdminDashboardHomeHealthCheck type instead of widening the shared one.
Added ~50 new dashboard.* / kept existing i18n strings across ru/en/hy;
no raw keys.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 08:59:29 +04:00
activityEmpty : 'Пока нет активности' ,
2026-07-14 12:21:33 +04:00
activityDraftSaved : 'Черновик сохранён' ,
activityPublished : 'Опубликовано' ,
healthTitle : 'Состояние системы' ,
healthAllClear : 'В с е проверки пройдены' ,
healthBootstrapValid : 'Bootstrap корректен' ,
healthConfigurationValid : 'Конфигурация корректна' ,
healthMissingTranslations : 'Отсутствуют переводы' ,
healthInvalidColors : 'Некорректные цвета' ,
healthInvalidWidgetReferences : 'Некорректные ссылки виджетов' ,
healthInvalidLayouts : 'Некорректные макеты' ,
comingSoonTitle : 'Скоро' ,
comingSoonDescription : 'Этот раздел ещё не реализован. Загляните позже.' ,
backToDashboard : 'Вернуться на панель управления' ,
feat(admin): redesign dashboard into professional SaaS homepage
Replaced the placeholder dashboard with a real business homepage built
on 6 new reusable widget components (DashboardSection, DashboardCard,
DashboardMetric, DashboardStatusRow, DashboardTimeline,
DashboardShortcutCard), all wired through shared app-card/app-skeleton/
app-empty-state.
Sections: Welcome (tenant, env badge, current user, last publish/save -
all real facade signals, never blank), Quick Actions (large cards: add
product, create category, open builder, edit homepage, media, orders),
Draft Status (real dirty/modifiedFields/publish/discard from
ProjectEditorFacade), Marketplace Health (9 checks - config, product/
category counts, missing translations, draft, static-pages-unpublished,
homepage/theme configured, all real; images-without-alt shown as
'not tracked yet' rather than fabricated), Recent Activity (existing
localStorage-backed history service, loading/empty states), Useful
Shortcuts, Documentation (honest coming-soon list, no dead links).
12-column responsive grid: 3-across cards on desktop, 2-column on
tablet, single column on mobile, no horizontal scroll. Keyboard/focus/
ARIA per shortcut card and status row; health status never conveyed by
color alone (icon + text every time).
AdminDashboardHealthCheck (boolean 'healthy' shape) and its facade
signal are untouched - AdminMonitoringPageComponent also consumes them.
New richer status data lives in a separate homeHealthChecks signal/
AdminDashboardHomeHealthCheck type instead of widening the shared one.
Added ~50 new dashboard.* / kept existing i18n strings across ru/en/hy;
no raw keys.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 08:59:29 +04:00
welcomeEyebrow : 'С возвращением' ,
welcomeFallbackTenant : 'Ваш маркетплейс' ,
envProduction : 'Продакшн' ,
envDevelopment : 'Разработка' ,
factCurrentUser : 'Текущий пользователь' ,
factTenant : 'Магазин' ,
quickActionsDescription : 'Самые частые задачи — начните здесь' ,
actionAddProduct : 'Добавить товар' ,
actionAddProductDescription : 'Создать новую карточку товара' ,
actionCreateCategory : 'Создать категорию' ,
actionCreateCategoryDescription : 'Добавить категорию в каталог' ,
actionEditProjectDescription : 'Открыть конструктор маркетплейса' ,
actionEditHomepage : 'Редактировать главную' ,
actionEditHomepageDescription : 'Настроить виджеты главной страницы' ,
actionMediaLibraryDescription : 'Загрузить и организовать файлы' ,
actionOrdersDescription : 'Просмотреть последние заказы' ,
draftStatusTitle : 'Статус черновика' ,
draftStatusHasChanges : 'Есть несохранённые изменения, ожидающие публикации.' ,
draftStatusAllPublished : 'Всё опубликовано. Черновика нет.' ,
draftStatusMoreFields : 'ещё {{count}}' ,
draftOpenBuilder : 'Открыть конструктор' ,
draftPublish : 'Опубликовать' ,
draftDiscard : 'Отменить черновик' ,
healthProductsCount : 'Товары' ,
healthCategoriesCount : 'Категории' ,
healthDraftExists : 'Черновик' ,
healthImagesWithoutAlt : 'Изображения без alt-текста' ,
healthStaticPagesUnpublished : 'Неопубликованные статические страницы' ,
healthHomepageConfigured : 'Главная страница настроена' ,
healthThemeConfigured : 'Тема настроена' ,
statusHealthy : 'В порядке' ,
statusAttention : 'Требует внимания' ,
statusUnhealthy : 'Проблема' ,
statusUnknown : 'Пока не отслеживается' ,
activityEmptyHint : 'Сохраните или опубликуйте изменение, чтобы увидеть е г о здесь.' ,
activityUnavailable : 'История активности недоступна' ,
activityUnavailableHint : 'Н е удалось подключиться к источнику данных. Попробуйте обновить страницу позже.' ,
activityErrorHint : 'Н е удалось загрузить недавнюю активность.' ,
shortcutsTitle : 'Полезные ссылки' ,
shortcutsDescription : 'Часто используемые разделы админ-панели' ,
shortcutMarketplaceBuilder : 'Конструктор маркетплейса' ,
shortcutSettings : 'Настройки' ,
shortcutContent : 'Контент' ,
docTitle : 'Документация' ,
docDocumentation : 'Документация' ,
docKeyboardShortcuts : 'Горячие клавиши' ,
docReportIssue : 'Сообщить о проблеме' ,
docReleaseNotes : 'Список изменений' ,
2026-07-14 12:21:33 +04:00
} ,
2026-07-10 13:52:01 +04:00
staticPages : {
notFound : 'Страница не найдена' ,
backHome : 'Н а главную' ,
duplicateSlug : 'Дублирующиеся slug запрещены.' ,
emptyTitle : 'У каждой страницы должен быть хотя бы один заголовок.' ,
feat(static-pages): CRUD completion + search/filter/bulk actions
Milestone 2 of the Static Pages Module sprint.
- StaticPagesEditorComponent: duplicate page, confirm-before-delete/bulk-
delete (matches the resetDraft confirm pattern), route/enabled/customTemplate/
media(hero/thumbnail/gallery) fields wired into the card, per-page publish/
unpublish action, status + duplicate-route/invalid-html/invalid-seo badges.
- Search (id/slug/route/title across all locales), filter by status
(draft/published) and by locale (hides pages missing a translation for the
selected locale) - all local computed() filters, no new service.
- Bulk selection (per-row + select-all-visible checkboxes) with bulk delete/
enable/disable/publish/unpublish, one updateBootstrap() call each.
- Correctness note: introduced `allPages` (unfiltered) vs `pages` (filtered
view) computeds. Every mutation (create/duplicate/delete/move/bulk) reads
from allPages(), never the filtered pages() - reading from the filtered
view would have silently deleted whatever an active search/filter hid on
the next persist(). Documented inline on persist() as a guardrail for
future edits.
- Fixed a template compile error found by the build gate: Angular templates
don't support inline arrow functions in binding expressions
((ngModelChange)="...map(v => v.trim())..." failed to parse) - moved the
gallery CSV-parsing into a component method (updateGallery).
- SEO robots field added to the page card (validated against a known-token
set from M1).
- i18n: staticPages.* extended (search/filter/bulk/route/enabled/status/
media/robots/disabled labels) across the interface + en/ru/hy.
Gate: tsc --noEmit, npm test (57/57), arch:check, build all green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 09:55:21 +04:00
duplicateRoute : 'Два или более страниц используют один и тот же маршрут.' ,
invalidHtml : 'Н а этой странице некорректный HTML-контент.' ,
invalidSeo : 'У этой страницы некорректное SEO-поле (canonical/OG-изображение или значение robots).' ,
searchPlaceholder : 'Поиск страниц…' ,
filterAll : 'В с е статусы' ,
filterAllLocales : 'В с е языки' ,
confirmDeletePage : 'Удалить эту страницу? Это действие нельзя отменить.' ,
confirmBulkDelete : 'Удалить выбранные страницы? Это действие нельзя отменить.' ,
duplicatePage : 'Дублировать' ,
selectAll : 'Выбрать все' ,
selectedCount : 'выбрано' ,
bulkDelete : 'Удалить выбранные' ,
bulkEnable : 'Включить выбранные' ,
bulkDisable : 'Отключить выбранные' ,
bulkPublishAction : 'Опубликовать выбранные' ,
bulkUnpublish : 'Снять с публикации выбранные' ,
routeLabel : 'Маршрут' ,
enabledLabel : 'Включена' ,
statusLabel : 'Статус' ,
publishPageAction : 'Опубликовать страницу' ,
unpublishPageAction : 'Снять страницу с публикации' ,
heroImageLabel : 'Главное изображение' ,
thumbnailLabel : 'Миниатюра' ,
galleryLabel : 'Галерея' ,
customTemplateLabel : 'Пользовательский шаблон' ,
seoRobotsLabel : 'Robots' ,
disabledBadge : 'Отключена' ,
2026-07-17 10:11:31 +04:00
previewDesktop : 'Десктоп' ,
previewTablet : 'Планшет' ,
previewMobile : 'Телефон' ,
previewToggle : 'Превью' ,
2026-07-10 13:52:01 +04:00
} ,
2026-07-18 11:02:26 +04:00
contentManagement : {
publishedPages : 'Опубликованные страницы' ,
draftPages : 'Черновики' ,
missingLegalPages : 'Отсутствующие юридические страницы' ,
seoHealth : 'SEO-здоровье' ,
lastEdited : 'Последнее изменение' ,
lastEditedNever : 'Никогда' ,
completionLabel : 'Готовность' ,
recommendedNext : 'Рекомендуемый следующий шаг' ,
recommendAddTitles : 'У некоторых страниц отсутствует заголовок хотя бы на одном языке.' ,
recommendFixSeo : 'Н а одной из страниц есть SEO-поле, которое нужно исправить (canonical/OG-изображение или robots).' ,
recommendPublish : 'Обязательная юридическая страница всё ещё черновик — опубликуйте её.' ,
recommendNone : 'Отлично — контент в хорошем состоянии.' ,
openAction : 'Открыть' ,
backToPages : 'Назад к страницам' ,
groupContent : 'Контент' ,
groupSeo : 'SEO' ,
groupSharing : 'Публикация в соцсетях' ,
groupAdvanced : 'Дополнительно' ,
groupAdvancedHtml : 'Исходный HTML (дополнительно)' ,
2026-07-25 20:43:43 +04:00
pageContentLabel : 'Содержимое страницы' ,
pageContentDesc : 'Напишите и оформите текст, изображения и ссылки, которые увидят покупатели на этой странице.' ,
2026-07-18 11:02:26 +04:00
seoExplainDesc : 'Это то, что видно в результатах поиска — понятный заголовок и описание помогают клиентам найти страницу.' ,
seoTitleHelp : 'Заголовок, отображаемый в результатах поиска. Делайте е г о коротким и понятным.' ,
seoDescriptionHelp : 'Краткое описание под заголовком в результатах поиска.' ,
seoCanonicalHelp : 'Официальный адрес страницы — помогает избежать дублирования контента.' ,
seoRobotsHelp : 'Определяет, могут ли поисковые системы показывать эту страницу.' ,
sharingExplain : 'Так страница выглядит при публикации в соцсетях (Facebook, Twitter/X и другие).' ,
mediaSelect : 'Выбрать изображение' ,
mediaReplace : 'Заменить' ,
mediaRemove : 'Удалить' ,
mediaAlt : 'Альтернативный текст' ,
mediaCaption : 'Подпись' ,
emptyStateGuideTitle : 'Начните создавать страницы магазина' ,
emptyStateGuideBody : 'Юридические страницы, такие как О нас, Конфиденциальность и Условия, повышают доверие клиентов. Рекомендуем сначала опубликовать О нас, Контакты, Конфиденциальность и Условия, затем добавить Cookies, Доставку, Возвраты и FAQ.' ,
seoStatusGood : 'SEO в порядке' ,
seoStatusPartial : 'SEO частично' ,
seoStatusWarning : 'Проблема SEO' ,
seoStatusMissing : 'SEO отсутствует' ,
needsAttention : 'Требует внимания' ,
legal : {
about : { label : 'О нас' , why : 'Рассказывает клиентам, кто вы, и повышает доверие перед покупкой.' } ,
contacts : { label : 'Контакты' , why : 'Даёт клиентам способ связаться с вами по вопросам.' } ,
privacy : { label : 'Конфиденциальность' , why : 'Объясняет, как обрабатываются данные клиентов — часто обязательно по закону.' } ,
terms : { label : 'Условия' , why : 'Устанавливает правила использования магазина — защищает вас и клиентов.' } ,
cookies : { label : 'Cookies' , why : 'Раскрывает использование cookie — требуется во многих регионах.' } ,
delivery : { label : 'Доставка' , why : 'Задаёт понятные ожидания по доставке и снижает число обращений в поддержку.' } ,
returns : { label : 'Возвраты' , why : 'Объясняет политику возврата и повышает уверенность в покупке.' } ,
faq : { label : 'Вопросы и ответы' , why : 'Отвечает на частые вопросы заранее.' } ,
} ,
} ,
2026-07-09 02:29:12 +04:00
widgets : {
unavailable : 'Виджет недоступен' ,
} ,
2026-02-26 23:09:20 +04:00
carousel : {
loading : 'Загрузка товаров...' ,
addToCart : 'Добавить в корзину' ,
} ,
common : {
retry : 'Попробовать снова' ,
loading : 'Загрузка...' ,
2026-07-17 15:22:45 +04:00
remove : 'Удалить' ,
fix(backoffice): add error+retry states to Users, Monitoring, Analytics, Reports
Phase 8 (RC-01): these 4 list/dashboard pages had no error-state handling
on their primary data-load subscriptions — on a gateway error, `loading`
was either never reset (Users, Monitoring, Analytics: genuine infinite-
spinner risk, nested subscribe chain in Analytics never resolved on
failure) or there was no loading/empty/error handling at all (Reports
queue: raw table with zero skeleton or fallback).
- admin-users.facade.ts, admin-monitoring.facade.ts: add `error` signal,
error callback on the primary load subscribe so `loading` always
resolves.
- admin-analytics.facade.ts: add `error` signal; every level of the
4-deep nested gateway subscribe chain (orders -> products ->
categories -> reviews) now has an error handler that resolves loading
instead of leaving it stuck true.
- admin-moderation.facade.ts: add `reportsLoading`/`reportsError` signals
(reports list had none previously).
- Templates: reuse existing `app-skeleton`/`app-empty-state`/`app-button`
primitives for the new error branch, `common.retry` label, two new
generic `common.errorTitle`/`common.errorDescription` i18n keys added
to en/ru/hy (reused across all 4 fixes instead of one-off per-page
copy).
Verified: tsc --noEmit clean, `npm run build` green (pre-existing bundle-
budget warning only, unrelated). Live-checked Home (375px) and Backoffice
Products (1024px) — no console errors, tables/cards render without
overflow.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 21:31:30 +04:00
errorTitle : 'Что-то пошло не так' ,
errorDescription : 'Н е удалось загрузить данные. Попробуйте ещё раз.' ,
2026-07-25 23:54:08 +04:00
ratingLabel : 'Рейтинг {{value}}' ,
discountLabel : 'Скидка {{value}}%' ,
slideLabel : 'Слайд {{value}}' ,
slidesLabel : 'Слайды' ,
previousProducts : 'Предыдущие товары' ,
nextProducts : 'Следующие товары' ,
closeDialog : 'Закрыть диалог' ,
dismiss : 'Скрыть' ,
qrCode : 'QR-код' ,
bankCardPayment : 'Оплата банковской картой' ,
guest : 'Гость' ,
2026-07-26 00:08:00 +04:00
cancel : 'Отмена' ,
confirm : 'Подтвердить' ,
2026-02-26 23:09:20 +04:00
} ,
2026-02-28 17:18:24 +04:00
location : {
allRegions : 'В с е регионы' ,
chooseRegion : 'Выберите регион' ,
detectAuto : 'Определить автоматически' ,
} ,
auth : {
loginRequired : 'Требуется авторизация' ,
loginDescription : 'Для оформления заказа войдите через Telegram' ,
checking : 'Проверка...' ,
loginWithTelegram : 'Войти через Telegram' ,
orScanQr : 'Или отсканируйте QR-код' ,
loginNote : 'После входа вы будете перенаправлены обратно' ,
2026-03-25 15:32:50 +04:00
qrExpired : 'QR-код устарел. Нажмите, чтобы обновить' ,
2026-06-01 00:47:26 +04:00
qrError : 'Н е удалось создать сессию входа. Нажмите, чтобы повторить' ,
2026-02-28 17:18:24 +04:00
} ,
2026-07-09 01:13:54 +04:00
ux : {
items : 'товаров' ,
wishlistTitle : 'Избранное' ,
wishlistEmptyTitle : 'Избранное пока пусто' ,
wishlistEmptyDescription : 'Сохраняйте товары, чтобы быстро вернуться к ним позже.' ,
clearWishlist : 'Очистить избранное' ,
2026-07-09 02:29:12 +04:00
wishlistCleared : 'Избранное очищено' ,
2026-07-09 01:13:54 +04:00
compareTitle : 'Сравнение товаров' ,
compareEmptyTitle : 'Нет товаров для сравнения' ,
compareEmptyDescription : 'Добавьте товары из каталога, чтобы сравнить характеристики и цену.' ,
clearCompare : 'Очистить сравнение' ,
2026-07-19 23:35:17 +04:00
removeFromCompare : 'Убрать из сравнения' ,
2026-07-09 01:13:54 +04:00
hideIdentical : 'Скрыть одинаковые значения' ,
highlightDifferences : 'Подсвечивать различия' ,
clearRecentlyViewed : 'Очистить просмотренные' ,
recentlyViewedEmpty : 'Вы пока не просматривали товары.' ,
saveSearch : 'Сохранить поиск' ,
goToCatalog : 'Перейти в каталог' ,
2026-07-09 01:40:22 +04:00
wishlistAdded : 'Добавлено в избранное' ,
wishlistRemoved : 'Удалено из избранного' ,
compareAdded : 'Добавлено в сравнение' ,
compareRemoved : 'Удалено из сравнения' ,
compareLimitReached : 'Достигнут лимит сравнения ({{maxItems}})' ,
productShared : 'Товар отправлен' ,
productLinkCopied : 'Ссылка на товар скопирована' ,
sharingUnsupported : 'Н а этом устройстве нет поддержки шаринга' ,
2026-07-09 02:29:12 +04:00
addedToCart : 'Добавлено в корзину' ,
2026-07-09 01:40:22 +04:00
enterQueryBeforeSave : 'Введите поисковый запрос перед сохранением' ,
savedSearchNamed : 'Сохраненный поиск: {{name}}' ,
2026-07-09 02:29:12 +04:00
recentlyViewedTitle : 'Недавно просмотренные' ,
compareAttribute : 'Атрибут' ,
comparePrice : 'Цена' ,
compareRating : 'Рейтинг' ,
compareStock : 'Наличие' ,
compareDiscount : 'Скидка' ,
compareColor : 'Цвет' ,
compareSize : 'Размер' ,
compareUnknown : 'неизвестно' ,
2026-07-09 01:13:54 +04:00
} ,
2026-07-10 13:34:25 +04:00
diagnostics : {
title : 'Диагностика маркетплейса' ,
disabledTitle : 'Диагностика недоступна' ,
disabledDescription : 'Страница диагностики доступна только в режиме разработки.' ,
generatedAt : 'Сформировано: {{value}}' ,
healthScore : 'Оценка состояния' ,
summary : 'Сводка' ,
passedChecks : '{{count}} успешных проверок' ,
warnings : '{{count}} предупреждений' ,
errors : '{{count}} ошибок' ,
critical : '{{count}} критических' ,
healthChecks : 'Проверки состояния' ,
results : 'Подробные результаты' ,
noIssues : 'Проблем диагностики не найдено.' ,
ok : 'OK' ,
failed : 'Ошибка' ,
affectedComponent : 'Затронутый компонент' ,
suggestedResolution : 'Рекомендация' ,
severity : { info : 'Инфо' , warning : 'Предупреждение' , error : 'Ошибка' , critical : 'Критично' } ,
checks : {
bootstrapLoaded : 'Bootstrap загружен' ,
tenantResolved : 'Tenant определен' ,
runtimeInitialized : 'Runtime инициализирован' ,
themeLoaded : 'Тема загружена' ,
widgetManifestLoaded : 'Манифест виджетов загружен' ,
sectionEngineInitialized : 'Section Engine доступен' ,
configurationEngineInitialized : 'Configuration Engine инициализирован' ,
translationResourcesAvailable : 'Переводы доступны' ,
requiredAssetsAvailable : 'Обязательные assets доступны' ,
} ,
bootstrapMissingTitle : 'Bootstrap отсутствует' ,
bootstrapMissingDescription : 'Конфигурация bootstrap не загружена.' ,
bootstrapMissingResolution : 'Проверьте provider bootstrap и локальный mock.' ,
requiredPropertyMissingTitle : 'Отсутствует обязательное свойство' ,
requiredPropertyMissingDescription : 'В bootstrap отсутствует обязательное свойство.' ,
requiredPropertyMissingResolution : 'Добавьте свойство в bootstrap payload.' ,
unknownWidgetTypeTitle : 'Неизвестный тип виджета' ,
unknownWidgetTypeDescription : 'Тип виджета отсутствует в widget manifest.' ,
unknownWidgetTypeResolution : 'Добавьте виджет в manifest или удалите неверную конфигурацию.' ,
duplicateIdTitle : 'Дублирующийся идентификатор' ,
duplicatePageIdDescription : 'Обнаружен дублирующийся id страницы.' ,
duplicateSectionIdDescription : 'Обнаружен дублирующийся id секции.' ,
duplicateWidgetIdDescription : 'Обнаружен дублирующийся id виджета.' ,
duplicateIdResolution : 'Сделайте id уникальными в bootstrap конфигурации.' ,
unknownLayoutTitle : 'Неизвестный layout' ,
unknownLayoutDescription : 'Значение layout страницы не распознано.' ,
unknownLayoutResolution : 'Используйте поддерживаемый layout или расширьте allow-list.' ,
invalidFeatureFlagTitle : 'Некорректный feature flag' ,
invalidFeatureFlagDescription : 'Значение feature flag должно быть boolean.' ,
invalidFeatureFlagResolution : 'Нормализуйте значение к true или false.' ,
brokenPageDefinitionTitle : 'Некорректное описание страницы' ,
brokenPageDefinitionDescription : 'Описание страницы неполное.' ,
brokenPageDefinitionResolution : 'Добавьте route, title, key или sections.' ,
invalidNavigationTargetTitle : 'Некорректная цель навигации' ,
invalidNavigationTargetDescription : 'Route навигации не совпадает с известными route.' ,
invalidNavigationTargetResolution : 'Исправьте target route или добавьте route.' ,
missingTranslationTitle : 'Отсутствует перевод' ,
missingTranslationDescription : 'Ключ перевода не разрешается.' ,
missingTranslationResolution : 'Добавьте ключ в translation resources.' ,
missingMediaTitle : 'Отсутствует media' ,
missingMediaDescription : 'Ожидаемый branding media р е с у р с отсутствует.' ,
missingMediaResolution : 'Укажите корректные media URL в branding конфиге.' ,
runtimeNotInitializedTitle : 'Runtime не инициализирован' ,
runtimeNotInitializedDescription : 'Platform runtime state не помечен как initialized.' ,
runtimeNotInitializedResolution : 'Проверьте цепочку initialize в PlatformRuntimeService.' ,
configFallbackUsageTitle : 'Используется fallback конфигурация' ,
configFallbackUsageDescription : 'Runtime разработки использует fallback или mock конфигурацию.' ,
configFallbackUsageResolution : 'Смените provider mode, если нужна проверка реального bootstrap.' ,
missingDatasourceTitle : 'Отсутствует datasource' ,
missingDatasourceDescription : 'Виджет поддерживает datasource, но он не задан.' ,
missingDatasourceResolution : 'Укажите source в props виджета или default settings manifest.' ,
widgetRenderFailureTitle : 'Сбой рендера виджета' ,
widgetRenderFailureDescription : 'Виджет откатился на unknown widget renderer.' ,
widgetRenderFailureResolution : 'Зарегистрируйте компонент виджета или исправьте component key.' ,
brokenRouteTitle : 'Нарушено ожидание route' ,
brokenRouteDescription : 'Ожидаемый route отсутствует.' ,
brokenRouteResolution : 'Верните регистрацию route или обновите правило диагностики.' ,
imageLoadFailedTitle : 'Ошибка загрузки изображения' ,
imageLoadFailedDescription : 'Отображаемое изображение не загрузилось.' ,
imageLoadFailedResolution : 'Проверьте asset path, CORS и доступность media.' ,
optionalDataMissingTitle : 'Отсутствуют необязательные данные' ,
optionalDataMissingDescription : 'Необязательное конфигурационное значение отсутствует.' ,
optionalDataMissingResolution : 'Добавьте значение, если оно нужно UX.' ,
} ,
feat(admin): implement review and moderation center
New Reviews & Moderation feature (frontend only): moderation dashboard (real pending/approved/rejected/reported/spam counts, average rating, recent activity, moderation-health%, computed from the full review queue); reviews list with table/cards, density, saved column visibility, search/status/rating filters, bulk approve/reject/spam/hide/export; review detail shows customer/product/rating/text/photos/timeline/moderator-notes with a real moderation workflow (approve/reject/spam/hide/restore/pin/feature, feature disabled with an explanation unless the review is approved); reusable ReviewHealthWidget (rating/text/media/moderated/report-status/visible + completion%); reports queue lists reports against products/reviews/customers/categories with resolve/dismiss, and honestly renders 'Not available yet' rather than fabricating a value wherever a target can't be resolved (e.g. photos, customer-target reports). Backed by a new in-memory AdminModerationLocalGateway seeded from real product data - the same mock-gateway pattern already used by every other admin feature in this app (orders/products/categories), since no review/report backend exists to reuse. Replaced the 'Reviews' comingSoon nav placeholder with a working link; added full adminModeration i18n coverage.
2026-07-18 22:01:16 +04:00
adminModeration : {
search : 'Поиск по клиенту, товару или тексту отзыва…' ,
2026-07-20 00:03:46 +04:00
selectAllRows : 'Выбрать все отзывы' ,
fix(backoffice): wording quality pass across orders, moderation, transactions, users, customers
- Replaced hardcoded English audit/timeline text (order status changes,
review moderation events, user role/status changes) with proper
adminXxx.timelineEvent.*/adminUsers.audit.* i18n keys, so Recent
Activity/Timeline/Audit panels no longer mix English into ru/hy UI.
- Translated raw internal codes rendered directly to users: transaction
payment method ('card'/'qr'/'cash_on_delivery' -> adminTransactions.methodValue.*)
and user roles/permissions ('products.manage' etc -> adminUsers.roleValue.*/
adminUsers.permission.*), replacing developer-facing enum leakage with
real copy.
- Fixed wrong-noun list-footer counts: Orders/Transactions/Moderation
list pages all reused adminProducts.items ("N товаров"/"N products")
regardless of what was actually listed; each now has its own itemsCount
key ("N заказов", "N транзакций", "N отзывов").
- Fixed customer detail page's "Back" button reusing adminOrders.back
("Back to orders") instead of a customers-specific label.
- Added translation keys to en/ru/hy + translations.ts interface for all
of the above.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 21:20:37 +04:00
itemsCount : 'отзывов' ,
feat(admin): implement review and moderation center
New Reviews & Moderation feature (frontend only): moderation dashboard (real pending/approved/rejected/reported/spam counts, average rating, recent activity, moderation-health%, computed from the full review queue); reviews list with table/cards, density, saved column visibility, search/status/rating filters, bulk approve/reject/spam/hide/export; review detail shows customer/product/rating/text/photos/timeline/moderator-notes with a real moderation workflow (approve/reject/spam/hide/restore/pin/feature, feature disabled with an explanation unless the review is approved); reusable ReviewHealthWidget (rating/text/media/moderated/report-status/visible + completion%); reports queue lists reports against products/reviews/customers/categories with resolve/dismiss, and honestly renders 'Not available yet' rather than fabricating a value wherever a target can't be resolved (e.g. photos, customer-target reports). Backed by a new in-memory AdminModerationLocalGateway seeded from real product data - the same mock-gateway pattern already used by every other admin feature in this app (orders/products/categories), since no review/report backend exists to reuse. Replaced the 'Reviews' comingSoon nav placeholder with a working link; added full adminModeration i18n coverage.
2026-07-18 22:01:16 +04:00
allStatuses : 'В с е статусы' ,
allRatings : 'В с е оценки' ,
rating : 'Оценка' ,
customer : 'Клиент' ,
product : 'Товар' ,
reviewText : 'Отзыв' ,
photos : 'Фото' ,
workflow : 'Действия' ,
approve : 'Одобрить' ,
reject : 'Отклонить' ,
markSpam : 'Отметить как спам' ,
hide : 'Скрыть' ,
restore : 'Восстановить' ,
pin : 'Закрепить' ,
unpin : 'Открепить' ,
feature : 'Выделить' ,
unfeature : 'Убрать выделение' ,
featureDisabledHint : 'Выделять можно только одобренные отзывы.' ,
moderatorNotes : 'Заметки модератора' ,
notAvailable : 'Пока недоступно' ,
changeStatus : 'Изменить статус' ,
hideSelected : 'Скрыть' ,
archiveSelected : 'В архив' ,
reportsQueue : 'Очередь жалоб' ,
reportsColumn : 'Жалобы' ,
reportTarget : 'Объект жалобы' ,
reportType : 'Тип' ,
reportReason : 'Причина' ,
resolve : 'Решено' ,
dismiss : 'Отклонить' ,
reportsEmptyTitle : 'Жалоб нет' ,
reportsEmptyDescription : 'Жалобы клиентов на товары, отзывы или аккаунты появятся здесь.' ,
reportedCount : 'С жалобами' ,
averageRating : 'Средняя оценка' ,
moderationHealth : 'Состояние модерации' ,
emptyTitle : 'Отзывов пока нет' ,
emptyDescription : 'Отзывы появятся здесь после первых оценок от клиентов.' ,
emptyGuide : 'Клиенты оставляют оценку и текст после покупки. Новые отзывы получают статус «Ожидает» до одобрения, отклонения или пометки как спам модератором — одобренные отзывы становятся видны на витрине. Старайтесь регулярно разбирать очередь ожидающих отзывов.' ,
healthRating : 'Оценка' ,
healthText : 'Текст' ,
healthMedia : 'Медиа' ,
healthModeration : 'Промодерирован' ,
healthReportStatus : 'Нет открытых жалоб' ,
healthVisibility : 'Виден' ,
health : 'Состояние' ,
column_product : 'Товар' ,
column_rating : 'Оценка' ,
column_status : 'Статус' ,
column_reports : 'Жалобы' ,
column_created : 'Отправлен' ,
status : {
pending : 'Ожидает' ,
approved : 'Одобрен' ,
rejected : 'Отклонён' ,
spam : 'Спам' ,
} ,
fix(backoffice): wording quality pass across orders, moderation, transactions, users, customers
- Replaced hardcoded English audit/timeline text (order status changes,
review moderation events, user role/status changes) with proper
adminXxx.timelineEvent.*/adminUsers.audit.* i18n keys, so Recent
Activity/Timeline/Audit panels no longer mix English into ru/hy UI.
- Translated raw internal codes rendered directly to users: transaction
payment method ('card'/'qr'/'cash_on_delivery' -> adminTransactions.methodValue.*)
and user roles/permissions ('products.manage' etc -> adminUsers.roleValue.*/
adminUsers.permission.*), replacing developer-facing enum leakage with
real copy.
- Fixed wrong-noun list-footer counts: Orders/Transactions/Moderation
list pages all reused adminProducts.items ("N товаров"/"N products")
regardless of what was actually listed; each now has its own itemsCount
key ("N заказов", "N транзакций", "N отзывов").
- Fixed customer detail page's "Back" button reusing adminOrders.back
("Back to orders") instead of a customers-specific label.
- Added translation keys to en/ru/hy + translations.ts interface for all
of the above.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 21:20:37 +04:00
timelineEvent : {
submitted : 'Отзыв отправлен' ,
statusChanged : 'Статус изменён на «{{status}}»' ,
restored : 'Отзыв восстановлен' ,
hidden : 'Отзыв скрыт' ,
} ,
actor : {
admin : 'Администратор' ,
customer : 'Клиент' ,
} ,
feat(admin): implement review and moderation center
New Reviews & Moderation feature (frontend only): moderation dashboard (real pending/approved/rejected/reported/spam counts, average rating, recent activity, moderation-health%, computed from the full review queue); reviews list with table/cards, density, saved column visibility, search/status/rating filters, bulk approve/reject/spam/hide/export; review detail shows customer/product/rating/text/photos/timeline/moderator-notes with a real moderation workflow (approve/reject/spam/hide/restore/pin/feature, feature disabled with an explanation unless the review is approved); reusable ReviewHealthWidget (rating/text/media/moderated/report-status/visible + completion%); reports queue lists reports against products/reviews/customers/categories with resolve/dismiss, and honestly renders 'Not available yet' rather than fabricating a value wherever a target can't be resolved (e.g. photos, customer-target reports). Backed by a new in-memory AdminModerationLocalGateway seeded from real product data - the same mock-gateway pattern already used by every other admin feature in this app (orders/products/categories), since no review/report backend exists to reuse. Replaced the 'Reviews' comingSoon nav placeholder with a working link; added full adminModeration i18n coverage.
2026-07-18 22:01:16 +04:00
targetType : {
product : 'Товар' ,
review : 'Отзыв' ,
customer : 'Клиент' ,
category : 'Категория' ,
unknown : 'Неизвестно' ,
} ,
reportStatus : {
open : 'Открыта' ,
resolved : 'Решена' ,
dismissed : 'Отклонена' ,
} ,
} ,
2026-07-18 21:47:54 +04:00
adminOrders : {
back : 'Назад к заказам' ,
search : 'Поиск по номеру заказа, имени, email или телефону…' ,
export : 'Экспорт' ,
2026-07-20 00:00:29 +04:00
selectAllRows : 'Выбрать все заказы' ,
selectRow : 'Выбрать заказ' ,
2026-07-18 21:47:54 +04:00
view : 'Просмотр' ,
orderNumber : 'Заказ' ,
customer : 'Клиент' ,
payment : 'Оплата' ,
delivery : 'Доставка' ,
trackingNumber : 'Номер отслеживания' ,
createdAt : 'Оформлен' ,
items : 'Товары' ,
timeline : 'Хронология' ,
fix(backoffice): wording quality pass across orders, moderation, transactions, users, customers
- Replaced hardcoded English audit/timeline text (order status changes,
review moderation events, user role/status changes) with proper
adminXxx.timelineEvent.*/adminUsers.audit.* i18n keys, so Recent
Activity/Timeline/Audit panels no longer mix English into ru/hy UI.
- Translated raw internal codes rendered directly to users: transaction
payment method ('card'/'qr'/'cash_on_delivery' -> adminTransactions.methodValue.*)
and user roles/permissions ('products.manage' etc -> adminUsers.roleValue.*/
adminUsers.permission.*), replacing developer-facing enum leakage with
real copy.
- Fixed wrong-noun list-footer counts: Orders/Transactions/Moderation
list pages all reused adminProducts.items ("N товаров"/"N products")
regardless of what was actually listed; each now has its own itemsCount
key ("N заказов", "N транзакций", "N отзывов").
- Fixed customer detail page's "Back" button reusing adminOrders.back
("Back to orders") instead of a customers-specific label.
- Added translation keys to en/ru/hy + translations.ts interface for all
of the above.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 21:20:37 +04:00
timelineEvent : {
created : 'Заказ создан' ,
statusChanged : 'Статус изменён на «{{status}}»' ,
refundRequested : 'Запрошен возврат' ,
} ,
2026-07-18 21:47:54 +04:00
notes : 'Заметки для клиента' ,
internalNotes : 'Внутренние заметки' ,
addNote : 'Добавить заметку' ,
changeStatus : 'Изменить статус' ,
applyStatus : 'Применить' ,
archiveSelected : 'В архив' ,
printSelected : 'Печать' ,
printInvoice : 'Печать накладной' ,
requestRefund : 'Запросить возврат' ,
cancelOrder : 'Отменить заказ' ,
confirmCancel : 'Отменить этот заказ?' ,
confirmRefund : 'Запросить возврат по этому заказу?' ,
emptyTitle : 'Заказов пока нет' ,
emptyDescription : 'Заказы появятся здесь после оформления покупок.' ,
column_customer : 'Клиент' ,
column_status : 'Статус' ,
column_payment : 'Оплата' ,
column_total : 'Сумма' ,
column_created : 'Оформлен' ,
status : {
2026-07-19 23:04:51 +04:00
all : 'В с е статусы' ,
2026-07-18 21:47:54 +04:00
pending : 'Ожидает' ,
processing : 'Сборка' ,
shipped : 'Доставляется' ,
delivered : 'Завершён' ,
cancelled : 'Отменён' ,
refunded : 'Возвращён' ,
} ,
paymentStatus : {
unpaid : 'Н е оплачен' ,
paid : 'Оплачен' ,
refund_requested : 'Запрошен возврат' ,
refunded : 'Возвращён' ,
} ,
fix(backoffice): wording quality pass across orders, moderation, transactions, users, customers
- Replaced hardcoded English audit/timeline text (order status changes,
review moderation events, user role/status changes) with proper
adminXxx.timelineEvent.*/adminUsers.audit.* i18n keys, so Recent
Activity/Timeline/Audit panels no longer mix English into ru/hy UI.
- Translated raw internal codes rendered directly to users: transaction
payment method ('card'/'qr'/'cash_on_delivery' -> adminTransactions.methodValue.*)
and user roles/permissions ('products.manage' etc -> adminUsers.roleValue.*/
adminUsers.permission.*), replacing developer-facing enum leakage with
real copy.
- Fixed wrong-noun list-footer counts: Orders/Transactions/Moderation
list pages all reused adminProducts.items ("N товаров"/"N products")
regardless of what was actually listed; each now has its own itemsCount
key ("N заказов", "N транзакций", "N отзывов").
- Fixed customer detail page's "Back" button reusing adminOrders.back
("Back to orders") instead of a customers-specific label.
- Added translation keys to en/ru/hy + translations.ts interface for all
of the above.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 21:20:37 +04:00
itemsCount : 'заказов' ,
2026-07-18 21:47:54 +04:00
ordersToday : 'Заказов сегодня' ,
paidCount : 'Оплачено' ,
customersCount : 'Клиенты' ,
returningCustomers : 'Повторные клиенты' ,
averageOrder : 'Средний чек' ,
recentActivity : 'Недавняя активность' ,
noRecentActivity : 'Активности пока нет.' ,
alertStuckPending : 'заказов ожидают более 48 часов' ,
alertRefundRequested : 'заказов ждут запроса на возврат' ,
} ,
adminCustomers : {
fix(backoffice): wording quality pass across orders, moderation, transactions, users, customers
- Replaced hardcoded English audit/timeline text (order status changes,
review moderation events, user role/status changes) with proper
adminXxx.timelineEvent.*/adminUsers.audit.* i18n keys, so Recent
Activity/Timeline/Audit panels no longer mix English into ru/hy UI.
- Translated raw internal codes rendered directly to users: transaction
payment method ('card'/'qr'/'cash_on_delivery' -> adminTransactions.methodValue.*)
and user roles/permissions ('products.manage' etc -> adminUsers.roleValue.*/
adminUsers.permission.*), replacing developer-facing enum leakage with
real copy.
- Fixed wrong-noun list-footer counts: Orders/Transactions/Moderation
list pages all reused adminProducts.items ("N товаров"/"N products")
regardless of what was actually listed; each now has its own itemsCount
key ("N заказов", "N транзакций", "N отзывов").
- Fixed customer detail page's "Back" button reusing adminOrders.back
("Back to orders") instead of a customers-specific label.
- Added translation keys to en/ru/hy + translations.ts interface for all
of the above.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 21:20:37 +04:00
back : 'Назад к клиентам' ,
2026-07-18 21:47:54 +04:00
search : 'Поиск по имени, email или телефону…' ,
name : 'Имя' ,
email : 'Email' ,
phone : 'Телефон' ,
orderCount : 'Заказы' ,
lifetimeValue : 'Общая сумма покупок' ,
returning : 'Повторный' ,
profile : 'Профиль' ,
statistics : 'Статистика' ,
firstOrder : 'Первый заказ' ,
lastOrder : 'Последний заказ' ,
addresses : 'Адреса' ,
notes : 'Заметки' ,
notesUnavailable : 'Заметок по клиенту пока нет — добавьте заметку к одному из е г о заказов.' ,
orders : 'Заказы' ,
activity : 'Активность' ,
emptyTitle : 'Клиентов пока нет' ,
emptyDescription : 'Клиенты появятся здесь после первого заказа.' ,
} ,
feat(media): add Media Manager UI (grid, upload, delete)
MediaLibraryPageComponent replaces the coming-soon placeholder at
/backoffice/media. Built entirely on Sprint 6 Design System primitives
(app-card, app-button, app-input, app-empty-state, app-dialog, app-pagination,
app-skeleton) and Sprint 4 Task 2's MediaRepository/MockMediaRepository.
- Grid view with per-tile filename/size and delete action
- Hidden native file input triggered by an app-button, uploads via
MediaLibraryFacade -> MediaRepository.upload()
- Delete requires confirmation through app-dialog (destructive action)
- Search + pagination wired to MockMediaRepository's list() params
- Loading state shows app-skeleton tiles; empty state shows app-empty-state
- New mediaLibrary.* translation namespace across en/ru/hy
Verified in browser (via a temporary unguarded route, reverted before
commit - /backoffice/media itself requires Telegram QR admin auth not
available in this session): empty state renders correctly with translated
copy, search input and upload button present, no console errors.
2026-07-15 07:14:16 +04:00
mediaLibrary : {
title : 'Медиатека' ,
upload : 'Загрузить' ,
uploading : 'Загрузка...' ,
searchPlaceholder : 'Поиск файлов...' ,
delete : 'Удалить' ,
deleteConfirmTitle : 'Удалить файл?' ,
deleteConfirmBody : 'Это действие необратимо.' ,
cancel : 'Отмена' ,
confirm : 'Удалить' ,
emptyTitle : 'Пока нет файлов' ,
emptyDescription : 'Загрузите изображение или документ, чтобы начать.' ,
feat(builder): implement reusable media library
Media dashboard (real total/images/SVG/logos/unused/storage/alt-coverage, computed from actual assets + a bootstrap usage scan, no fabricated stats); gallery gets grid/list toggle, type filter, sort, drag-and-drop + multi-file upload with cancel/retry and friendly error mapping, lazy thumbnails, multi-select with bulk delete/download/export-metadata; asset details drawer shows real dimensions/size/format/date/usage locations (walks bootstrap config for exact URL matches, reports not-used rather than guessing) plus editable alt text/caption/description/decorative flag with missing-alt warning; shared MediaPickerComponent (already the one reusable picker used by content management) gains type filter, a recent shortcut, and keyboard grid navigation.
2026-07-18 16:09:47 +04:00
allFolders : 'В с е папки' ,
newFolder : 'Новая папка' ,
editTags : 'Изменить теги' ,
totalAssets : 'В с е г о файлов' ,
logos : 'Логотипы' ,
unused : 'Неиспользуемые' ,
storageUsed : 'Использовано места' ,
altCoverage : 'Покрытие alt-текстом' ,
allTypes : 'В с е типы' ,
typeImage : 'Изображения' ,
typeSvg : 'SVG' ,
typePdf : 'PDF' ,
sortRecent : 'Недавние' ,
sortName : 'Имя' ,
sortSize : 'Размер' ,
viewMode : 'Вид' ,
viewGrid : 'Сетка' ,
viewList : 'Список' ,
dropHint : 'Перетащите изображения сюда или используйте кнопку «Загрузить» выше.' ,
cancelUpload : 'Отменить' ,
retry : 'Повторить' ,
errorTooLarge : 'Файл слишком большой. Попробуйте файл меньшего размера.' ,
errorUnsupportedType : 'Этот тип файла не поддерживается. Используйте JPG, PNG, WebP, GIF, SVG или PDF.' ,
errorGeneric : 'Н е удалось загрузить файл. Попробуйте ещё раз.' ,
selectedCount : 'выбрано' ,
download : 'Скачать' ,
exportMetadata : 'Экспортировать метаданные' ,
bulkDelete : 'Удалить выбранные' ,
bulkDeleteConfirm : 'Удалить выбранные файлы? Это действие нельзя отменить.' ,
clearSelection : 'Снять выделение' ,
guideCopy : 'Повторное использование существующего файла избавляет от дублей и экономит место. Для баннеров и главных изображений рекомендуем размер около 1200× 1200px и сжатие крупных фото перед загрузкой.' ,
missingAlt : 'Нет alt-текста' ,
usageCount : 'исп.' ,
detailsTitle : 'Информация о файле' ,
filename : 'Имя файла' ,
format : 'Формат' ,
fileSize : 'Размер файла' ,
dimensions : 'Размеры' ,
uploadDate : 'Загружен' ,
lastUsed : 'Последнее использование' ,
usageCountLabel : 'Количество использований' ,
usedIn : 'Используется в' ,
notUsed : 'Пока нигде не используется.' ,
unknownValue : 'Неизвестно' ,
altText : 'Alt-текст' ,
altTextHelp : 'Описывает изображение для программ чтения с экрана и поисковых систем.' ,
decorative : 'Декоративное (alt-текст не нужен)' ,
missingAltWarning : 'У этого изображения нет alt-текста, и оно не отмечено как декоративное — пользователи с программами чтения с экрана не узнают, что на нём изображено.' ,
caption : 'Подпись' ,
description : 'Описание' ,
usage : {
brand : 'Логотип' ,
theme : 'Тема' ,
header : 'Шапка' ,
footer : 'Подвал' ,
staticPage : 'Статическая страница' ,
homepage : 'Главная страница' ,
catalog : 'Каталог' ,
productPage : 'Страница товара' ,
widget : 'Виджет' ,
company : 'Информация о компании' ,
seo : 'SEO' ,
navigation : 'Навигация' ,
other : 'Другое' ,
} ,
feat(media): add Media Manager UI (grid, upload, delete)
MediaLibraryPageComponent replaces the coming-soon placeholder at
/backoffice/media. Built entirely on Sprint 6 Design System primitives
(app-card, app-button, app-input, app-empty-state, app-dialog, app-pagination,
app-skeleton) and Sprint 4 Task 2's MediaRepository/MockMediaRepository.
- Grid view with per-tile filename/size and delete action
- Hidden native file input triggered by an app-button, uploads via
MediaLibraryFacade -> MediaRepository.upload()
- Delete requires confirmation through app-dialog (destructive action)
- Search + pagination wired to MockMediaRepository's list() params
- Loading state shows app-skeleton tiles; empty state shows app-empty-state
- New mediaLibrary.* translation namespace across en/ru/hy
Verified in browser (via a temporary unguarded route, reverted before
commit - /backoffice/media itself requires Telegram QR admin auth not
available in this session): empty state renders correctly with translated
copy, search input and upload button present, no console errors.
2026-07-15 07:14:16 +04:00
} ,
fix(static-pages): backfill enabled/status in export, fix missing i18n key
Independent review pass over the Static Pages Module sprint (M1-M7),
including live browser E2E per the task's own verification checklist.
- ProjectEditorFacade.normalize() now backfills enabled/status on
record-format static pages (defaulting missing values to enabled+published,
same rule ContentPageService.normalizePage applies for display - mirrored
rather than imported, to avoid a project-editor <-> content-management
circular dependency since ContentManagementFacade already depends on this
facade). Found live: exporting a page that predates this sprint and was
never touched/re-saved in the current session produced JSON missing
enabled/status entirely - the editor UI and storefront resolver both
normalize-on-read so nothing was actually broken live, but Export/Import
fidelity should match what the editor shows. Verified fixed live (export
now includes "enabled":true,"status":"published" for an untouched legacy
page) and via the full gate.
- Added the missing adminCategories.chooseImage i18n key (interface +
en/ru/hy). Found live: the media-picker "choose image" button rendered as
the literal string "adminCategories.chooseImage" - a pre-existing,
repo-wide bug (5 templates reference this key; none of the locale files
ever defined it) that I propagated into a 3rd/4th/5th... well, 2 new
occurrences by copying the existing branding-section/footer-section
pattern into static-pages-editor. Fixed the actual defect (missing
translation) rather than renaming the key, which would have required
touching 2 unrelated admin components outside this sprint's scope.
Live-verified this pass: Static Pages editor renders with all new fields;
create page works (page count 4->confirmed); device preview toggles
desktop/tablet/mobile widths correctly; navigation "Insert page link"
creates a real type:'staticPage' nav item end-to-end (confirmed in the
exported JSON); export includes all Sprint X+2 fields after the fix; no
console errors throughout.
Gate: tsc --noEmit, npm test (57/57), arch:check, build all green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 11:27:29 +04:00
adminCategories : {
chooseImage : 'Выбрать изображение' ,
2026-07-17 15:22:45 +04:00
replaceImage : 'Заменить изображение' ,
2026-07-18 17:04:11 +04:00
search : 'Поиск категорий…' ,
showDeleted : 'Показать удалённые' ,
2026-07-19 23:57:49 +04:00
selectAllRows : 'Выбрать все категории' ,
selectRow : 'Выбрать категорию' ,
toggleVisibility : 'Переключить видимость' ,
2026-07-18 17:04:11 +04:00
create : 'Создать категорию' ,
edit : 'Редактировать категорию' ,
title : 'Название' ,
slug : 'URL-адрес' ,
slugTaken : 'Этот адрес уже используется другой категорией.' ,
parent : 'Родительская категория' ,
noParent : 'Без родителя (верхний уровень)' ,
icon : 'Иконка' ,
image : 'Изображение' ,
imageHint : 'Показывается в списках категорий и навигации.' ,
description : 'Описание' ,
items : 'товаров' ,
status : { draft : 'Черновик' , published : 'Опубликовано' } ,
restore : 'Восстановить' ,
saveDraft : 'Сохранить черновик' ,
publish : 'Опубликовать' ,
confirmDelete : 'Удалить эту категорию? Это действие нельзя отменить.' ,
confirmLeaveUnsaved : 'У вас есть несохранённые изменения. Выйти без сохранения?' ,
deleteBlocked : 'Эту категорию нельзя удалить, пока у неё есть подкатегории или назначенные товары.' ,
emptyTitle : 'Категорий пока нет' ,
emptyDescription : 'Создайте первую категорию, чтобы начать организовывать товары.' ,
emptyGuide : 'Категории помогают покупателям находить товары. Начните с нескольких верхнеуровневых категорий (например, Одежда, Электроника), затем добавляйте подкатегории по мере роста каталога — избегайте вложенности глубже 2-3 уровней.' ,
viewTree : 'Дерево' ,
viewCards : 'Карточки' ,
expandAll : 'Развернуть всё' ,
collapseAll : 'Свернуть всё' ,
expandNode : 'Развернуть' ,
collapseNode : 'Свернуть' ,
fix(backoffice): WCAG 2.1 AA accessibility fixes
RC A11Y-01 audit pass, Backoffice (admin/*) area. Builds on 712a7b4/63c9cee's
composition pass (scope="col", skeletons, empty-states) without redoing that
work.
- Sidebar nav landmark: admin-layout's <nav aria-label> reused the
"Dashboard" nav-item translation key as its landmark label, misleadingly
announcing the whole sidebar as "Dashboard" - added a dedicated
adminShell.sidebarLabel key ("Admin sidebar navigation") in en/ru/hy.
Skip link, #admin-content main landmark, Escape handling, and mobile-drawer
focus management were already correct - verified, not touched.
- Categories tree drag-and-drop keyboard fallback (WCAG 2.1.1): the category
tree's native HTML5 DnD (draggable/dragstart/drop) reorders siblings with
no keyboard equivalent - existing arrow-key tree navigation only expands/
collapses/selects, never reorders. Added per-row move-up/move-down icon
buttons (disabled at sibling boundaries), reusing the existing `reorder`
output so the facade's reorder logic is untouched; new
adminCategories.moveUp/moveDown keys in en/ru/hy.
- Screen-reader loading announcements: skeleton-row loading states across
Products, Categories, Customers, Orders, Transactions, Users, Reviews,
Monitoring (webhooks/events), and Analytics (summary cards + top products)
were purely visual (app-skeleton is aria-hidden by design) with no
accessible "loading" text, unlike the storefront/product-details pattern -
added role="status"/aria-live="polite"/aria-busy + sr-only text using the
existing common.loading key.
- Table row headers: added scope="row" to the primary identifying cell
(product/category/customer name, order number, transaction order number,
user name, review customer, report target, top-products/low-stock product
name, webhook endpoint) on 9 tables that only had scope="col". Added
matching `tbody th[scope='row'] { font-weight/color/text-align/
vertical-align }` + last-row border resets in each component's own scss so
the semantic change doesn't alter visuals (the shared app-table stylesheet
styles all <th> as bold/muted by default).
Verified via `git show --stat` of fb1afb7/a03260e and `docs/UI-COMPOSITION-
REVIEW.md`'s Backoffice sections first, per instructions - confirmed
scope="col" coverage already complete, all admin modals already route
through the shared app-dialog (focus-trap/Escape/return-focus already
correct, nothing to fix), and the bare-<select> filters still carry
aria-label per the accepted Sprint 28 decision (not re-migrated to
app-select).
Flagged, not fixed:
- No toast/notification system exists anywhere in this codebase (product/
category save and delete call the gateway with no success/error UI at
all, not even a subscribe error handler) - there is nothing to wire
aria-live onto without adding a new UI mechanism, which is out of scope
for an a11y-only pass. A prerequisite feature-level fix, not an a11y
regression.
- Dashboard's per-card metric/status-row/timeline skeletons (dashboard-
metric, dashboard-status-row, dashboard-timeline) were left without
aria-live wiring - wrapping each of the ~10 simultaneous mini-widgets in
its own live region would fire a burst of redundant announcements; needs
a single page-level "loading dashboard" region instead, a larger change
than this surgical pass.
- Monitoring's events table and the notifications dropdown (role="menu"
with a static empty-state message, aria-haspopup="true") were left as-is -
matches the same partial-widget-pattern precedent already accepted for
locale-tabs/product-tabs in the storefront and builder passes.
- Analytics `lowStockProducts` table's missing loading-skeleton branch
(already flagged, not fixed, in the RC-Visual-02 pass) - untouched again
here for the same reason.
Verified: npx tsc --noEmit clean; npm run build green (only the pre-existing
768.57 kB vs 700 kB initial-bundle budget warning, unrelated to this pass).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-24 09:18:09 +04:00
moveUp : 'Переместить вверх' ,
moveDown : 'Переместить вниз' ,
2026-07-18 17:04:11 +04:00
jumpToParent : 'К родителю' ,
deletedBadge : 'Удалена' ,
column_slug : 'Адрес' ,
column_items : 'Товары' ,
column_status : 'Статус' ,
column_visibility : 'Видимость' ,
column_updated : 'Последнее изменение' ,
bulkAssignParent : 'Назначить родителя' ,
bulkAssignImage : 'Назначить изображение' ,
groupGeneral : 'Основное' ,
groupMedia : 'Медиа' ,
groupSeo : 'SEO' ,
groupVisibility : 'Видимость' ,
groupNavigation : 'Навигация' ,
groupAttributes : 'Атрибуты' ,
groupAdvanced : 'Дополнительно' ,
visibilityExplain : 'Скрытая категория и её товары не отображаются в навигации и поиске магазина, пока вы снова не сделаете её видимой.' ,
navBreadcrumb : 'Хлебные крошки' ,
2026-07-19 08:35:18 +04:00
navBreadcrumbHint : 'Это путь, который покупатели видят над категорией, напр. Главная › Электроника › Телефоны. Он строится из выбранной родительской категории.' ,
iconHint : 'Небольшой эмодзи или символ рядом с названием категории в меню, напр. 📱. Оставьте пустым, если не нужен.' ,
2026-07-18 17:04:11 +04:00
navRoot : 'Это категория верхнего уровня.' ,
navChildren : 'Подкатегории' ,
navNoChildren : 'Подкатегорий пока нет.' ,
navAppearsIn : 'Где это отображается' ,
navAppearsVisible : 'Видна в навигации каталога и поиске.' ,
navAppearsHidden : 'Скрыта — не отображается в навигации каталога, пока скрыта.' ,
itemsCountLabel : 'Назначенные товары' ,
createdAtLabel : 'Создана' ,
healthImage : 'Изображение' ,
healthSeo : 'SEO' ,
healthDescription : 'Описание' ,
healthParent : 'Родитель' ,
healthVisibility : 'Видимость' ,
healthProducts : 'Назначены товары' ,
totalCategories : 'В с е г о категорий' ,
visibleCount : 'Видимые' ,
hiddenCount : 'Скрытые' ,
emptyCount : 'Пустые' ,
rootCount : 'Корневые категории' ,
subCount : 'Подкатегории' ,
missingImagesCount : 'Без изображений' ,
missingSeoCount : 'Без SEO' ,
lastModified : 'Последнее изменение' ,
lastModifiedNever : 'Никогда' ,
completionLabel : 'Готовность' ,
recommendedNext : 'Рекомендуемый следующий шаг' ,
recommendAddImage : 'У категории нет изображения — добавьте е г о для доверия в листингах.' ,
recommendAddSeo : 'У категории нет заголовка или описания для поиска — добавьте их.' ,
recommendFillEmpty : 'В категории нет товаров — добавьте товары или скройте категорию.' ,
recommendNone : 'Отлично — структура категорий в хорошем состоянии.' ,
fix(static-pages): backfill enabled/status in export, fix missing i18n key
Independent review pass over the Static Pages Module sprint (M1-M7),
including live browser E2E per the task's own verification checklist.
- ProjectEditorFacade.normalize() now backfills enabled/status on
record-format static pages (defaulting missing values to enabled+published,
same rule ContentPageService.normalizePage applies for display - mirrored
rather than imported, to avoid a project-editor <-> content-management
circular dependency since ContentManagementFacade already depends on this
facade). Found live: exporting a page that predates this sprint and was
never touched/re-saved in the current session produced JSON missing
enabled/status entirely - the editor UI and storefront resolver both
normalize-on-read so nothing was actually broken live, but Export/Import
fidelity should match what the editor shows. Verified fixed live (export
now includes "enabled":true,"status":"published" for an untouched legacy
page) and via the full gate.
- Added the missing adminCategories.chooseImage i18n key (interface +
en/ru/hy). Found live: the media-picker "choose image" button rendered as
the literal string "adminCategories.chooseImage" - a pre-existing,
repo-wide bug (5 templates reference this key; none of the locale files
ever defined it) that I propagated into a 3rd/4th/5th... well, 2 new
occurrences by copying the existing branding-section/footer-section
pattern into static-pages-editor. Fixed the actual defect (missing
translation) rather than renaming the key, which would have required
touching 2 unrelated admin components outside this sprint's scope.
Live-verified this pass: Static Pages editor renders with all new fields;
create page works (page count 4->confirmed); device preview toggles
desktop/tablet/mobile widths correctly; navigation "Insert page link"
creates a real type:'staticPage' nav item end-to-end (confirmed in the
exported JSON); export includes all Sprint X+2 fields after the fix; no
console errors throughout.
Gate: tsc --noEmit, npm test (57/57), arch:check, build all green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 11:27:29 +04:00
} ,
2026-07-16 00:19:41 +04:00
adminProducts : {
fix(admin): products canDeactivate guard, unblock npm, drop dead deps
RC-01 Phase 1 mechanical fixes (verified against current repo state,
not blindly reapplied from TODO.md):
- admin/products create/edit/duplicate now protected by an unsaved-
changes guard (adminProductDirtyGuard), mirroring the existing
categories pattern. AdminProductsFacade had zero dirty-tracking
before this - added a dirty signal, set true on updateDraft(),
cleared on load/create/successful save. Added confirmLeaveUnsaved
to the adminProducts i18n section (en/ru/hy) - categories already
had its own copy of this key, products didn't.
- barry-cache bumped ^0.1.0 -> ^0.9.3 (the pinned range no longer
resolved on the registry - ETARGET - which had been silently
blocking every npm install/uninstall all cycle).
- Removed primeng/primeicons (npm uninstall, now unblocked) - the
only consumer (items-carousel) was already deleted in RC PERF-01.
- Removed core/search/services/search-history.service.ts, a dead
1-line re-export with zero importers (verified: the real
implementation is features/search/services/search-history.service.ts,
used by search.facade.ts). Left core/search/models/* alone - those
ARE live, imported by catalog components.
Verified before touching: HeaderConfig.showProfile toggle is already
removed from the header-section editor template (TODO.md was stale on
this one) - no change needed, will correct the tracking doc separately.
tsc --noEmit clean, npm run build green (bundle unchanged, primeng
was already tree-shaken out, this just removes the dead dependency
declaration itself).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 20:04:51 +04:00
confirmLeaveUnsaved : 'У вас есть несохранённые изменения. Выйти без сохранения?' ,
2026-07-16 00:19:41 +04:00
emptyTitle : 'Товары не найдены' ,
emptyDescription : 'Измените фильтры или создайте новый товар.' ,
feat(products): implement professional product management experience
Products dashboard (real total/published/drafts/out-of-stock/hidden/missing-images/missing-SEO/low-quality counts, recently-edited list, recommended next action); list gains table/grid view toggle, density, saved column visibility and saved sort (persisted via LocalStorageService), plus real bulk assign-category/assign-tags/duplicate/CSV-export alongside existing publish/hide/delete; per-row and per-editor reusable ProductHealthWidget (images/SEO/price/category/description/inventory checklist + completion %); editor reorganized into General/Media/Pricing/Inventory/Categories/Attributes/SEO/Visibility/Advanced tabs, media now uses the shared MediaPickerComponent/ImageFieldComponent (primary image + reorderable gallery) instead of raw URL textareas, specifications/attributes/variants moved off pipe-delimited textareas onto the shared KeyValueEditorComponent, SEO tab explains fields in plain language with a live search-result preview, inventory relabeled in business language, toggles/badges use the shared Toggle/Badge components. Filled in the adminProducts i18n namespace (previously ~98% missing, rendering raw translation keys) across en/ru/hy.
2026-07-18 16:34:06 +04:00
emptyGuide : 'Хорошему товару нужны понятное название, минимум одно фото, цена и короткое описание — этого достаточно для публикации. Остальное можно добавить позже.' ,
2026-07-19 23:55:11 +04:00
selectAllRows : 'Выбрать все товары' ,
selectRow : 'Выбрать товар' ,
feat(products): implement professional product management experience
Products dashboard (real total/published/drafts/out-of-stock/hidden/missing-images/missing-SEO/low-quality counts, recently-edited list, recommended next action); list gains table/grid view toggle, density, saved column visibility and saved sort (persisted via LocalStorageService), plus real bulk assign-category/assign-tags/duplicate/CSV-export alongside existing publish/hide/delete; per-row and per-editor reusable ProductHealthWidget (images/SEO/price/category/description/inventory checklist + completion %); editor reorganized into General/Media/Pricing/Inventory/Categories/Attributes/SEO/Visibility/Advanced tabs, media now uses the shared MediaPickerComponent/ImageFieldComponent (primary image + reorderable gallery) instead of raw URL textareas, specifications/attributes/variants moved off pipe-delimited textareas onto the shared KeyValueEditorComponent, SEO tab explains fields in plain language with a live search-result preview, inventory relabeled in business language, toggles/badges use the shared Toggle/Badge components. Filled in the adminProducts i18n namespace (previously ~98% missing, rendering raw translation keys) across en/ru/hy.
2026-07-18 16:34:06 +04:00
search : 'Поиск товаров…' ,
category : 'Категория' ,
allCategories : 'В с е категории' ,
visibility : 'Видимость' ,
allVisibility : 'Любая видимость' ,
visible : 'Видимый' ,
hidden : 'Скрытый' ,
stockStatus : 'Статус наличия' ,
allStock : 'Любой остаток' ,
inStock : 'В наличии' ,
lowStock : 'Мало на складе' ,
outOfStock : 'Нет в наличии' ,
sortTitle : 'Имя' ,
sortPrice : 'Цена' ,
sortPriority : 'Приоритет' ,
sortStock : 'Остаток' ,
sortUpdated : 'Последнее изменение' ,
showArchived : 'Показать архивные' ,
infiniteScroll : 'Бесконечная прокрутка' ,
viewMode : 'Вид' ,
viewTable : 'Таблица' ,
viewGrid : 'Сетка' ,
density : 'Плотность' ,
densityComfortable : 'Комфортная' ,
densityCompact : 'Компактная' ,
columns : 'Столбцы' ,
column_sku : 'Артикул' ,
column_brand : 'Бренд' ,
column_price : 'Цена' ,
column_stock : 'Остаток' ,
column_visibility : 'Видимость' ,
column_updated : 'Последнее изменение' ,
create : 'Создать товар' ,
edit : 'Редактировать товар' ,
duplicate : 'Дублировать' ,
selectedCount : 'выбрано' ,
bulkShow : 'Опубликовать' ,
bulkHide : 'Скрыть' ,
bulkAssignCategory : 'Назначить категорию' ,
bulkAssignTags : 'Назначить теги' ,
bulkDuplicateAction : 'Дублировать' ,
bulkExportAction : 'Экспорт' ,
bulkDelete : 'Удалить' ,
tagsPlaceholder : 'например, лето, скидка' ,
name : 'Название' ,
brand : 'Бренд' ,
healthColumn : 'Качество' ,
actions : 'Действия' ,
archive : 'В архив' ,
delete : 'Удалить' ,
items : 'товаров' ,
loadMore : 'Загрузить ещё' ,
noImage : 'Нет изображения' ,
slug : 'URL-адрес' ,
barcode : 'Штрихкод' ,
priority : 'Приоритет' ,
shortDescription : 'Краткое описание' ,
translations : 'Переводы' ,
primaryImage : 'Главное изображение' ,
primaryImageHint : 'Основное фото, показываемое в списках и результатах поиска.' ,
gallery : 'Галерея' ,
galleryHint : 'Дополнительные фото на странице товара. Порядок меняется стрелками.' ,
moveLeft : 'Переместить раньше' ,
moveRight : 'Переместить позже' ,
videos : 'Видео (по одной ссылке на строку)' ,
discount : 'Скидка %' ,
currency : 'Валюта' ,
stockQuantity : 'Количество на складе' ,
stockQuantityHint : 'Сколько единиц доступно для продажи прямо сейчас.' ,
availabilityStatus : 'Доступность' ,
availabilityStatusHint : 'Что видит покупатель: в наличии, заканчивается или нет в наличии.' ,
availabilityNote : 'Примечание о доступности' ,
availabilityNoteHint : 'Дополнительная информация для покупателя, например «Доставка за 3 дня».' ,
reservedNote : 'Резерв пока не учитывается отдельно — здесь показано общее доступное количество.' ,
relatedProducts : 'Похожие товары' ,
specifications : 'Характеристики' ,
attributes : 'Атрибуты' ,
addRow : 'Добавить строку' ,
removeRow : 'Удалить' ,
rowKey : 'Название' ,
rowValue : 'Значение' ,
addVariant : 'Добавить вариант' ,
variantName : 'Название варианта' ,
variantsHint : 'Каждый вариант — это отдельный покупаемый вариант товара (например, размер или цвет) с о своей ценой и остатком.' ,
2026-07-18 22:44:39 +04:00
variants : 'Варианты' ,
feat(admin): Shopify-style variant attributes matching production data shape
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
P0 user feedback: variants were just free-text name+price, and the user shared the real production payload - a flat array of {color, size, price, currency, remaining} rows, colors as '0x8B4513' hex.
- New model: AdminProductVariantAttributeDef (key/label/isColor/values) + AdminProductVariant (attributes: Record<string,string>, sku, image, remaining, prices: {currency,price}[]) - this IS the production shape, grouped by combo with one row per currency instead of flattened, so admins edit one variant card instead of 4 duplicate rows
- Attribute manager: add custom attributes (Color, Size, or anything), color attributes get a native color picker + live swatch preview instead of typing hex; other attributes get plain value chips
- 'Generate variants' computes the cartesian product of attribute values (Color x Size = 4 combos for 1 color x 4 sizes) and preserves existing sku/price/stock data for combos that still exist after regeneration
- Multi-currency pricing per variant (matches prod: same combo priced in RUB/USD/EUR/AMD) with per-currency add/remove
- Color hex kept in the exact '0x8B4513' production format (toBackendColor/toCssColor conversion helpers)
- Fixed an Angular v21 control-flow parser bug hit while building this: an @if/@else block whose only content is a bare {{ interpolation }} touching the block's closing brace fails to parse (NG5002 'Unclosed block for' cascading from a completely unrelated line) - worked around by keeping interpolation in its own element
- Verified end-to-end in browser: added Color (color picker) + Size (S/M/L/XL) attributes, generated 4 variant combos, added all 4 currencies to a variant - matches the shared production JSON exactly
2026-07-19 13:40:51 +04:00
variantAttributes : 'Опции' ,
variantAttributesHint : 'Добавьте опции вроде Цвет или Размер, затем перечислите значения. Комбинации ниже создаются автоматически.' ,
colorAttribute : 'Цвет' ,
removeAttribute : 'Удалить опцию' ,
removeValue : 'Удалить значение' ,
pickColor : 'Выбрать цвет' ,
newValuePlaceholder : 'напр. Маленький' ,
addValue : 'Добавить' ,
newAttributePlaceholder : 'напр. Размер' ,
addAttribute : 'Добавить опцию' ,
generateVariants : 'Сгенерировать варианты' ,
variantsList : 'Варианты' ,
remaining : 'Остаток' ,
variantImage : 'Изображение' ,
2026-07-18 22:44:39 +04:00
archived : 'В архиве' ,
feat(admin): product editor auto-slug, SKU helper, one-click SEO fill
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
P0 user feedback: admins did not know what SKU means, had to hand-write slugs, and left SEO empty.
- Name edits now derive the URL slug automatically (supports Cyrillic/Armenian characters); the derivation stops the moment the slug no longer matches the auto value, so a manually edited slug is never overwritten - verified in browser
- SEO title mirrors the name under the same only-while-untouched rule
- SKU field explains itself (what a stock keeping unit is, that any unique text works) and gains a Generate button producing readable codes like WIR-GAM-7K2P from the product name
- SEO tab gains 'Fill from product details': fills only empty title/description/keywords from name and short description, existing text untouched
- New adminProducts keys (slugHint, skuHint, generate, seoGenerate, seoGenerateHint) in en/ru/hy
2026-07-19 08:30:49 +04:00
slugHint : 'В е б -адрес этого товара. Заполняется автоматически из названия — меняйте, только если нужен особый URL.' ,
skuHint : 'SKU (артикул) — ваш внутренний код товара для учёта склада и поиска заказов. Подойдёт любой уникальный текст.' ,
generate : 'Сгенерировать' ,
seoGenerate : 'Заполнить из данных товара' ,
seoGenerateHint : 'Заполняет пустые поля из названия и краткого описания. Ваш текст не перезаписывается.' ,
2026-07-19 08:40:30 +04:00
translationsHint : 'Основные поля выше отображаются на языке магазина по умолчанию. Здесь добавьте переводы для других языков — если перевод пуст, покупатели увидят текст по умолчанию.' ,
2026-07-19 08:44:20 +04:00
badgesHint : 'Бейджи — небольшие цветные ярлыки, которые покупатели видят на фото товара. Выберите из стандартных или добавьте свой.' ,
addBadge : 'Добавить' ,
removeBadge : 'Убрать бейдж' ,
customBadgePlaceholder : 'Текст своего бейджа…' ,
feat(products): implement professional product management experience
Products dashboard (real total/published/drafts/out-of-stock/hidden/missing-images/missing-SEO/low-quality counts, recently-edited list, recommended next action); list gains table/grid view toggle, density, saved column visibility and saved sort (persisted via LocalStorageService), plus real bulk assign-category/assign-tags/duplicate/CSV-export alongside existing publish/hide/delete; per-row and per-editor reusable ProductHealthWidget (images/SEO/price/category/description/inventory checklist + completion %); editor reorganized into General/Media/Pricing/Inventory/Categories/Attributes/SEO/Visibility/Advanced tabs, media now uses the shared MediaPickerComponent/ImageFieldComponent (primary image + reorderable gallery) instead of raw URL textareas, specifications/attributes/variants moved off pipe-delimited textareas onto the shared KeyValueEditorComponent, SEO tab explains fields in plain language with a live search-result preview, inventory relabeled in business language, toggles/badges use the shared Toggle/Badge components. Filled in the adminProducts i18n namespace (previously ~98% missing, rendering raw translation keys) across en/ru/hy.
2026-07-18 16:34:06 +04:00
seoExplain : 'Это то, что видно в результатах поиска — понятные заголовок и описание помогают найти товар.' ,
searchTitle : 'Заголовок для поиска' ,
searchTitleHint : 'Заголовок, показываемый в результатах поиска. Делайте е г о коротким.' ,
searchDescription : 'Описание для поиска' ,
searchDescriptionHint : 'Краткое описание под заголовком в результатах поиска.' ,
seoMissingTitle : 'Добавьте заголовок для поиска, чтобы товар можно было найти.' ,
seoMissingDescription : 'Добавьте описание для поиска, чтобы улучшить отображение товара.' ,
keywords : 'Ключевые слова' ,
featured : 'Рекомендуемый' ,
recommended : 'В подборке' ,
new : 'Новинка' ,
bestseller : 'Хит продаж' ,
badges : 'Значки (через запятую)' ,
htmlDescription : 'Подробное описание' ,
customer : 'Отзывы покупателей' ,
reviewsReadonly : 'Отзывы' ,
noReviews : 'Пока нет отзывов.' ,
questionsReadonly : 'Вопросы' ,
noQuestions : 'Пока нет вопросов.' ,
save : 'Сохранить товар' ,
groupGeneral : 'Основное' ,
groupMedia : 'Медиа' ,
groupPricing : 'Цена' ,
groupInventory : 'Склад' ,
groupCategories : 'Категории' ,
groupAttributes : 'Атрибуты' ,
groupSeo : 'SEO' ,
groupVisibility : 'Видимость' ,
groupAdvanced : 'Дополнительно' ,
healthImages : 'Изображения' ,
healthSeo : 'SEO' ,
healthPrice : 'Цена' ,
healthCategory : 'Категория' ,
healthDescription : 'Описание' ,
healthInventory : 'Склад' ,
totalProducts : 'В с е г о товаров' ,
publishedCount : 'Опубликовано' ,
draftsCount : 'Черновики' ,
outOfStockCount : 'Нет в наличии' ,
hiddenCount : 'Скрыто' ,
missingImagesCount : 'Без изображений' ,
missingSeoCount : 'Без SEO' ,
lowQualityCount : 'Низкое качество' ,
recentlyEdited : 'Недавно изменённые' ,
recommendedNext : 'Рекомендуемый следующий шаг' ,
openAction : 'Открыть' ,
recommendAddImages : 'У товара нет фото — добавьте хотя бы одно изображение.' ,
recommendAddSeo : 'У товара нет заголовка или описания для поиска — добавьте их.' ,
recommendRestock : 'Товар закончился на складе — пополните запас или скройте е г о .' ,
recommendNone : 'Отлично — каталог в хорошем состоянии.' ,
2026-07-16 00:19:41 +04:00
} ,
adminUsers : {
emptyTitle : 'Пользователи не найдены' ,
emptyDescription : 'Пригласите коллегу, чтобы начать.' ,
invitationsEmptyTitle : 'Нет ожидающих приглашений' ,
2026-07-18 22:44:39 +04:00
title : 'Команда' ,
name : 'Имя' ,
email : 'Email' ,
scope : 'Рабочая область' ,
role : 'Роль' ,
roles : 'Роли' ,
lastLogin : 'Последний вход' ,
sessions : 'Активные сессии' ,
currentSession : 'Текущая сессия' ,
invite : 'Пригласить участника' ,
sendInvite : 'Отправить приглашение' ,
revoke : 'Отозвать' ,
passwordlessHint : 'Участники входят через Telegram — пароли не нужны.' ,
confirmSuspend : 'Заблокировать этого участника? Доступ будет закрыт немедленно.' ,
2026-07-19 23:04:51 +04:00
suspend : 'Заблокировать' ,
reactivate : 'Восстановить' ,
2026-07-18 22:44:39 +04:00
scopeValue : {
marketplace : 'Витрина' ,
office : 'Бэк-офис' ,
} ,
statusValue : {
active : 'Активен' ,
invited : 'Приглашён' ,
suspended : 'Заблокирован' ,
} ,
invitationStatus : {
pending : 'Ожидает' ,
accepted : 'Принято' ,
expired : 'Истекло' ,
revoked : 'Отозвано' ,
} ,
fix(backoffice): wording quality pass across orders, moderation, transactions, users, customers
- Replaced hardcoded English audit/timeline text (order status changes,
review moderation events, user role/status changes) with proper
adminXxx.timelineEvent.*/adminUsers.audit.* i18n keys, so Recent
Activity/Timeline/Audit panels no longer mix English into ru/hy UI.
- Translated raw internal codes rendered directly to users: transaction
payment method ('card'/'qr'/'cash_on_delivery' -> adminTransactions.methodValue.*)
and user roles/permissions ('products.manage' etc -> adminUsers.roleValue.*/
adminUsers.permission.*), replacing developer-facing enum leakage with
real copy.
- Fixed wrong-noun list-footer counts: Orders/Transactions/Moderation
list pages all reused adminProducts.items ("N товаров"/"N products")
regardless of what was actually listed; each now has its own itemsCount
key ("N заказов", "N транзакций", "N отзывов").
- Fixed customer detail page's "Back" button reusing adminOrders.back
("Back to orders") instead of a customers-specific label.
- Added translation keys to en/ru/hy + translations.ts interface for all
of the above.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 21:20:37 +04:00
roleValue : {
owner : 'Владелец' ,
admin : 'Администратор' ,
editor : 'Редактор' ,
viewer : 'Наблюдатель' ,
} ,
permission : {
all : 'Полный доступ ко всем разделам' ,
productsManage : 'Управление товарами' ,
productsView : 'Просмотр товаров' ,
categoriesManage : 'Управление категориями' ,
ordersManage : 'Управление заказами' ,
ordersView : 'Просмотр заказов' ,
mediaManage : 'Управление медиатекой' ,
} ,
actor : {
admin : 'Администратор' ,
} ,
audit : {
roleChanged : 'Роль изменена на «{{role}}»' ,
statusChanged : 'Статус изменён на «{{status}}»' ,
} ,
2026-07-18 22:44:39 +04:00
} ,
adminTransactions : {
search : 'Поиск транзакций' ,
type : 'Тип' ,
method : 'Способ оплаты' ,
fix(backoffice): wording quality pass across orders, moderation, transactions, users, customers
- Replaced hardcoded English audit/timeline text (order status changes,
review moderation events, user role/status changes) with proper
adminXxx.timelineEvent.*/adminUsers.audit.* i18n keys, so Recent
Activity/Timeline/Audit panels no longer mix English into ru/hy UI.
- Translated raw internal codes rendered directly to users: transaction
payment method ('card'/'qr'/'cash_on_delivery' -> adminTransactions.methodValue.*)
and user roles/permissions ('products.manage' etc -> adminUsers.roleValue.*/
adminUsers.permission.*), replacing developer-facing enum leakage with
real copy.
- Fixed wrong-noun list-footer counts: Orders/Transactions/Moderation
list pages all reused adminProducts.items ("N товаров"/"N products")
regardless of what was actually listed; each now has its own itemsCount
key ("N заказов", "N транзакций", "N отзывов").
- Fixed customer detail page's "Back" button reusing adminOrders.back
("Back to orders") instead of a customers-specific label.
- Added translation keys to en/ru/hy + translations.ts interface for all
of the above.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 21:20:37 +04:00
itemsCount : 'транзакций' ,
2026-07-18 22:44:39 +04:00
fraud : 'Проверка на мошенничество' ,
flagged : 'Помечено' ,
2026-07-19 08:25:29 +04:00
flag : 'Пометить как подозрительную' ,
clearFlag : 'Снять пометку' ,
2026-07-18 22:44:39 +04:00
retry : 'Повторить' ,
audit : 'История' ,
emptyTitle : 'Транзакции не найдены' ,
emptyDescription : 'Попробуйте изменить фильтр или поисковый запрос.' ,
status : {
all : 'В с е статусы' ,
pending : 'В обработке' ,
success : 'Успешно' ,
failed : 'Ошибка' ,
retried : 'Повторено' ,
} ,
typeValue : {
all : 'В с е типы' ,
payment : 'Оплата' ,
refund : 'Возврат' ,
qr_payment : 'Оплата по QR' ,
} ,
fix(backoffice): wording quality pass across orders, moderation, transactions, users, customers
- Replaced hardcoded English audit/timeline text (order status changes,
review moderation events, user role/status changes) with proper
adminXxx.timelineEvent.*/adminUsers.audit.* i18n keys, so Recent
Activity/Timeline/Audit panels no longer mix English into ru/hy UI.
- Translated raw internal codes rendered directly to users: transaction
payment method ('card'/'qr'/'cash_on_delivery' -> adminTransactions.methodValue.*)
and user roles/permissions ('products.manage' etc -> adminUsers.roleValue.*/
adminUsers.permission.*), replacing developer-facing enum leakage with
real copy.
- Fixed wrong-noun list-footer counts: Orders/Transactions/Moderation
list pages all reused adminProducts.items ("N товаров"/"N products")
regardless of what was actually listed; each now has its own itemsCount
key ("N заказов", "N транзакций", "N отзывов").
- Fixed customer detail page's "Back" button reusing adminOrders.back
("Back to orders") instead of a customers-specific label.
- Added translation keys to en/ru/hy + translations.ts interface for all
of the above.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 21:20:37 +04:00
methodValue : {
card : 'Карта' ,
qr : 'QR-код' ,
cash_on_delivery : 'Наличными при получении' ,
} ,
2026-07-16 00:19:41 +04:00
} ,
adminMonitoring : {
eventsEmptyTitle : 'События не найдены' ,
eventsEmptyDescription : 'Попробуйте изменить фильтр категории или поисковый запрос.' ,
2026-07-18 22:44:39 +04:00
health : 'Проверки состояния' ,
queues : 'Фоновые очереди' ,
depth : 'В ожидании' ,
webhooks : 'Доставка вебхуков' ,
endpoint : 'Получатель' ,
event : 'Событие' ,
events : 'Журнал активности' ,
category : 'Категория' ,
level : 'Важность' ,
message : 'Описание' ,
2026-07-26 00:17:14 +04:00
technicalDetails : 'Технические детали' ,
2026-07-18 22:44:39 +04:00
categoryValue : {
all : 'В с е категории' ,
audit : 'Действия администраторов' ,
security : 'Безопасность' ,
login : 'Вход' ,
failed_login : 'Неудачный вход' ,
api : 'API' ,
error : 'Ошибка' ,
warning : 'Предупреждение' ,
} ,
queueStatus : {
healthy : 'Работает штатно' ,
degraded : 'Замедлена' ,
down : 'Остановлена' ,
} ,
webhookStatus : {
delivered : 'Доставлено' ,
failed : 'Ошибка' ,
pending : 'Ожидает' ,
} ,
levelValue : {
info : 'Инфо' ,
warning : 'Предупреждение' ,
error : 'Ошибка' ,
} ,
feat(admin): implement analytics and monitoring center
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Business Dashboard: revenue/orders/customers/AOV/top products/low stock/recent activity/warnings/completion% (Overview tab)
- Marketplace Health: real completion checks (images, SEO, categories, reviews, orders, translations, homepage, backend, performance) with clickable recommendations
- Product Analytics: top selling/most reviewed/worst rated/hidden/archived counts; top-viewed honestly marked Unknown (no view tracking exists)
- Customer Analytics: new/returning customers, average spend, retention - derived from real order data
- Search & Traffic tabs: honest 'Unknown - available after backend integration' placeholders, no fabricated numbers
- Recommendations engine: actionable cards (missing images/SEO/category, empty categories, incomplete homepage, unpublished static pages) linking to the relevant admin page
- System Monitoring: added real draft/publish/sync/backend-connectivity state from AdminDashboardFacade
- CSV export extended to top products and health checks; added print action
- New adminAnalytics.* and adminMarketplaceHealth.* i18n namespaces (en/ru/hy), no raw i18n keys
- Reused existing shared UI (app-table/app-badge/app-skeleton/app-empty-state) and content-health-widget completion-meter pattern - no new backend APIs, no storage changes
2026-07-18 22:33:36 +04:00
systemState : 'Состояние системы' ,
backendConnectivity : 'Бэкенд' ,
connected : 'Подключено' ,
loading : 'Загрузка' ,
draftState : 'Черновик' ,
unsavedChanges : 'Есть несохранённые изменения' ,
noDraft : 'Черновика нет' ,
lastSaved : 'Последнее сохранение' ,
lastPublished : 'Последняя публикация' ,
syncStatus : 'Синхронизация' ,
2026-07-16 00:19:41 +04:00
} ,
adminAnalytics : {
topProductsEmptyTitle : 'Нет продаж товаров за этот период' ,
topProductsEmptyDescription : 'Попробуйте выбрать более широкий диапазон дат.' ,
2026-07-18 22:44:39 +04:00
topProducts : 'Топ товаров' ,
feat(admin): implement analytics and monitoring center
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Business Dashboard: revenue/orders/customers/AOV/top products/low stock/recent activity/warnings/completion% (Overview tab)
- Marketplace Health: real completion checks (images, SEO, categories, reviews, orders, translations, homepage, backend, performance) with clickable recommendations
- Product Analytics: top selling/most reviewed/worst rated/hidden/archived counts; top-viewed honestly marked Unknown (no view tracking exists)
- Customer Analytics: new/returning customers, average spend, retention - derived from real order data
- Search & Traffic tabs: honest 'Unknown - available after backend integration' placeholders, no fabricated numbers
- Recommendations engine: actionable cards (missing images/SEO/category, empty categories, incomplete homepage, unpublished static pages) linking to the relevant admin page
- System Monitoring: added real draft/publish/sync/backend-connectivity state from AdminDashboardFacade
- CSV export extended to top products and health checks; added print action
- New adminAnalytics.* and adminMarketplaceHealth.* i18n namespaces (en/ru/hy), no raw i18n keys
- Reused existing shared UI (app-table/app-badge/app-skeleton/app-empty-state) and content-health-widget completion-meter pattern - no new backend APIs, no storage changes
2026-07-18 22:33:36 +04:00
print : 'Печать' ,
tabsLabel : 'Разделы аналитики' ,
tab : {
overview : 'Обзор' ,
health : 'Здоровье' ,
products : 'Товары' ,
customers : 'Клиенты' ,
search : 'Поиск' ,
traffic : 'Трафик' ,
recommendations : 'Рекомендации' ,
} ,
revenue : 'Выручка' ,
orders : 'Заказы' ,
customers : 'Клиенты' ,
avgOrderValue : 'Средний чек' ,
conversion : 'Конверсия' ,
completionPercent : 'Готовность' ,
unknown : 'Неизвестно' ,
salesChart : 'Продажи' ,
quantitySold : 'Продано, шт.' ,
lowStock : 'Мало на складе' ,
lowStockEmptyTitle : 'Нет товаров с низким остатком' ,
quantity : 'Количество' ,
status : 'Статус' ,
recentActivity : 'Недавняя активность' ,
recentActivityEmptyTitle : 'Нет недавней активности' ,
activityDraftSaved : 'Черновик сохранён' ,
activityPublished : 'Опубликовано' ,
warnings : 'Предупреждения' ,
topViewed : 'Самые просматриваемые' ,
hiddenProducts : 'Скрытые товары' ,
archivedProducts : 'Архивные товары' ,
mostReviewed : 'Больше всего отзывов' ,
worstRated : 'Худший рейтинг' ,
noReviewedProducts : 'Пока нет товаров с отзывами' ,
reviewCount : 'Отзывы' ,
avgRating : 'Средний рейтинг' ,
newCustomers : 'Новые клиенты' ,
returningCustomers : 'Повторные клиенты' ,
averageSpend : 'Средние траты' ,
retention : 'Удержание' ,
searchAnalytics : 'Аналитика поиска' ,
trafficAnalytics : 'Трафик' ,
availableAfterBackend : 'Будет доступно после интеграции с бэкендом.' ,
pendingBackend : 'Ожидает бэкенд' ,
pendingBackendHint : 'Отслеживание поисковых запросов пока не реализовано.' ,
funnelsHeatmaps : 'Воронки и тепловые карты' ,
visitors : 'Посетители' ,
products : 'Товары' ,
categories : 'Категории' ,
} ,
adminMarketplaceHealth : {
title : 'Здоровье маркетплейса' ,
complete : 'готово' ,
recommendationsTitle : 'Рекомендации' ,
recommendNone : 'Всё в порядке.' ,
checkImages : 'У товаров есть изображения' ,
checkSeo : 'У товаров заполнено SEO' ,
checkCategories : 'В категориях есть товары' ,
checkReviews : 'Отзывы модерируются' ,
checkOrders : 'Заказы обрабатываются' ,
checkTranslations : 'Переводы заполнены' ,
checkHomepage : 'Главная страница настроена' ,
checkBackend : 'Связь с бэкендом' ,
checkPerformance : 'Производительность' ,
recommendImages : 'Добавьте изображения товарам без них' ,
recommendImagesCount : 'Товары без изображений снижают конверсию.' ,
recommendSeo : 'Заполните SEO для товаров без него' ,
recommendSeoCount : 'Отсутствие SEO ухудшает видимость в поиске.' ,
recommendCategory : 'Назначьте категорию товарам без категории' ,
recommendCategoryCount : 'Товары без категории труднее найти.' ,
recommendEmptyCategories : 'Категории без товаров' ,
recommendEmptyCategoriesCount : 'Рассмотрите объединение или удаление пустых категорий.' ,
recommendHomepage : 'Главная страница не заполнена' ,
recommendStaticPages : 'Есть неопубликованные статические страницы' ,
severity : {
info : 'Инфо' ,
warning : 'Внимание' ,
critical : 'Критично' ,
} ,
2026-07-16 00:19:41 +04:00
} ,
feat(admin): build shared admin shell
Sidebar (Dashboard/Catalog group/Products/Categories/Orders/Transactions/
Reviews/Reports/Content/Media/Marketplace Builder/Users/Settings/
Monitoring/Analytics + Documentation/Help/Logout), sticky topbar
(breadcrumbs, page title/description, search, notifications, tenant
selector and quick-publish placeholders, current user), reserved
right-rail slot, scrollable content area. Desktop 280px sidebar, tablet
icon rail, mobile drawer with focus management and Escape-to-close.
Nav items without a built page (Reviews, Reports, Settings, Docs, Help)
render disabled with a coming-soon badge instead of dead links; Content
and Marketplace Builder route to the existing project-editor pages
(static-pages / general) rather than duplicating them.
All 15 /backoffice/** routes now render through AdminLayoutComponent;
the public storefront header/back-button/footer no longer render on
admin routes (app.ts/app.html gate on a new isAdminRoute signal).
Added the adminShell i18n namespace (ru/en/hy) for every new shell
string so this doesn't add to the existing untranslated-admin-UI gap
tracked in KNOWN-ISSUES.md.
Colors/type sizes follow DESIGN.md tokens; the two rgba() modal-scrim
values are a documented, intentional exception (neutral overlay,
not a themed token).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 00:12:19 +04:00
adminShell : {
skipToContent : 'Перейти к содержимому' ,
fix(backoffice): WCAG 2.1 AA accessibility fixes
RC A11Y-01 audit pass, Backoffice (admin/*) area. Builds on 712a7b4/63c9cee's
composition pass (scope="col", skeletons, empty-states) without redoing that
work.
- Sidebar nav landmark: admin-layout's <nav aria-label> reused the
"Dashboard" nav-item translation key as its landmark label, misleadingly
announcing the whole sidebar as "Dashboard" - added a dedicated
adminShell.sidebarLabel key ("Admin sidebar navigation") in en/ru/hy.
Skip link, #admin-content main landmark, Escape handling, and mobile-drawer
focus management were already correct - verified, not touched.
- Categories tree drag-and-drop keyboard fallback (WCAG 2.1.1): the category
tree's native HTML5 DnD (draggable/dragstart/drop) reorders siblings with
no keyboard equivalent - existing arrow-key tree navigation only expands/
collapses/selects, never reorders. Added per-row move-up/move-down icon
buttons (disabled at sibling boundaries), reusing the existing `reorder`
output so the facade's reorder logic is untouched; new
adminCategories.moveUp/moveDown keys in en/ru/hy.
- Screen-reader loading announcements: skeleton-row loading states across
Products, Categories, Customers, Orders, Transactions, Users, Reviews,
Monitoring (webhooks/events), and Analytics (summary cards + top products)
were purely visual (app-skeleton is aria-hidden by design) with no
accessible "loading" text, unlike the storefront/product-details pattern -
added role="status"/aria-live="polite"/aria-busy + sr-only text using the
existing common.loading key.
- Table row headers: added scope="row" to the primary identifying cell
(product/category/customer name, order number, transaction order number,
user name, review customer, report target, top-products/low-stock product
name, webhook endpoint) on 9 tables that only had scope="col". Added
matching `tbody th[scope='row'] { font-weight/color/text-align/
vertical-align }` + last-row border resets in each component's own scss so
the semantic change doesn't alter visuals (the shared app-table stylesheet
styles all <th> as bold/muted by default).
Verified via `git show --stat` of fb1afb7/a03260e and `docs/UI-COMPOSITION-
REVIEW.md`'s Backoffice sections first, per instructions - confirmed
scope="col" coverage already complete, all admin modals already route
through the shared app-dialog (focus-trap/Escape/return-focus already
correct, nothing to fix), and the bare-<select> filters still carry
aria-label per the accepted Sprint 28 decision (not re-migrated to
app-select).
Flagged, not fixed:
- No toast/notification system exists anywhere in this codebase (product/
category save and delete call the gateway with no success/error UI at
all, not even a subscribe error handler) - there is nothing to wire
aria-live onto without adding a new UI mechanism, which is out of scope
for an a11y-only pass. A prerequisite feature-level fix, not an a11y
regression.
- Dashboard's per-card metric/status-row/timeline skeletons (dashboard-
metric, dashboard-status-row, dashboard-timeline) were left without
aria-live wiring - wrapping each of the ~10 simultaneous mini-widgets in
its own live region would fire a burst of redundant announcements; needs
a single page-level "loading dashboard" region instead, a larger change
than this surgical pass.
- Monitoring's events table and the notifications dropdown (role="menu"
with a static empty-state message, aria-haspopup="true") were left as-is -
matches the same partial-widget-pattern precedent already accepted for
locale-tabs/product-tabs in the storefront and builder passes.
- Analytics `lowStockProducts` table's missing loading-skeleton branch
(already flagged, not fixed, in the RC-Visual-02 pass) - untouched again
here for the same reason.
Verified: npx tsc --noEmit clean; npm run build green (only the pre-existing
768.57 kB vs 700 kB initial-bundle budget warning, unrelated to this pass).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-24 09:18:09 +04:00
sidebarLabel : 'Навигация панели администратора' ,
feat(admin): build shared admin shell
Sidebar (Dashboard/Catalog group/Products/Categories/Orders/Transactions/
Reviews/Reports/Content/Media/Marketplace Builder/Users/Settings/
Monitoring/Analytics + Documentation/Help/Logout), sticky topbar
(breadcrumbs, page title/description, search, notifications, tenant
selector and quick-publish placeholders, current user), reserved
right-rail slot, scrollable content area. Desktop 280px sidebar, tablet
icon rail, mobile drawer with focus management and Escape-to-close.
Nav items without a built page (Reviews, Reports, Settings, Docs, Help)
render disabled with a coming-soon badge instead of dead links; Content
and Marketplace Builder route to the existing project-editor pages
(static-pages / general) rather than duplicating them.
All 15 /backoffice/** routes now render through AdminLayoutComponent;
the public storefront header/back-button/footer no longer render on
admin routes (app.ts/app.html gate on a new isAdminRoute signal).
Added the adminShell i18n namespace (ru/en/hy) for every new shell
string so this doesn't add to the existing untranslated-admin-UI gap
tracked in KNOWN-ISSUES.md.
Colors/type sizes follow DESIGN.md tokens; the two rgba() modal-scrim
values are a documented, intentional exception (neutral overlay,
not a themed token).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 00:12:19 +04:00
openSidebar : 'Открыть меню' ,
closeSidebar : 'Закрыть меню' ,
collapseSidebar : 'Свернуть меню' ,
expandSidebar : 'Развернуть меню' ,
nav : {
dashboard : 'Панель управления' ,
catalogGroup : 'Каталог' ,
products : 'Товары' ,
categories : 'Категории' ,
orders : 'Заказы' ,
2026-07-18 21:47:54 +04:00
customers : 'Клиенты' ,
feat(admin): implement review and moderation center
New Reviews & Moderation feature (frontend only): moderation dashboard (real pending/approved/rejected/reported/spam counts, average rating, recent activity, moderation-health%, computed from the full review queue); reviews list with table/cards, density, saved column visibility, search/status/rating filters, bulk approve/reject/spam/hide/export; review detail shows customer/product/rating/text/photos/timeline/moderator-notes with a real moderation workflow (approve/reject/spam/hide/restore/pin/feature, feature disabled with an explanation unless the review is approved); reusable ReviewHealthWidget (rating/text/media/moderated/report-status/visible + completion%); reports queue lists reports against products/reviews/customers/categories with resolve/dismiss, and honestly renders 'Not available yet' rather than fabricating a value wherever a target can't be resolved (e.g. photos, customer-target reports). Backed by a new in-memory AdminModerationLocalGateway seeded from real product data - the same mock-gateway pattern already used by every other admin feature in this app (orders/products/categories), since no review/report backend exists to reuse. Replaced the 'Reviews' comingSoon nav placeholder with a working link; added full adminModeration i18n coverage.
2026-07-18 22:01:16 +04:00
moderation : 'Отзывы и модерация' ,
feat(admin): build shared admin shell
Sidebar (Dashboard/Catalog group/Products/Categories/Orders/Transactions/
Reviews/Reports/Content/Media/Marketplace Builder/Users/Settings/
Monitoring/Analytics + Documentation/Help/Logout), sticky topbar
(breadcrumbs, page title/description, search, notifications, tenant
selector and quick-publish placeholders, current user), reserved
right-rail slot, scrollable content area. Desktop 280px sidebar, tablet
icon rail, mobile drawer with focus management and Escape-to-close.
Nav items without a built page (Reviews, Reports, Settings, Docs, Help)
render disabled with a coming-soon badge instead of dead links; Content
and Marketplace Builder route to the existing project-editor pages
(static-pages / general) rather than duplicating them.
All 15 /backoffice/** routes now render through AdminLayoutComponent;
the public storefront header/back-button/footer no longer render on
admin routes (app.ts/app.html gate on a new isAdminRoute signal).
Added the adminShell i18n namespace (ru/en/hy) for every new shell
string so this doesn't add to the existing untranslated-admin-UI gap
tracked in KNOWN-ISSUES.md.
Colors/type sizes follow DESIGN.md tokens; the two rgba() modal-scrim
values are a documented, intentional exception (neutral overlay,
not a themed token).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 00:12:19 +04:00
transactions : 'Транзакции' ,
reviews : 'Отзывы' ,
reports : 'Отчёты' ,
feat(admin): Seller Management Phase 1 UI - Partners section, empty state, request/learn-more dialogs
No backend, no CRUD, no API, no business logic - production-quality
UI only, built entirely from existing shared components (app-dialog,
app-empty-state, app-button, app-form-field, app-input, app-icon,
app-badge). Gated per ADR-011: reads
modules.sellerManagement.enabled from bootstrap (always false today,
no backend sets it) rather than hardcoding disabled state.
New:
- AdminSellerManagementPageComponent (features/admin/seller-management/
pages/) - renders the specified empty state (title/description/
Request Access + Learn More buttons) using existing shared/ui
primitives only, no new UI infrastructure.
- Request Access dialog: Company/Email/Message form via
app-form-field + app-input + a plain textarea (no dedicated
textarea component exists yet, styled to match app-input's own
tokens exactly). Submission is mocked (setTimeout), no API call.
On submit: closes and opens a success dialog ("Thank you...").
- Learn More dialog: 6 capability bullets (seller dashboards,
storefronts, permissions, analytics, product ownership, marketplace
administration) under a "Coming Soon" badge.
- New admin nav group "Partners" > "Seller Management" link
(admin-nav.model.ts), new route /backoffice/partners/seller-management
(app.routes.ts), using the same loadComponent/breadcrumb pattern as
every other admin route.
Translations: full en/ru/hy coverage, zero hardcoded strings - new
adminShell.nav.{partnersGroup,sellerManagement},
adminShell.pages.sellerManagement, and a new adminSellerManagement.*
namespace (emptyState/requestDialog/requestSuccessDialog/
learnMoreDialog) added to translations.ts (types) and all three
locale files.
Accessibility: inherited from app-dialog (role="dialog",
aria-modal, focus trap on Tab/Shift+Tab, Escape to close, focus
restored to trigger on close) - no new a11y code needed, reused as-is.
Responsive: existing --space-*/--font-size-* tokens throughout,
flex-wrap on button row, mobile breakpoint stacks actions full-width.
Verified live (ru locale, devBypassAdmin): nav group/link render
correctly, breadcrumb shows "Управление продавцами", empty state
copy matches spec exactly, Request Access dialog opens with all 3
fields + Cancel/Send Request, filled + submitted -> success dialog
with exact spec copy, Learn More dialog shows all 6 bullets + Coming
Soon badge, no console errors, verified again at 375px mobile
viewport. tsc --noEmit clean, ng build clean (pre-existing bundle-
budget warning only), arch:check (boundaries + cycles) clean.
2026-07-26 20:47:18 +04:00
partnersGroup : 'Партнёры' ,
sellerManagement : 'Управление продавцами' ,
feat(admin): build shared admin shell
Sidebar (Dashboard/Catalog group/Products/Categories/Orders/Transactions/
Reviews/Reports/Content/Media/Marketplace Builder/Users/Settings/
Monitoring/Analytics + Documentation/Help/Logout), sticky topbar
(breadcrumbs, page title/description, search, notifications, tenant
selector and quick-publish placeholders, current user), reserved
right-rail slot, scrollable content area. Desktop 280px sidebar, tablet
icon rail, mobile drawer with focus management and Escape-to-close.
Nav items without a built page (Reviews, Reports, Settings, Docs, Help)
render disabled with a coming-soon badge instead of dead links; Content
and Marketplace Builder route to the existing project-editor pages
(static-pages / general) rather than duplicating them.
All 15 /backoffice/** routes now render through AdminLayoutComponent;
the public storefront header/back-button/footer no longer render on
admin routes (app.ts/app.html gate on a new isAdminRoute signal).
Added the adminShell i18n namespace (ru/en/hy) for every new shell
string so this doesn't add to the existing untranslated-admin-UI gap
tracked in KNOWN-ISSUES.md.
Colors/type sizes follow DESIGN.md tokens; the two rgba() modal-scrim
values are a documented, intentional exception (neutral overlay,
not a themed token).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 00:12:19 +04:00
content : 'Контент' ,
mediaLibrary : 'Медиатека' ,
marketplaceBuilder : 'Конструктор маркетплейса' ,
users : 'Пользователи' ,
settings : 'Настройки' ,
monitoring : 'Мониторинг' ,
analytics : 'Аналитика' ,
documentation : 'Документация' ,
help : 'Помощь' ,
logout : 'Выйти' ,
comingSoonBadge : 'Скоро' ,
} ,
topbar : {
searchLabel : 'Поиск по админ-панели' ,
searchPlaceholder : 'Искать товары, заказы, страницы...' ,
notifications : 'Уведомления' ,
notificationsEmpty : 'Новых уведомлений нет' ,
account : 'Аккаунт администратора' ,
tenantSelector : 'Магазин' ,
tenantSelectorComingSoon : 'Переключение между магазинами скоро появится' ,
quickPublish : 'Опубликовать' ,
quickPublishComingSoon : 'Быстрая публикация скоро появится' ,
} ,
breadcrumbHome : 'Админ-панель' ,
pages : {
dashboard : { title : 'Панель управления' , description : 'Обзор состояния вашего маркетплейса' } ,
products : { title : 'Товары' , description : 'Управляйте карточками товаров и их видимостью' } ,
productCreate : { title : 'Новый товар' , description : 'Заполните карточку, чтобы добавить товар в каталог' } ,
productEdit : { title : 'Редактирование товара' , description : 'Измените данные товара' } ,
productDuplicate : { title : 'Копия товара' , description : 'Создайте новый товар на основе существующего' } ,
categories : { title : 'Категории' , description : 'Постройте дерево категорий каталога' } ,
categoryCreate : { title : 'Новая категория' , description : 'Добавьте категорию в дерево каталога' } ,
categoryEdit : { title : 'Редактирование категории' , description : 'Измените данные категории' } ,
orders : { title : 'Заказы' , description : 'Просматривайте и обрабатывайте заказы покупателей' } ,
orderDetail : { title : 'Заказ' , description : 'Детали и статус заказа' } ,
2026-07-18 21:47:54 +04:00
customers : { title : 'Клиенты' , description : 'В с е , кто оформлял заказ' } ,
customerDetail : { title : 'Клиент' , description : 'Профиль клиента, заказы и активность' } ,
feat(admin): implement review and moderation center
New Reviews & Moderation feature (frontend only): moderation dashboard (real pending/approved/rejected/reported/spam counts, average rating, recent activity, moderation-health%, computed from the full review queue); reviews list with table/cards, density, saved column visibility, search/status/rating filters, bulk approve/reject/spam/hide/export; review detail shows customer/product/rating/text/photos/timeline/moderator-notes with a real moderation workflow (approve/reject/spam/hide/restore/pin/feature, feature disabled with an explanation unless the review is approved); reusable ReviewHealthWidget (rating/text/media/moderated/report-status/visible + completion%); reports queue lists reports against products/reviews/customers/categories with resolve/dismiss, and honestly renders 'Not available yet' rather than fabricating a value wherever a target can't be resolved (e.g. photos, customer-target reports). Backed by a new in-memory AdminModerationLocalGateway seeded from real product data - the same mock-gateway pattern already used by every other admin feature in this app (orders/products/categories), since no review/report backend exists to reuse. Replaced the 'Reviews' comingSoon nav placeholder with a working link; added full adminModeration i18n coverage.
2026-07-18 22:01:16 +04:00
moderation : { title : 'Отзывы и модерация' , description : 'Проверяйте и модерируйте отзывы клиентов' } ,
reviewDetail : { title : 'Отзыв' , description : 'Детали отзыва и действия модерации' } ,
reportsQueue : { title : 'Очередь жалоб' , description : 'Контент, на который пожаловались клиенты' } ,
feat(admin): build shared admin shell
Sidebar (Dashboard/Catalog group/Products/Categories/Orders/Transactions/
Reviews/Reports/Content/Media/Marketplace Builder/Users/Settings/
Monitoring/Analytics + Documentation/Help/Logout), sticky topbar
(breadcrumbs, page title/description, search, notifications, tenant
selector and quick-publish placeholders, current user), reserved
right-rail slot, scrollable content area. Desktop 280px sidebar, tablet
icon rail, mobile drawer with focus management and Escape-to-close.
Nav items without a built page (Reviews, Reports, Settings, Docs, Help)
render disabled with a coming-soon badge instead of dead links; Content
and Marketplace Builder route to the existing project-editor pages
(static-pages / general) rather than duplicating them.
All 15 /backoffice/** routes now render through AdminLayoutComponent;
the public storefront header/back-button/footer no longer render on
admin routes (app.ts/app.html gate on a new isAdminRoute signal).
Added the adminShell i18n namespace (ru/en/hy) for every new shell
string so this doesn't add to the existing untranslated-admin-UI gap
tracked in KNOWN-ISSUES.md.
Colors/type sizes follow DESIGN.md tokens; the two rgba() modal-scrim
values are a documented, intentional exception (neutral overlay,
not a themed token).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 00:12:19 +04:00
transactions : { title : 'Транзакции' , description : 'Платежи, возвраты и проверка мошенничества' } ,
media : { title : 'Медиатека' , description : 'Изображения и файлы для товаров и страниц' } ,
users : { title : 'Пользователи' , description : 'Команда администраторов и права доступа' } ,
monitoring : { title : 'Мониторинг' , description : 'Состояние очередей, вебхуков и системных событий' } ,
analytics : { title : 'Аналитика' , description : 'Продажи, товары и поведение покупателей' } ,
feat(admin): Seller Management Phase 1 UI - Partners section, empty state, request/learn-more dialogs
No backend, no CRUD, no API, no business logic - production-quality
UI only, built entirely from existing shared components (app-dialog,
app-empty-state, app-button, app-form-field, app-input, app-icon,
app-badge). Gated per ADR-011: reads
modules.sellerManagement.enabled from bootstrap (always false today,
no backend sets it) rather than hardcoding disabled state.
New:
- AdminSellerManagementPageComponent (features/admin/seller-management/
pages/) - renders the specified empty state (title/description/
Request Access + Learn More buttons) using existing shared/ui
primitives only, no new UI infrastructure.
- Request Access dialog: Company/Email/Message form via
app-form-field + app-input + a plain textarea (no dedicated
textarea component exists yet, styled to match app-input's own
tokens exactly). Submission is mocked (setTimeout), no API call.
On submit: closes and opens a success dialog ("Thank you...").
- Learn More dialog: 6 capability bullets (seller dashboards,
storefronts, permissions, analytics, product ownership, marketplace
administration) under a "Coming Soon" badge.
- New admin nav group "Partners" > "Seller Management" link
(admin-nav.model.ts), new route /backoffice/partners/seller-management
(app.routes.ts), using the same loadComponent/breadcrumb pattern as
every other admin route.
Translations: full en/ru/hy coverage, zero hardcoded strings - new
adminShell.nav.{partnersGroup,sellerManagement},
adminShell.pages.sellerManagement, and a new adminSellerManagement.*
namespace (emptyState/requestDialog/requestSuccessDialog/
learnMoreDialog) added to translations.ts (types) and all three
locale files.
Accessibility: inherited from app-dialog (role="dialog",
aria-modal, focus trap on Tab/Shift+Tab, Escape to close, focus
restored to trigger on close) - no new a11y code needed, reused as-is.
Responsive: existing --space-*/--font-size-* tokens throughout,
flex-wrap on button row, mobile breakpoint stacks actions full-width.
Verified live (ru locale, devBypassAdmin): nav group/link render
correctly, breadcrumb shows "Управление продавцами", empty state
copy matches spec exactly, Request Access dialog opens with all 3
fields + Cancel/Send Request, filled + submitted -> success dialog
with exact spec copy, Learn More dialog shows all 6 bullets + Coming
Soon badge, no console errors, verified again at 375px mobile
viewport. tsc --noEmit clean, ng build clean (pre-existing bundle-
budget warning only), arch:check (boundaries + cycles) clean.
2026-07-26 20:47:18 +04:00
sellerManagement : { title : 'Управление продавцами' , description : 'Подключайте независимых продавцов к вашему маркетплейсу с централизованным администрированием' } ,
} ,
} ,
adminSellerManagement : {
emptyState : {
title : 'Управление продавцами' ,
description : 'Позвольте торговым центрам, маркетплейсам и корпоративным клиентам подключать независимых продавцов, сохраняя централизованное администрирование. Этот модуль сейчас в разработке.' ,
requestAccess : 'Запросить доступ' ,
learnMore : 'Узнать больше' ,
} ,
requestDialog : {
title : 'Запросить доступ' ,
companyLabel : 'Компания' ,
companyPlaceholder : 'Название вашей компании' ,
emailLabel : 'Email' ,
emailPlaceholder : 'you@company.com' ,
messageLabel : 'Сообщение' ,
messagePlaceholder : 'Расскажите о вашем маркетплейсе и потребностях в продавцах' ,
cancel : 'Отмена' ,
send : 'Отправить запрос' ,
} ,
requestSuccessDialog : {
title : 'Спасибо' ,
message : 'Наша команда получила ваш запрос. Мы свяжемся с вами, как только Управление продавцами станет доступно.' ,
close : 'Закрыть' ,
} ,
learnMoreDialog : {
title : 'Управление продавцами' ,
comingSoonBadge : 'Скоро' ,
features : {
sellerDashboards : 'Личные кабинеты продавцов' ,
sellerStorefronts : 'Витрины продавцов' ,
sellerPermissions : 'Права доступа продавцов' ,
sellerAnalytics : 'Аналитика продавцов' ,
productOwnership : 'Владение товарами' ,
marketplaceAdministration : 'Администрирование маркетплейса' ,
} ,
close : 'Закрыть' ,
feat(admin): build shared admin shell
Sidebar (Dashboard/Catalog group/Products/Categories/Orders/Transactions/
Reviews/Reports/Content/Media/Marketplace Builder/Users/Settings/
Monitoring/Analytics + Documentation/Help/Logout), sticky topbar
(breadcrumbs, page title/description, search, notifications, tenant
selector and quick-publish placeholders, current user), reserved
right-rail slot, scrollable content area. Desktop 280px sidebar, tablet
icon rail, mobile drawer with focus management and Escape-to-close.
Nav items without a built page (Reviews, Reports, Settings, Docs, Help)
render disabled with a coming-soon badge instead of dead links; Content
and Marketplace Builder route to the existing project-editor pages
(static-pages / general) rather than duplicating them.
All 15 /backoffice/** routes now render through AdminLayoutComponent;
the public storefront header/back-button/footer no longer render on
admin routes (app.ts/app.html gate on a new isAdminRoute signal).
Added the adminShell i18n namespace (ru/en/hy) for every new shell
string so this doesn't add to the existing untranslated-admin-UI gap
tracked in KNOWN-ISSUES.md.
Colors/type sizes follow DESIGN.md tokens; the two rgba() modal-scrim
values are a documented, intentional exception (neutral overlay,
not a themed token).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 00:12:19 +04:00
} ,
} ,
2026-02-26 23:09:20 +04:00
} ;