2026-02-26 23:09:20 +04:00
import { Translations } from './translations' ;
export const en : Translations = {
header : {
home : 'Home' ,
search : 'Search' ,
about : 'About' ,
contacts : 'Contacts' ,
searchPlaceholder : 'Search...' ,
catalog : 'Catalog' ,
2026-07-09 01:13:54 +04:00
wishlist : 'Wishlist' ,
compare : 'Compare' ,
2026-07-09 02:29:12 +04:00
openMenu : 'Open menu' ,
closeMenu : 'Close menu' ,
2026-02-26 23:09:20 +04:00
} ,
footer : {
description : 'A modern marketplace for comfortable shopping' ,
company : 'Company' ,
aboutUs : 'About us' ,
contacts : 'Contacts' ,
requisites : 'Company details' ,
support : 'Support' ,
faq : 'FAQ' ,
delivery : 'Delivery' ,
guarantee : 'Warranty' ,
legal : 'Legal information' ,
offer : 'Public offer' ,
privacy : 'Privacy policy' ,
returns : 'Returns' ,
info : 'Information' ,
aboutCompany : 'About company' ,
documents : 'Documents' ,
paymentRules : 'Payment terms' ,
returnPolicy : 'Return policy' ,
publicOffer : 'Public offer' ,
help : 'Help' ,
payment : 'Payment' ,
allRightsReserved : 'All rights reserved.' ,
} ,
home : {
welcomeTo : 'Welcome to {{brand}}' ,
subtitle : 'Find everything you need in one place' ,
startSearch : 'Start search' ,
loading : 'Loading categories...' ,
errorTitle : 'Something went wrong' ,
retry : 'Try again' ,
categoriesTitle : 'Product categories' ,
categoriesSubtitle : 'Choose a category' ,
categoriesEmpty : 'Categories coming soon' ,
categoriesEmptyDesc : 'We are working on filling the catalog' ,
dexarHeroTitle : 'Find everything here' ,
dexarHeroSubtitle : 'Thousands of products in one place' ,
dexarHeroTagline : 'simple and convenient' ,
goToCatalog : 'Go to catalog' ,
findProduct : 'Find a product' ,
loadingDexar : 'Loading categories...' ,
catalogTitle : 'Product catalog' ,
emptyCategoriesDexar : 'No categories yet' ,
categoriesSoonDexar : 'Categories will appear here soon' ,
itemsCount : '{{count}} products' ,
} ,
cart : {
title : 'Cart' ,
clear : 'Clear' ,
empty : 'Cart is empty' ,
emptyDesc : 'Add products to start shopping' ,
goShopping : 'Start shopping' ,
total : 'Total' ,
items : 'Products' ,
deliveryLabel : 'Delivery' ,
2026-06-21 23:13:01 +04:00
deliveryMethod : 'Delivery option' ,
selectDelivery : 'Select delivery option' ,
deliveryPlace : 'Place' ,
deliveryTime : 'Delivery time' ,
digitalDelivery : 'Digital delivery' ,
deliveryRequired : 'Select delivery for every shippable item before checkout.' ,
2026-02-26 23:09:20 +04:00
toPay : 'To pay' ,
agreeWith : 'I agree with the' ,
publicOffer : 'public offer' ,
returnPolicy : 'return policy' ,
guaranteeTerms : 'warranty terms' ,
privacyPolicy : 'privacy policy' ,
and : 'and' ,
checkout : 'Place order' ,
2026-06-29 00:06:18 +04:00
payViaQr : 'Pay via QR' ,
payViaCard : 'Pay via card' ,
2026-02-26 23:09:20 +04:00
close : 'Close' ,
creatingPayment : 'Creating payment...' ,
waitFewSeconds : 'Please wait a few seconds' ,
scanQr : 'Scan the QR code to pay' ,
amountToPay : 'Amount due:' ,
waitingPayment : 'Waiting for payment...' ,
copied : '✓ Copied' ,
copyLink : 'Copy link' ,
openNewTab : 'Open in new tab' ,
paymentSuccess : 'Congratulations! Payment successful!' ,
paymentSuccessDesc : 'Enter your contact details and we will send your purchase within a few minutes' ,
sending : 'Sending...' ,
send : 'Send' ,
2026-06-02 00:57:36 +04:00
paymentError : 'Unable to create payment' ,
paymentErrorDesc : 'We could not prepare the payment QR code right now. Please try again in a moment.' ,
retryPayment : 'Try again' ,
2026-02-26 23:09:20 +04:00
paymentTimeout : 'Payment timed out' ,
paymentTimeoutDesc : 'We did not receive payment confirmation within 3 minutes.' ,
autoClose : 'Window will close automatically...' ,
confirmClear : 'Are you sure you want to clear the cart?' ,
2026-07-09 02:29:12 +04:00
removeItem : 'Remove item' ,
2026-07-19 23:39:14 +04:00
increaseQuantity : 'Increase quantity' ,
decreaseQuantity : 'Decrease quantity' ,
2026-07-09 02:29:12 +04:00
paymentQrAlt : 'Payment QR code' ,
2026-02-26 23:09:20 +04:00
acceptTerms : 'Please accept the offer terms, return policy, and warranty terms to proceed with the order.' ,
copyError : 'Copy error:' ,
emailSuccess : 'Email sent successfully! Check your inbox.' ,
emailError : 'An error occurred while sending the email. Please try again.' ,
phoneRequired : 'Phone number is required' ,
phoneMoreDigits : 'Enter {{count}} more digits' ,
phoneTooMany : 'Too many digits' ,
emailRequired : 'Email is required' ,
emailTooShort : 'Email is too short (minimum 5 characters)' ,
emailTooLong : 'Email is too long (maximum 100 characters)' ,
emailNeedsAt : 'Email must contain @' ,
emailNeedsDomain : 'Email must contain a domain (.com, .ru, etc.)' ,
emailInvalid : 'Invalid email format' ,
2026-03-24 00:09:11 +04:00
loginRequired : 'Log in to checkout' ,
loginRequiredDesc : 'Please log in via Telegram to place your order' ,
loginWithTelegram : 'Log in with Telegram' ,
orScanQr : 'Or scan the QR code' ,
2026-02-26 23:09:20 +04:00
} ,
search : {
title : 'Product search' ,
placeholder : 'Enter product name...' ,
2026-07-10 13:25:31 +04:00
searchBarAria : 'Search bar' ,
2026-02-26 23:09:20 +04:00
resultsCount : 'Products found:' ,
searching : 'Searching...' ,
retry : 'Try again' ,
noResults : 'Nothing found' ,
noResultsFor : 'No products found for "{{query}}"' ,
noResultsHint : 'Try changing your query or using different keywords' ,
2026-07-10 13:25:31 +04:00
emptyResultsAria : 'Empty search results' ,
popularCategories : 'Popular categories' ,
recommendedProducts : 'Recommended products' ,
aiSuggestionHint : 'AI suggestion (future)' ,
suggestionType : {
product : 'Product' ,
category : 'Category' ,
brand : 'Brand' ,
collection : 'Collection' ,
seller : 'Seller' ,
'static-page' : 'Page' ,
ai : 'AI' ,
} ,
2026-02-26 23:09:20 +04:00
addToCart : 'Add to cart' ,
loadingMore : 'Loading...' ,
allLoaded : 'All results loaded' ,
emptyState : 'Enter a query to search for products' ,
2026-07-05 01:10:56 +04:00
minLength : 'Enter at least {{count}} characters to search' ,
2026-02-26 23:09:20 +04:00
of : 'of' ,
} ,
category : {
retry : 'Try again' ,
addToCart : 'Add to cart' ,
loadingMore : 'Loading...' ,
allLoaded : 'All products loaded' ,
emptyTitle : 'Oops! Nothing here yet' ,
emptyDesc : 'There are no products in this category yet, but they will appear soon' ,
goHome : 'Go home' ,
loading : 'Loading products...' ,
} ,
2026-07-05 01:36:21 +04:00
catalog : {
title : 'Catalog' ,
breadcrumb : 'Catalog breadcrumb' ,
allCategories : 'All categories' ,
products : 'Products' ,
loading : 'Loading catalog...' ,
loadingProducts : 'Loading products...' ,
errorTitle : 'Catalog is unavailable' ,
error : 'Could not load catalog data. Try again later.' ,
retry : 'Try again' ,
categoryHint : 'Choose a category to continue' ,
productHint : 'Browse products in this category' ,
emptyTitle : 'Nothing here yet' ,
emptyCategories : 'There are no child categories in this section yet.' ,
emptyProducts : 'There are no products in this category yet.' ,
addToCart : 'Add to cart' ,
categoriesCount : '{{count}} categories' ,
productsCount : '{{count}} products' ,
2026-07-09 01:40:22 +04:00
entriesCount : '{{count}} entries' ,
categoryBannerPlaceholder : 'Category banner placeholder for backend-driven media and description.' ,
navigationPlaceholder : 'Navigation layout placeholder prepared for backend/bootstrap-driven rendering.' ,
removeSavedSearch : 'Remove saved search' ,
resetFilters : 'Reset' ,
filtersTitle : 'Filters' ,
2026-07-09 02:57:48 +04:00
from : 'From' ,
to : 'To' ,
2026-07-09 01:40:22 +04:00
minValue : 'Min {{value}}' ,
maxValue : 'Max {{value}}' ,
enabled : 'Enabled' ,
searchPlaceholder : 'Search products, brands, categories' ,
searchSubmit : 'Search' ,
2026-07-09 02:29:12 +04:00
clearSearch : 'Clear' ,
2026-07-09 01:40:22 +04:00
suggestionsTitle : 'Suggestions' ,
2026-07-09 02:29:12 +04:00
popularSearchesTitle : 'Popular searches' ,
2026-07-09 01:40:22 +04:00
recentSearchesTitle : 'Recent searches' ,
searchHistoryTitle : 'Search history' ,
clearHistory : 'Clear' ,
searchNoResultsHint : 'No results found for this query. Try broader keywords.' ,
2026-07-09 02:29:12 +04:00
searchProductsFound : '{{total}} products found' ,
searchResultsSummary : '{{total}} results for "{{query}}"' ,
2026-07-10 15:55:38 +04:00
loadMore : 'Load more' ,
2026-07-09 01:40:22 +04:00
sortBy : 'Sort by' ,
2026-07-09 01:46:32 +04:00
sortRelevance : 'Recommended' ,
2026-07-09 01:40:22 +04:00
sortLatest : 'Newest' ,
sortPriceAsc : 'Price Low -> High' ,
sortPriceDesc : 'Price High -> Low' ,
sortRating : 'Highest Rated' ,
sortPopular : 'Most Popular' ,
sortDiscount : 'Discount' ,
layoutGrid : 'Grid' ,
layoutLargeGrid : 'Large grid' ,
layoutCompactGrid : 'Compact grid' ,
2026-07-10 15:55:38 +04:00
layoutGrid2 : '2 Columns' ,
layoutGrid3 : '3 Columns' ,
layoutGrid4 : '4 Columns' ,
layoutCompact : 'Compact' ,
2026-07-09 01:40:22 +04:00
layoutList : 'List' ,
noResults : 'No results' ,
itemsCount : '{{count}} items' ,
emptyResultsTitle : 'No results found' ,
emptyResultsDescription : 'Try changing filters, sorting, or search keywords.' ,
previousPage : 'Previous' ,
nextPage : 'Next' ,
pageOf : 'Page {{page}} / {{total}}' ,
2026-07-09 01:46:32 +04:00
emptyCategoryTitle : 'This category has no products yet' ,
emptyCategoryMessage : 'Try browsing parent categories or return to the full catalog.' ,
2026-07-10 15:55:38 +04:00
goToParentCategory : 'Go to parent category' ,
2026-07-09 01:46:32 +04:00
browseCategories : 'Browse Categories' ,
2026-07-10 15:55:38 +04:00
offlineTitle : 'You are offline' ,
offlineMessage : 'Reconnect to continue browsing this catalog.' ,
2026-07-09 01:46:32 +04:00
noFilterMatchTitle : 'No products match your selected filters.' ,
noFilterMatchMessage : 'Try broadening price, attributes, or brand filters.' ,
clearFilters : 'Clear Filters' ,
openFilters : 'Open Filters' ,
applyFilters : 'Apply' ,
close : 'Close' ,
filtersDrawerAria : 'Filters drawer' ,
sortSheetAria : 'Sort options' ,
mobileToolbarAria : 'Catalog mobile toolbar' ,
gridCycle : 'Grid' ,
filtersPanelAria : 'Catalog filters' ,
2026-07-09 01:40:22 +04:00
filterPrice : 'Price' ,
filterAvailability : 'Availability' ,
filterInStock : 'In stock' ,
filterLowStock : 'Low stock' ,
filterOutOfStock : 'Out of stock' ,
filterRating : 'Rating' ,
filterStars : '{{count}} stars' ,
filterBrand : 'Brand' ,
filterCategory : 'Category' ,
filterCategoryValue : 'Category {{value}}' ,
filterSubcategory : 'Subcategory' ,
filterDiscount : 'Discount' ,
filterNew : 'New' ,
filterColor : 'Color' ,
filterSize : 'Size' ,
filterAttributes : 'Attributes' ,
2026-07-19 22:04:13 +04:00
favorite : 'Add to favorites' ,
compare : 'Compare' ,
share : 'Share' ,
quickView : 'Quick view' ,
stockHigh : 'In stock' ,
stockMedium : 'Limited stock' ,
stockLow : 'Almost gone' ,
stockOut : 'Out of stock' ,
2026-07-09 01:40:22 +04:00
} ,
productDetails : {
loading : 'Loading product...' ,
errorTitle : 'Product unavailable' ,
retry : 'Try again' ,
missingTitle : 'Product not found' ,
missingDescription : 'This product does not exist or is no longer available.' ,
backToCatalog : 'Back to catalog' ,
tabsAria : 'Product tabs' ,
mediaAria : 'Product media' ,
ratingStarsAria : 'Rating stars' ,
selectRatingAria : 'Select rating' ,
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 : 'stars' ,
2026-07-09 01:40:22 +04:00
reviewsEmpty : 'No reviews yet.' ,
questionsEmpty : 'No questions yet.' ,
askQuestion : 'Ask question' ,
hideQuestionForm : 'Hide question form' ,
questionFormTitle : 'Ask a question' ,
questionFormPlaceholder : 'Ask about size, delivery, compatibility or usage' ,
questionFormAnonymous : 'Ask anonymously' ,
submitQuestion : 'Submit question' ,
reviewFormTitle : 'Leave a review' ,
reviewRatingLabel : 'Rating' ,
reviewTitleLabel : 'Title' ,
reviewTitlePlaceholder : 'Short headline' ,
reviewTextLabel : 'Review' ,
reviewTextPlaceholder : 'Describe your experience' ,
reviewAnonymous : 'Submit anonymously' ,
reviewUploadPlaceholder : 'Photo upload is planned for a future sprint.' ,
2026-07-10 13:10:35 +04:00
reviewRatingRequired : 'Please select a rating.' ,
reviewTextRequired : 'Please add your review text.' ,
reviewSuccess : 'Review submitted successfully.' ,
2026-07-09 01:40:22 +04:00
submitReview : 'Submit review' ,
submitting : 'Submitting...' ,
2026-07-10 13:10:35 +04:00
loadMore : 'Load more' ,
showingOf : 'Showing {{shown}} of {{total}}' ,
questionsSubmissionFuture : 'Question submission can be enabled later without component changes.' ,
specificationsGeneral : 'General' ,
actionsAria : 'Product actions' ,
buyNow : 'Buy now' ,
wishlist : 'Wishlist' ,
compare : 'Compare' ,
share : 'Share' ,
notifyMe : 'Notify me' ,
zoom : 'Zoom' ,
fullscreen : 'Fullscreen' ,
pdfDocument : 'Product PDF document' ,
manualDocument : 'Product manual' ,
warrantyDocument : 'Warranty document' ,
openDocument : 'Open document' ,
2026-07-09 01:40:22 +04:00
specificationsEmpty : 'No specifications provided yet.' ,
warrantyTitle : 'Warranty and returns' ,
warrantyItem1 : 'Warranty terms are provided by the seller and local law.' ,
warrantyItem2 : 'Return eligibility depends on item condition and category.' ,
warrantyItem3 : 'Detailed return instructions are available after purchase.' ,
verifiedPurchase : 'Verified purchase' ,
officialSeller : 'Official seller' ,
acceptedAnswer : 'Accepted answer' ,
like : 'Like' ,
dislike : 'Dislike' ,
reviewsCountLabel : '{{count}} reviews' ,
previous : 'Previous' ,
next : 'Next' ,
pageOf : 'Page {{page}} / {{total}}' ,
2026-07-05 01:36:21 +04:00
} ,
2026-02-26 23:09:20 +04:00
subcategories : {
loading : 'Loading subcategories...' ,
retry : 'Try again' ,
emptyTitle : 'Oops! No subcategories yet' ,
emptyDesc : 'There are no subcategories in this section yet, but they will appear soon' ,
goHome : 'Go home' ,
2026-03-24 00:09:11 +04:00
itemsInCategory : 'Items in this category' ,
2026-07-05 01:09:55 +04:00
childrenCount : '{{count}} categories' ,
productsCount : '{{count}} products' ,
includesProducts : 'Includes products' ,
2026-02-26 23:09:20 +04:00
} ,
itemDetail : {
loading : 'Loading...' ,
loadingDexar : 'Loading product...' ,
back : 'Go back' ,
backHome : 'Back to home' ,
noImage : 'No image' ,
stock : 'Availability:' ,
inStock : 'In stock' ,
lowStock : 'Few left' ,
lastItems : 'Last items' ,
mediumStock : 'Running low' ,
addToCart : 'Add to cart' ,
description : 'Description' ,
2026-02-28 16:13:14 +04:00
specifications : 'Specifications' ,
2026-02-26 23:09:20 +04:00
reviews : 'Reviews' ,
yourReview : 'Your review' ,
leaveReview : 'Leave a review' ,
rating : 'Rating:' ,
reviewPlaceholder : 'Share your experience with this product...' ,
reviewPlaceholderDexar : 'Share your thoughts on this product...' ,
anonymous : 'Anonymous' ,
submitting : 'Submitting...' ,
submit : 'Submit' ,
reviewSuccess : 'Thank you for your review!' ,
reviewError : 'Submission failed. Please try later.' ,
defaultUser : 'User' ,
defaultUserDexar : 'Anonymous' ,
noReviews : 'No reviews yet. Be the first!' ,
qna : 'Questions & Answers' ,
photo : 'Photo' ,
reviewsCount : 'reviews' ,
today : 'Today' ,
yesterday : 'Yesterday' ,
daysAgo : 'd. ago' ,
weeksAgo : 'w. ago' ,
2026-03-24 00:09:11 +04:00
colour : 'Colour' ,
size : 'Size' ,
2026-07-05 01:07:53 +04:00
relatedProducts : 'Related products' ,
2026-02-26 23:09:20 +04:00
} ,
app : {
connecting : 'Connecting to server...' ,
serverUnavailable : 'Server unavailable' ,
serverError : 'Could not connect to the server. Please check your internet connection.' ,
retryConnection : 'Retry' ,
pageTitle : 'Marketplace of goods and services' ,
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 : 'Skip to main content' ,
2026-02-26 23:09:20 +04:00
} ,
2026-07-09 02:29:12 +04:00
platform : {
loadingPage : 'Loading platform page...' ,
emptyConfig : 'No page configuration found.' ,
} ,
backoffice : {
title : 'Backoffice Sandbox' ,
subtitle : 'Business data management domain (mocked for platform foundation).' ,
loading : 'Loading backoffice data...' ,
products : 'Products' ,
categories : 'Categories' ,
otherDomains : 'Other Domains' ,
sku : 'SKU' ,
titleColumn : 'Title' ,
price : 'Price' ,
status : 'Status' ,
itemsCount : 'items' ,
orders : 'Orders' ,
customers : 'Customers' ,
inventory : 'Inventory' ,
media : 'Media' ,
settings : 'Settings' ,
notAvailable : 'n/a' ,
} ,
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 : 'Marketplace Builder' ,
subtitle : 'Build your marketplace step by step.' ,
2026-07-10 13:43:53 +04:00
general : 'General' ,
2026-07-09 02:29:12 +04:00
branding : 'Branding' ,
2026-07-10 13:43:53 +04:00
theme : 'Theme' ,
header : 'Header' ,
footer : 'Footer' ,
homepage : 'Homepage' ,
widgets : 'Widgets' ,
2026-07-10 13:52:01 +04:00
staticPages : 'Static Pages' ,
2026-07-10 13:43:53 +04:00
marketplaceFeatures : 'Marketplace Features' ,
preview : 'Preview' ,
2026-07-09 02:29:12 +04:00
brandName : 'Brand Name' ,
2026-07-10 13:43:53 +04:00
marketplaceName : 'Marketplace Name' ,
domain : 'Domain' ,
descriptionLabel : 'Description' ,
defaultLanguage : 'Default Language' ,
supportedLanguages : 'Supported Languages' ,
logo : 'Logo' ,
smallLogo : 'Small Logo' ,
favicon : 'Favicon' ,
2026-07-17 15:22:45 +04:00
socialImage : 'Social Share Image' ,
gallery : 'Gallery' ,
addGalleryImage : 'Add image' ,
2026-07-17 15:29:55 +04:00
headerLayout : 'Header Layout' ,
headerLayoutDefault : 'Default' ,
headerLayoutCentered : 'Centered' ,
headerSticky : 'Sticky Header' ,
2026-07-10 13:43:53 +04:00
marketplaceTitle : 'Marketplace Title' ,
primaryColor : 'Primary Color' ,
secondaryColor : 'Secondary Color' ,
backgroundColor : 'Background' ,
surfaceColor : 'Surface' ,
textColor : 'Text' ,
successColor : 'Success' ,
warningColor : 'Warning' ,
dangerColor : 'Danger' ,
showLogo : 'Logo' ,
showSearch : 'Search' ,
showCategories : 'Categories' ,
showLanguages : 'Languages' ,
showCart : 'Cart' ,
showProfile : 'Profile' ,
showWishlist : 'Wishlist' ,
showCompare : 'Compare' ,
showRegion : 'Region' ,
companyName : 'Company Information' ,
address : 'Address' ,
phone : 'Phone' ,
email : 'Email' ,
copyright : 'Copyright' ,
paymentIcons : 'Payment Icons' ,
socialLinks : 'Social Links' ,
2026-07-16 02:06:26 +04:00
footerLogo : 'Footer Logo' ,
addPaymentIcon : 'Add Payment Icon' ,
removePaymentIcon : 'Remove' ,
iconAltLabel : 'Icon Label' ,
addSocialLink : 'Add Social Link' ,
removeSocialLink : 'Remove' ,
socialLinkLabel : 'Platform' ,
socialLinkUrl : 'URL' ,
invalidUrl : 'Enter a valid URL starting with http:// or https://.' ,
2026-07-10 13:52:01 +04:00
createPage : 'Create Page' ,
deletePage : 'Delete Page' ,
pageId : 'Page ID' ,
slug : 'Slug' ,
iconLabel : 'Icon' ,
showInFooter : 'Show In Footer' ,
showInHeader : 'Show In Header' ,
showInSitemap : 'Show In Sitemap' ,
requiresAuthentication : 'Requires Authentication' ,
footerGroup : 'Footer Group' ,
orderLabel : 'Order' ,
translationTitle : 'Translation Title' ,
htmlPreview : 'HTML' ,
2026-07-15 04:11:18 +04:00
seoSection : 'SEO' ,
seoTitle : 'SEO Title' ,
seoDescription : 'SEO Description' ,
seoKeywords : 'Keywords' ,
seoCanonical : 'Canonical URL' ,
seoOgTitle : 'OG Title' ,
seoOgDescription : 'OG Description' ,
seoOgImage : 'OG Image' ,
2026-07-10 13:43:53 +04:00
visible : 'Visible' ,
layoutLabel : 'Layout' ,
columns : 'Columns' ,
height : 'Height' ,
overlay : 'Overlay' ,
autoplay : 'Autoplay' ,
cardsPerRow : 'Cards Per Row' ,
filtersLabel : 'Filters' ,
showBadges : 'Show Badges' ,
showRating : 'Show Rating' ,
showPrice : 'Show Price' ,
widgetJson : 'Widget JSON' ,
reviews : 'Reviews' ,
questions : 'Questions' ,
comments : 'Comments' ,
recommendations : 'Recommendations' ,
recentlyViewed : 'Recently Viewed' ,
searchSuggestions : 'Search Suggestions' ,
searchHistory : 'Search History' ,
livePreview : 'Live Preview' ,
2026-07-17 09:00:47 +04:00
previewChangesTitle : 'Changes since last publish' ,
previewNoIssues : 'No validation issues.' ,
previewNoChanges : 'No changes since the last publish.' ,
previewChangeField : 'Field' ,
previewChangeBefore : 'Before' ,
previewChangeAfter : 'After' ,
2026-07-13 08:10:00 +04:00
languagesTab : 'Languages' ,
addLanguage : 'Add Language' ,
removeLanguage : 'Remove' ,
setDefaultLanguage : 'Set as Default' ,
defaultLanguageLabel : 'Default' ,
2026-07-13 08:57:42 +04:00
navigationTab : 'Navigation' ,
navigationHeader : 'Header Navigation' ,
navigationFooter : 'Footer Navigation' ,
navigationFooterGrouped : 'Footer navigation uses grouped columns and is not editable here yet — edit via the Footer tab.' ,
addLink : 'Add Link' ,
2026-07-17 10:18:08 +04:00
insertPageLink : 'Insert page link' ,
linkedToPage : 'Linked to page' ,
2026-07-13 08:57:42 +04:00
removeLink : 'Remove' ,
linkLabel : 'Label' ,
linkUrl : 'URL' ,
2026-07-10 13:43:53 +04:00
exportBootstrap : 'Export Bootstrap' ,
importBootstrap : 'Import Bootstrap' ,
exportedBootstrap : 'Exported Bootstrap' ,
importSource : 'Import Source' ,
importError : 'Import failed. Invalid bootstrap JSON.' ,
2026-07-09 02:29:12 +04:00
featureFlags : 'Feature Flags' ,
2026-07-13 10:51:05 +04:00
validationMissingLogo : 'Branding is missing a logo.' ,
validationNoLanguages : 'No languages are configured.' ,
2026-07-17 19:00:17 +04:00
validationDefaultLocaleNotSupported : 'The default language is not in the supported languages list.' ,
2026-07-13 10:51:05 +04:00
validationInvalidUrl : 'The marketplace URL is invalid.' ,
validationDuplicateSlugs : 'Two or more static pages share the same slug.' ,
validationEmptyHomepage : 'The homepage has no sections.' ,
validationMissingWidget : 'A homepage section has a widget with no type.' ,
validationDuplicateNavLinks : 'Two or more header navigation links are duplicates.' ,
validationInvalidColors : 'One or more theme colors are not valid hex colors.' ,
2026-07-14 12:21:33 +04:00
validationMissingTranslations : 'Some content is missing translations for a supported language.' ,
validationInvalidLayouts : 'One or more layouts reference an unknown layout type.' ,
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 : 'The configuration is not valid JSON.' ,
validationInvalidCss : 'A static page contains invalid CSS.' ,
validationDuplicateRoutes : 'Two or more pages share the same route.' ,
validationInvalidWidgetConfig : 'A widget is missing a required field (id, type, version, or props).' ,
2026-07-17 16:57:43 +04:00
validationInvalidContactEmail : 'The company contact email is not a valid email address.' ,
validationInvalidSocialLinkUrl : 'One or more footer social links have an invalid URL.' ,
validationIncompletePaymentIcon : 'A footer payment icon is missing its image or alt text.' ,
2026-07-17 02:13:34 +04:00
undo : 'Undo' ,
redo : 'Redo' ,
2026-07-13 15:00:03 +04:00
statusDraft : 'Draft' ,
statusPublished : 'Published' ,
unsavedChanges : 'Unsaved changes' ,
save : 'Save' ,
publish : 'Publish' ,
2026-07-13 15:57:54 +04:00
confirmLeaveUnsaved : 'You have unsaved changes. Leave anyway?' ,
promptLinkUrl : 'URL' ,
promptImageUrl : 'Image URL' ,
2026-07-17 10:00:33 +04:00
promptEmbedUrl : 'Embed URL' ,
htmlEditorInvalidHtml : 'This HTML has an unclosed or mismatched tag. Fix it before switching back to the visual editor.' ,
2026-07-13 15:57:54 +04:00
htmlEditorCode : 'Code' ,
htmlEditorPreview : 'Preview' ,
2026-07-14 09:50:03 +04:00
lastSaved : 'Last saved' ,
draftRestored : 'A local draft was restored from your last session.' ,
dismiss : 'Dismiss' ,
resetDraft : 'Reset draft' ,
resetSection : 'Reset section' ,
confirmResetDraft : 'This discards all unpublished changes and restores the last published configuration. Continue?' ,
confirmResetSection : 'This discards unpublished changes in this section only. Continue?' ,
2026-07-14 16:05:09 +04:00
marketplaceNameDesc : 'The name shown to shoppers across the storefront and browser tab.' ,
domainDesc : 'The domain shoppers use to reach this marketplace. Changing it does not move DNS.' ,
descriptionFieldDesc : 'A short summary used for search engines and social link previews.' ,
defaultLanguageDesc : 'The language shown when a shopper has no saved language preference.' ,
supportedLanguagesDesc : 'Comma-separated language codes shoppers can switch to (e.g. en, ru, hy).' ,
logoDesc : 'Full logo image URL, shown in the header on desktop.' ,
smallLogoDesc : 'Compact logo image URL, used where space is limited (e.g. mobile header).' ,
faviconDesc : 'Browser tab icon image URL. Should be a small square image.' ,
2026-07-17 15:22:45 +04:00
socialImageDesc : 'Default image shown when the marketplace is shared on social media (Open Graph).' ,
galleryDesc : 'Extra brand images available for future use across the storefront.' ,
2026-07-17 15:29:55 +04:00
headerLayoutDesc : 'How the header content is arranged: default (logo left, nav spread) or centered.' ,
headerStickyDesc : 'Keep the header pinned to the top of the viewport while scrolling.' ,
2026-07-14 16:05:09 +04:00
marketplaceTitleDesc : 'The page title used by search engines and browser tabs.' ,
primaryColorDesc : 'The main brand color, used on primary buttons and highlights. Must be a valid hex color.' ,
secondaryColorDesc : 'A supporting brand color used for secondary UI elements. Must be a valid hex color.' ,
backgroundColorDesc : 'The default page background color. Must be a valid hex color.' ,
surfaceColorDesc : 'The background color for cards and raised surfaces. Must be a valid hex color.' ,
textColorDesc : 'The default body text color. Must be a valid hex color.' ,
successColorDesc : 'Color used for success messages and positive states. Must be a valid hex color.' ,
warningColorDesc : 'Color used for warning messages and caution states. Must be a valid hex color.' ,
dangerColorDesc : 'Color used for errors and destructive actions. Must be a valid hex color.' ,
themeModeLabel : 'Color mode' ,
themeModeDesc : 'Controls whether the storefront renders in light, dark, or the shopper\'s system preference.' ,
themeModeLight : 'Light' ,
themeModeLightDesc : 'Always use the light color scheme.' ,
themeModeDark : 'Dark' ,
themeModeDarkDesc : 'Always use the dark color scheme.' ,
themeModeSystem : 'System' ,
themeModeSystemDesc : 'Follow the shopper\'s device/browser color scheme preference.' ,
siteLayoutLabel : 'Site layout' ,
siteLayoutDesc : 'The overall page chrome mode used across the storefront.' ,
siteLayoutDefault : 'Default' ,
siteLayoutDefaultDesc : 'Standard layout with a top navigation bar.' ,
siteLayoutSidebarLeft : 'Sidebar (left)' ,
siteLayoutSidebarLeftDesc : 'Adds a left-hand sidebar, typically for category navigation.' ,
siteLayoutCarouselHome : 'Carousel home' ,
siteLayoutCarouselHomeDesc : 'Homepage leads with a full-width carousel/hero.' ,
siteLayoutMinimal : 'Minimal' ,
siteLayoutMinimalDesc : 'Stripped-down chrome with minimal navigation elements.' ,
showLogoDesc : 'Show the marketplace logo in the header.' ,
showSearchDesc : 'Show the search bar in the header.' ,
showCategoriesDesc : 'Show the categories menu entry point in the header.' ,
showLanguagesDesc : 'Show the language switcher in the header.' ,
showCartDesc : 'Show the cart icon/link in the header.' ,
showProfileDesc : 'Show the account/profile entry point in the header.' ,
showWishlistDesc : 'Show the wishlist entry point in the header.' ,
showCompareDesc : 'Show the compare-products entry point in the header.' ,
showRegionDesc : 'Show the region/country selector in the header.' ,
companyNameDesc : 'Legal company name shown in the footer and static pages.' ,
addressDesc : 'Company street address shown in the footer.' ,
phoneDesc : 'Contact phone number shown in the footer.' ,
emailDesc : 'Contact email address shown in the footer.' ,
copyrightDesc : 'Copyright line shown at the bottom of every page.' ,
paymentIconsDesc : 'One payment icon entry per line (image URL and label) shown in the footer.' ,
socialLinksDesc : 'One social link entry per line (platform and URL) shown in the footer.' ,
2026-07-16 02:06:26 +04:00
footerLogoDesc : 'Logo shown in the footer, if different from the header logo.' ,
iconAltLabelDesc : 'Alt text describing the payment icon for accessibility.' ,
socialLinkUrlDesc : 'Full URL to the social media profile, must start with http:// or https://.' ,
2026-07-14 16:05:09 +04:00
staticPagesFieldDesc : 'Static pages (about, terms, privacy, etc.) linked from the footer.' ,
2026-07-19 13:58:57 +04:00
additionalPhones : 'Extra phone numbers' ,
additionalPhonesDesc : 'Add more numbers if you support customers in different countries.' ,
addPhone : 'Add phone number' ,
removePhone : 'Remove phone number' ,
additionalEmails : 'Extra email addresses' ,
additionalEmailsDesc : 'Add more addresses for different regions or departments.' ,
addEmail : 'Add email address' ,
removeEmail : 'Remove email address' ,
footerColumns : 'Footer columns' ,
footerColumnsDesc : 'Group links into columns, like a real footer. Drag columns and links to reorder them.' ,
footerColumnTitlePlaceholder : 'Column title, e.g. Company' ,
footerLinkLabelPlaceholder : 'Link text' ,
footerLinkExistingPage : 'Existing page' ,
footerLinkCustomUrl : 'Custom URL' ,
addColumn : 'Add column' ,
removeColumn : 'Remove column' ,
addColumnLink : 'Add link' ,
removeColumnLink : 'Remove link' ,
2026-07-14 16:05:09 +04:00
sectionVisibleDesc : 'Whether this homepage section is shown to shoppers.' ,
layoutStrategyLabel : 'Layout strategy' ,
layoutStrategyDesc : 'How widgets inside this section are arranged.' ,
layoutStrategyStack : 'Stack' ,
layoutStrategyStackDesc : 'Widgets stack vertically, one after another.' ,
layoutStrategyGrid : 'Grid' ,
layoutStrategyGridDesc : 'Widgets arrange in a multi-column grid.' ,
layoutStrategyHero : 'Hero' ,
layoutStrategyHeroDesc : 'A single large, full-width promotional layout.' ,
layoutStrategyCarousel : 'Carousel' ,
layoutStrategyCarouselDesc : 'Widgets scroll horizontally as a carousel.' ,
layoutStrategySplit : 'Split' ,
layoutStrategySplitDesc : 'Content is split into two side-by-side panes.' ,
sectionColumnsDesc : 'Number of columns to use when the layout strategy supports columns.' ,
widgetLayoutDesc : 'Free-text layout variant name understood by this widget (e.g. "full-bleed", "boxed").' ,
widgetHeightDesc : 'Preferred height for this widget (e.g. "480px" or "60vh").' ,
widgetOverlayDesc : 'Show a dark overlay behind hero text for readability.' ,
widgetAutoplayDesc : 'Automatically rotate hero slides without shopper interaction.' ,
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 : 'Full width (edge to edge)' ,
heroLayoutBoxed : 'Boxed (within page margins)' ,
heroHeightCompact : 'Compact' ,
heroHeightMedium : 'Medium' ,
heroHeightTall : 'Tall' ,
heroHeightFullScreen : 'Full screen' ,
heroSlides : 'Slides' ,
heroSlidesHint : 'Add more slides to turn this into a slideshow. The fields above are slide 1. Autoplay and dots only appear once you have more than one slide.' ,
heroSlideTitlePlaceholder : 'Slide title' ,
heroSlideSubtitlePlaceholder : 'Slide subtitle' ,
addSlide : 'Add slide' ,
removeSlide : 'Remove slide' ,
2026-07-14 16:05:09 +04:00
widgetColumnsDesc : 'Number of category tiles per row.' ,
widgetCardsPerRowDesc : 'Number of product cards shown per row.' ,
widgetFiltersDesc : 'Show filter controls alongside the product collection.' ,
widgetShowBadgesDesc : 'Show badges such as "New" or "Sale" on product cards.' ,
widgetShowRatingDesc : 'Show the star rating on product cards.' ,
widgetShowPriceDesc : 'Show the price on product cards.' ,
widgetJsonDesc : 'Raw widget properties as JSON. Used when no dedicated editor exists for this widget type.' ,
2026-07-17 18:14:58 +04:00
widgetJsonInvalid : 'Invalid JSON - the last valid version is still saved.' ,
2026-07-14 16:05:09 +04:00
wishlistFeatureDesc : 'Let shoppers save products to a wishlist.' ,
compareFeatureDesc : 'Let shoppers compare multiple products side by side.' ,
reviewsFeatureDesc : 'Let shoppers leave and read product reviews.' ,
questionsFeatureDesc : 'Let shoppers ask and read product questions and answers.' ,
commentsFeatureDesc : 'Enable general comments on marketplace content.' ,
recommendationsFeatureDesc : 'Show recommended-product blocks across the storefront.' ,
recentlyViewedFeatureDesc : 'Show a "recently viewed" product list to shoppers.' ,
searchSuggestionsDesc : 'Show live search suggestions as shoppers type.' ,
searchHistoryDesc : 'Remember and show a shopper\'s recent searches.' ,
catalogNavigationModeLabel : 'Catalog navigation mode' ,
catalogNavigationModeDesc : 'How shoppers navigate categories in the catalog.' ,
catalogNavDefault : 'Default' ,
catalogNavDefaultDesc : 'Standard breadcrumb-driven category navigation.' ,
catalogNavLeftCategory : 'Left category navigation' ,
catalogNavLeftCategoryDesc : 'Persistent category tree in a left-hand sidebar.' ,
catalogNavMegaCategory : 'Mega category layout' ,
catalogNavMegaCategoryDesc : 'Expanded dropdown showing subcategories and featured items.' ,
catalogNavTopCarousel : 'Top category carousel' ,
catalogNavTopCarouselDesc : 'Horizontally scrollable category chips above the catalog grid.' ,
newLanguageDesc : 'ISO language code to add as a supported storefront language (e.g. de, fr).' ,
2026-07-17 18:31:01 +04:00
languageAlreadyAdded : 'This language is already supported.' ,
2026-07-14 16:05:09 +04:00
languagesTabDesc : 'Languages available to shoppers. The default language is used as a fallback everywhere.' ,
linkLabelDesc : 'Text shown for this navigation link.' ,
linkUrlDesc : 'Path or URL this navigation link points to.' ,
linkVisibleDesc : 'Whether this navigation link is shown to shoppers.' ,
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 : 'Marketplace Builder' ,
2026-07-19 08:25:29 +04:00
backToDashboard : 'Back to dashboard' ,
2026-07-19 08:53:10 +04:00
languagesSummaryDesc : 'Languages your marketplace is available in. The first one is what customers see by default.' ,
manageLanguages : 'Manage languages' ,
2026-07-19 08:48:22 +04:00
htmlToolBold : 'Bold' ,
htmlToolItalic : 'Italic' ,
htmlToolUnderline : 'Underline' ,
htmlToolHeading : 'Heading' ,
htmlToolSubheading : 'Subheading' ,
htmlToolBulletList : 'Bulleted list' ,
htmlToolNumberedList : 'Numbered list' ,
htmlToolLink : 'Insert link' ,
htmlToolImage : 'Insert image' ,
htmlToolTable : 'Insert table' ,
htmlToolDivider : 'Divider line' ,
htmlToolCodeBlock : 'Code block' ,
htmlToolEmbed : 'Embed video' ,
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 : 'Marketplace Builder' ,
statusComplete : 'Complete' ,
statusInProgress : 'In progress' ,
statusNotStarted : 'Not started' ,
statusUnknown : 'Not tracked yet' ,
draftBadge : 'Draft' ,
publishedBadge : 'Published' ,
modifiedBadge : 'Unsaved changes' ,
helpToggleShow : 'What is this?' ,
helpToggleHide : 'Hide help' ,
helpWhatIsThis : 'What is this' ,
helpWhySkip : 'Why configure it' ,
helpWhereVisible : 'Where shoppers see it' ,
helpWhatIfSkip : "What happens if you skip it" ,
helpWhenReturn : 'When to come back to this' ,
openSidebar : 'Open sections menu' ,
closeSidebar : 'Close sections menu' ,
overviewTitle : 'Marketplace Builder' ,
overviewSubtitle : 'Build your marketplace step by step' ,
overviewReadinessLabel : 'Your marketplace is {{percent}}% configured' ,
overviewReadinessHint : 'Based on the required fields you have filled in so far.' ,
overviewNextStepLabel : 'Recommended next step' ,
overviewNextStepFallback : 'All required steps are done - you are ready to publish.' ,
overviewQuickLinksTitle : 'Quick links' ,
overviewSectionsTitle : 'Builder sections' ,
overviewOpenSection : 'Open section' ,
overviewReadinessTitle : 'Marketplace readiness' ,
readinessLogoUploaded : 'Logo uploaded' ,
readinessHomepageConfigured : 'Homepage configured' ,
readinessThemeConfigured : 'Theme configured' ,
readinessLanguagesConfigured : 'Languages configured' ,
readinessContentPagesAdded : 'Info pages added' ,
readinessPreviewReviewed : 'Preview reviewed' ,
readinessPublished : 'Marketplace published' ,
readinessCategoriesExist : 'Categories exist' ,
readinessProductsExist : 'Products exist' ,
groupMarketplaceLabel : 'Marketplace' ,
groupMarketplaceDescription : 'Name, address, and the core details of your marketplace.' ,
groupMarketplacePurpose : 'The basic information that defines your marketplace: name, domain, and default language.' ,
groupMarketplaceWhere : 'The name and address show up in the browser tab, search results, and every storefront page.' ,
groupMarketplaceSkip : "Without a name and address, your marketplace won't feel finished to shoppers." ,
groupBrandingLabel : 'Branding & Design' ,
groupBrandingDescription : 'Logo, colors, header and footer - your store\'s visual identity.' ,
groupBrandingPurpose : "Set how your marketplace looks: logo, color palette, and the header/footer chrome." ,
groupBrandingWhere : 'Changes show up on every page a shopper sees.' ,
groupBrandingSkip : "Your marketplace will use default styling that doesn't reflect your brand." ,
groupHomepageLabel : 'Homepage' ,
groupHomepageDescription : 'The banners, showcases, and widgets shoppers see first.' ,
groupHomepagePurpose : 'Build your homepage from blocks: a hero banner, featured categories and products, promotions.' ,
groupHomepageWhere : "It's the first page a shopper sees when they open your marketplace." ,
groupHomepageSkip : 'Your homepage will stay empty or use a default layout.' ,
groupContentLabel : 'Content' ,
groupContentDescription : 'About us, contacts, delivery, returns, and other info pages.' ,
groupContentPurpose : 'Add the pages shoppers trust: about us, contacts, delivery and return terms.' ,
groupContentWhere : "Links to these pages usually appear in the site footer." ,
groupContentSkip : "Shoppers won't find answers about delivery, returns, or how to contact you - that hurts trust." ,
groupLanguagesLabel : 'Languages' ,
groupLanguagesDescription : 'Which languages your marketplace works in.' ,
groupLanguagesPurpose : 'Pick a default language and add more for shoppers in other regions.' ,
groupLanguagesWhere : 'The language switcher is visible in the header on every page.' ,
groupLanguagesSkip : 'Your marketplace will only be available in the default language.' ,
groupFeaturesLabel : 'Marketplace Features' ,
groupFeaturesDescription : 'Wishlist, compare, reviews, guest checkout, and more.' ,
groupFeaturesPurpose : 'Turn shopper-facing features on or off: wishlist, product comparison, guest checkout.' ,
groupFeaturesWhere : 'Affects the catalog, product, and checkout pages.' ,
groupFeaturesSkip : 'Your marketplace will use the default feature set.' ,
groupNavigationLabel : 'Navigation & Search' ,
groupNavigationDescription : "The site menu and how shoppers find products." ,
groupNavigationPurpose : 'Configure the menu items and how catalog navigation is structured.' ,
groupNavigationWhere : 'Visible in the site header on every page.' ,
groupNavigationSkip : 'Shoppers will use the default navigation.' ,
groupPreviewLabel : 'Preview' ,
groupPreviewDescription : 'See how your marketplace looks on desktop, tablet, and phone.' ,
groupPreviewPurpose : 'Check your marketplace through a shopper\'s eyes before publishing - across screen sizes.' ,
groupPreviewWhere : "This is a preview - shoppers never see it." ,
groupPreviewSkip : 'You can publish your changes without reviewing them first.' ,
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 : 'Brand identity' ,
brandOverviewSubtitle : 'The logo, colors, and fonts shoppers see on every page.' ,
brandOverviewComplete : 'Your brand is fully set up.' ,
brandLastModified : 'Last modified' ,
brandFaviconUploaded : 'Favicon uploaded' ,
brandColorsSelected : 'Brand colors selected' ,
brandTypographyConfigured : 'Typography configured' ,
brandSocialImageUploaded : 'Social share image uploaded' ,
brandAccessibilityPassed : 'Text contrast looks good' ,
brandColorsPreviewTitle : 'Marketplace colors' ,
brandTypographyPreviewTitle : 'Typography' ,
brandSocialPreviewTitle : 'How this looks when shared' ,
brandTypeSampleHeading : 'Sample heading' ,
brandTypeSampleBody : 'Sample body text the way shoppers will see it.' ,
brandContrastWarning : 'This text is hard to read against the background - consider higher-contrast colors. This will not block publishing.' ,
brandSocialEmpty : "No social share image yet - shared links will show a blank card until you add one." ,
brandAccentColor : 'Accent' ,
brandBorderColor : 'Borders' ,
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 : 'Homepage' ,
homepageOverviewSubtitle : "What your marketplace's homepage is made of." ,
homepageOverviewComplete : 'Your homepage is fully set up.' ,
homepageActiveSections : 'Active sections' ,
homepageDisabledSections : 'Hidden sections' ,
homepageHealthHero : 'Hero banner added' ,
homepageHealthCategories : 'Featured categories added' ,
homepageHealthProducts : 'Featured products added' ,
homepageHealthPromotion : 'Promotion block added' ,
homepageHealthNewsletter : 'Newsletter signup added' ,
homepageHealthAnySections : 'The page has at least one section' ,
widgetTypeHero : 'Hero banner' ,
widgetTypeCategories : 'Featured categories' ,
widgetTypeProducts : 'Featured products' ,
widgetHidden : 'Hidden' ,
widgetVisible : 'Show' ,
widgetMoveUp : 'Move up' ,
widgetMoveDown : 'Move down' ,
widgetDuplicate : 'Duplicate' ,
widgetRemove : 'Remove' ,
widgetRemoveConfirm : 'Remove this section from the homepage?' ,
widgetAdvancedSettings : 'Advanced settings' ,
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 : 'No widgets yet' ,
widgetsEmptyDesc : 'Add a block to your homepage in the Homepage tab and its widget settings will appear here.' ,
homepageEmptyTitle : 'No homepage configured' ,
homepageEmptyDesc : 'Your marketplace does not have a homepage set up yet. Contact support to get one created.' ,
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 : 'These are the blocks customers see on your homepage, top to bottom. Drag the handle to reorder.' ,
addBlockHint : 'Add a block to your homepage:' ,
dragToReorder : 'Drag to reorder' ,
blockRemoveConfirm : 'Remove this block from the homepage?' ,
blockHero : 'Hero banner' ,
blockHeroDesc : 'The large welcome banner at the top of your homepage, with a title and call-to-action button.' ,
blockCategories : 'Categories' ,
blockCategoriesDesc : 'A grid of category tiles so customers can browse by department.' ,
blockFeaturedProducts : 'Featured products' ,
blockFeaturedProductsDesc : 'A grid of hand-picked or best-selling products.' ,
blockProductCarousel : 'Product carousel' ,
blockProductCarouselDesc : 'A horizontally scrolling row of products, with arrows to browse more.' ,
blockRecentlyViewed : 'Recently viewed' ,
blockRecentlyViewedDesc : 'Shows each customer the products they looked at recently.' ,
blockBanner : 'Promo banner' ,
blockBannerDesc : 'A single image with a headline and button, for sales or announcements.' ,
blockPartners : 'Partner logos' ,
blockPartnersDesc : 'A row of brand or partner logos for trust and credibility.' ,
blockCustomHtml : 'Custom block' ,
blockCustomHtmlDesc : 'Free-form HTML for anything the other blocks do not cover.' ,
2026-07-09 02:29:12 +04:00
} ,
2026-07-14 12:21:33 +04:00
dashboard : {
title : 'Dashboard' ,
subtitle : 'Overview of your marketplace' ,
cardMarketplaceStatus : 'Marketplace Status' ,
cardProjectName : 'Project Name' ,
cardCurrentTheme : 'Current Theme' ,
cardLanguages : 'Languages' ,
cardCategoriesCount : 'Categories' ,
cardProductsCount : 'Products' ,
cardOrders : 'Orders' ,
cardRevenue : 'Revenue' ,
cardLastPublish : 'Last Publish' ,
cardLastDraftSave : 'Last Draft Save' ,
cardBootstrapVersion : 'Bootstrap Version' ,
cardActiveLayout : 'Active Layout' ,
cardEnabledWidgets : 'Enabled Widgets' ,
stateLoading : 'Loading...' ,
stateEmpty : 'No data yet' ,
stateError : 'Could not load this card' ,
statePendingBackend : 'Awaiting backend integration' ,
never : 'Never' ,
quickActionsTitle : 'Quick Actions' ,
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 : 'Marketplace Builder' ,
2026-07-14 12:21:33 +04:00
actionCategories : 'Categories' ,
actionProducts : 'Products' ,
actionStaticPages : 'Static Pages' ,
actionTransactions : 'Transactions' ,
actionOrders : 'Orders' ,
actionMediaLibrary : 'Media Library' ,
2026-07-15 20:25:12 +04:00
actionUsers : 'Users & Permissions' ,
actionMonitoring : 'Monitoring' ,
actionAnalytics : 'Analytics' ,
2026-07-14 12:21:33 +04:00
actionPreviewMarketplace : 'Preview Marketplace' ,
activityTitle : 'Recent Activity' ,
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 : 'No activity yet' ,
2026-07-14 12:21:33 +04:00
activityDraftSaved : 'Draft saved' ,
activityPublished : 'Published' ,
healthTitle : 'System Health' ,
healthAllClear : 'All checks passed' ,
healthBootstrapValid : 'Bootstrap valid' ,
healthConfigurationValid : 'Configuration valid' ,
healthMissingTranslations : 'Missing translations' ,
healthInvalidColors : 'Invalid colors' ,
healthInvalidWidgetReferences : 'Invalid widget references' ,
healthInvalidLayouts : 'Invalid layouts' ,
comingSoonTitle : 'Coming soon' ,
comingSoonDescription : 'This section is not built yet. Check back in a future update.' ,
backToDashboard : 'Back to dashboard' ,
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 : 'Welcome back' ,
welcomeFallbackTenant : 'Your marketplace' ,
envProduction : 'Production' ,
envDevelopment : 'Development' ,
factCurrentUser : 'Current user' ,
factTenant : 'Store' ,
quickActionsDescription : 'Your most common tasks - start here' ,
actionAddProduct : 'Add product' ,
actionAddProductDescription : 'Create a new product listing' ,
actionCreateCategory : 'Create category' ,
actionCreateCategoryDescription : 'Add a category to the catalog' ,
actionEditProjectDescription : 'Open the marketplace builder' ,
actionEditHomepage : 'Edit homepage' ,
actionEditHomepageDescription : 'Configure the homepage widgets' ,
actionMediaLibraryDescription : 'Upload and organize files' ,
actionOrdersDescription : 'Review recent orders' ,
draftStatusTitle : 'Draft status' ,
draftStatusHasChanges : 'There are unpublished changes waiting to go live.' ,
draftStatusAllPublished : 'Everything published. No draft in progress.' ,
draftStatusMoreFields : '+{{count}} more' ,
draftOpenBuilder : 'Open builder' ,
draftPublish : 'Publish' ,
draftDiscard : 'Discard draft' ,
healthProductsCount : 'Products' ,
healthCategoriesCount : 'Categories' ,
healthDraftExists : 'Draft' ,
healthImagesWithoutAlt : 'Images missing alt text' ,
healthStaticPagesUnpublished : 'Unpublished static pages' ,
healthHomepageConfigured : 'Homepage configured' ,
healthThemeConfigured : 'Theme configured' ,
statusHealthy : 'Healthy' ,
statusAttention : 'Needs attention' ,
statusUnhealthy : 'Issue' ,
statusUnknown : 'Not tracked yet' ,
activityEmptyHint : 'Save or publish a change to see it appear here.' ,
activityUnavailable : 'Activity history unavailable' ,
activityUnavailableHint : "Couldn't reach the activity data source. Try refreshing later." ,
activityErrorHint : "Couldn't load recent activity." ,
shortcutsTitle : 'Useful shortcuts' ,
shortcutsDescription : 'Frequently used destinations across the admin panel' ,
shortcutMarketplaceBuilder : 'Marketplace Builder' ,
shortcutSettings : 'Settings' ,
shortcutContent : 'Content' ,
docTitle : 'Documentation' ,
docDocumentation : 'Documentation' ,
docKeyboardShortcuts : 'Keyboard shortcuts' ,
docReportIssue : 'Report an issue' ,
docReleaseNotes : 'Release notes' ,
2026-07-14 12:21:33 +04:00
} ,
2026-07-10 13:52:01 +04:00
staticPages : {
notFound : 'Page not found' ,
backHome : 'Back to home' ,
duplicateSlug : 'Duplicate slugs are not allowed.' ,
emptyTitle : 'Each page must have at least one title.' ,
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 : 'Two or more pages share the same route.' ,
invalidHtml : 'This page has malformed HTML content.' ,
invalidSeo : 'This page has an invalid SEO field (canonical/OG image URL or robots value).' ,
searchPlaceholder : 'Search pages…' ,
filterAll : 'All statuses' ,
filterAllLocales : 'All languages' ,
confirmDeletePage : 'Delete this page? This cannot be undone.' ,
confirmBulkDelete : 'Delete the selected pages? This cannot be undone.' ,
duplicatePage : 'Duplicate' ,
selectAll : 'Select all' ,
selectedCount : 'selected' ,
bulkDelete : 'Delete selected' ,
bulkEnable : 'Enable selected' ,
bulkDisable : 'Disable selected' ,
bulkPublishAction : 'Publish selected' ,
bulkUnpublish : 'Unpublish selected' ,
routeLabel : 'Route' ,
enabledLabel : 'Enabled' ,
statusLabel : 'Status' ,
publishPageAction : 'Publish page' ,
unpublishPageAction : 'Unpublish page' ,
heroImageLabel : 'Hero image' ,
thumbnailLabel : 'Thumbnail' ,
galleryLabel : 'Gallery' ,
customTemplateLabel : 'Custom template' ,
seoRobotsLabel : 'Robots' ,
disabledBadge : 'Disabled' ,
2026-07-17 10:11:31 +04:00
previewDesktop : 'Desktop' ,
previewTablet : 'Tablet' ,
previewMobile : 'Mobile' ,
previewToggle : 'Preview' ,
2026-07-10 13:52:01 +04:00
} ,
2026-07-18 11:02:26 +04:00
contentManagement : {
publishedPages : 'Published pages' ,
draftPages : 'Draft pages' ,
missingLegalPages : 'Missing legal pages' ,
seoHealth : 'SEO health' ,
lastEdited : 'Last edited' ,
lastEditedNever : 'Never' ,
completionLabel : 'Completion' ,
recommendedNext : 'Recommended next step' ,
recommendAddTitles : 'Some pages are missing a title in at least one language.' ,
recommendFixSeo : 'A page has an SEO field that needs fixing (canonical/OG image URL or robots value).' ,
recommendPublish : 'A required legal page is still a draft — publish it so customers can see it.' ,
recommendNone : 'Nice work — your content is in good shape.' ,
openAction : 'Open' ,
backToPages : 'Back to pages' ,
groupContent : 'Content' ,
groupSeo : 'SEO' ,
groupSharing : 'Sharing' ,
groupAdvanced : 'Advanced' ,
groupAdvancedHtml : 'Raw HTML (advanced)' ,
seoExplainDesc : 'This is what shows up in search results — a clear title and description help customers find this page.' ,
seoTitleHelp : 'The headline shown in search results. Keep it short and descriptive.' ,
seoDescriptionHelp : 'A short summary shown under the title in search results.' ,
seoCanonicalHelp : 'The official web address for this page, used to avoid duplicate-content issues.' ,
seoRobotsHelp : 'Controls whether search engines are allowed to list this page.' ,
sharingExplain : 'This is how the page looks when shared on social media (Facebook, Twitter/X, and others).' ,
mediaSelect : 'Choose image' ,
mediaReplace : 'Replace' ,
mediaRemove : 'Remove' ,
mediaAlt : 'Alt text' ,
mediaCaption : 'Caption' ,
emptyStateGuideTitle : 'Start building your storefront pages' ,
emptyStateGuideBody : 'Legal pages like About, Privacy, and Terms build trust with customers. We recommend publishing About, Contacts, Privacy, and Terms first, then adding Cookies, Delivery, Returns, and FAQ.' ,
seoStatusGood : 'SEO good' ,
seoStatusPartial : 'SEO partial' ,
seoStatusWarning : 'SEO issue' ,
seoStatusMissing : 'SEO missing' ,
needsAttention : 'Needs attention' ,
legal : {
about : { label : 'About' , why : 'Tells customers who you are and builds trust before they buy.' } ,
contacts : { label : 'Contacts' , why : 'Gives customers a way to reach you with questions or issues.' } ,
privacy : { label : 'Privacy' , why : 'Explains how customer data is handled — often legally required.' } ,
terms : { label : 'Terms' , why : 'Sets the rules for using your store — protects you and your customers.' } ,
cookies : { label : 'Cookies' , why : 'Discloses cookie usage, required in many regions.' } ,
delivery : { label : 'Delivery' , why : 'Sets clear shipping expectations and reduces support requests.' } ,
returns : { label : 'Returns' , why : 'Explains your refund policy and builds purchase confidence.' } ,
faq : { label : 'FAQ' , why : 'Answers common questions before customers have to ask.' } ,
} ,
} ,
2026-07-09 02:29:12 +04:00
widgets : {
unavailable : 'Widget unavailable' ,
} ,
2026-02-26 23:09:20 +04:00
carousel : {
loading : 'Loading products...' ,
addToCart : 'Add to cart' ,
} ,
common : {
retry : 'Try again' ,
loading : 'Loading...' ,
2026-07-17 15:22:45 +04:00
remove : 'Remove' ,
2026-02-26 23:09:20 +04:00
} ,
2026-02-28 17:18:24 +04:00
location : {
allRegions : 'All regions' ,
chooseRegion : 'Choose region' ,
detectAuto : 'Detect automatically' ,
} ,
auth : {
loginRequired : 'Login required' ,
loginDescription : 'Please log in via Telegram to proceed with your order' ,
checking : 'Checking...' ,
loginWithTelegram : 'Log in with Telegram' ,
orScanQr : 'Or scan the QR code' ,
loginNote : 'You will be redirected back after login' ,
2026-03-25 15:32:50 +04:00
qrExpired : 'QR code expired. Click to refresh' ,
2026-06-01 00:47:26 +04:00
qrError : 'Could not create login session. Click to retry' ,
2026-02-28 17:18:24 +04:00
} ,
2026-07-09 01:13:54 +04:00
ux : {
items : 'items' ,
wishlistTitle : 'Wishlist' ,
wishlistEmptyTitle : 'Your wishlist is empty' ,
wishlistEmptyDescription : 'Save products to revisit them anytime.' ,
clearWishlist : 'Clear wishlist' ,
2026-07-09 02:29:12 +04:00
wishlistCleared : 'Wishlist cleared' ,
2026-07-09 01:13:54 +04:00
compareTitle : 'Compare Products' ,
compareEmptyTitle : 'No products to compare' ,
compareEmptyDescription : 'Add products from catalog cards to compare specs and prices.' ,
clearCompare : 'Clear compare' ,
2026-07-19 23:35:17 +04:00
removeFromCompare : 'Remove from compare' ,
2026-07-09 01:13:54 +04:00
hideIdentical : 'Hide identical values' ,
highlightDifferences : 'Highlight differences' ,
clearRecentlyViewed : 'Clear recently viewed' ,
recentlyViewedEmpty : 'No recently viewed products yet.' ,
saveSearch : 'Save search' ,
goToCatalog : 'Go to catalog' ,
2026-07-09 01:40:22 +04:00
wishlistAdded : 'Added to wishlist' ,
wishlistRemoved : 'Removed from wishlist' ,
compareAdded : 'Added to compare' ,
compareRemoved : 'Removed from compare' ,
compareLimitReached : 'Compare limit reached ({{maxItems}})' ,
productShared : 'Product shared' ,
productLinkCopied : 'Product link copied' ,
sharingUnsupported : 'Sharing is not supported on this device' ,
2026-07-09 02:29:12 +04:00
addedToCart : 'Added to cart' ,
2026-07-09 01:40:22 +04:00
enterQueryBeforeSave : 'Enter a search query before saving' ,
savedSearchNamed : 'Saved search: {{name}}' ,
2026-07-09 02:29:12 +04:00
recentlyViewedTitle : 'Recently Viewed' ,
compareAttribute : 'Attribute' ,
comparePrice : 'Price' ,
compareRating : 'Rating' ,
compareStock : 'Stock' ,
compareDiscount : 'Discount' ,
compareColor : 'Color' ,
compareSize : 'Size' ,
compareUnknown : 'unknown' ,
2026-07-09 01:13:54 +04:00
} ,
2026-07-10 13:34:25 +04:00
diagnostics : {
title : 'Marketplace Diagnostics' ,
disabledTitle : 'Diagnostics unavailable' ,
disabledDescription : 'Diagnostics page is available only in development mode.' ,
generatedAt : 'Generated at {{value}}' ,
healthScore : 'Health score' ,
summary : 'Summary' ,
passedChecks : '{{count}} passed checks' ,
warnings : '{{count}} warnings' ,
errors : '{{count}} errors' ,
critical : '{{count}} critical' ,
healthChecks : 'Health checks' ,
results : 'Detailed results' ,
noIssues : 'No diagnostics issues found.' ,
ok : 'OK' ,
failed : 'Failed' ,
affectedComponent : 'Affected component' ,
suggestedResolution : 'Suggested resolution' ,
severity : {
info : 'Info' ,
warning : 'Warning' ,
error : 'Error' ,
critical : 'Critical' ,
} ,
checks : {
bootstrapLoaded : 'Bootstrap loaded' ,
tenantResolved : 'Tenant resolved' ,
runtimeInitialized : 'Runtime initialized' ,
themeLoaded : 'Theme loaded' ,
widgetManifestLoaded : 'Widget manifest loaded' ,
sectionEngineInitialized : 'Section engine reachable' ,
configurationEngineInitialized : 'Configuration engine initialized' ,
translationResourcesAvailable : 'Translations available' ,
requiredAssetsAvailable : 'Required assets healthy' ,
} ,
bootstrapMissingTitle : 'Bootstrap missing' ,
bootstrapMissingDescription : 'Bootstrap configuration could not be loaded.' ,
bootstrapMissingResolution : 'Verify bootstrap provider response and local mock availability.' ,
requiredPropertyMissingTitle : 'Required property missing' ,
requiredPropertyMissingDescription : 'Required bootstrap property is missing.' ,
requiredPropertyMissingResolution : 'Add missing property to bootstrap payload.' ,
unknownWidgetTypeTitle : 'Unknown widget type' ,
unknownWidgetTypeDescription : 'Widget type is not present in widget manifest.' ,
unknownWidgetTypeResolution : 'Register widget in manifest or remove invalid widget config.' ,
duplicateIdTitle : 'Duplicate identifier' ,
duplicatePageIdDescription : 'Duplicate page id detected.' ,
duplicateSectionIdDescription : 'Duplicate section id detected.' ,
duplicateWidgetIdDescription : 'Duplicate widget id detected.' ,
duplicateIdResolution : 'Ensure ids are unique within bootstrap config.' ,
unknownLayoutTitle : 'Unknown layout' ,
unknownLayoutDescription : 'Page layout value is not recognized.' ,
unknownLayoutResolution : 'Use supported layout or extend diagnostics allow-list.' ,
invalidFeatureFlagTitle : 'Invalid feature flag' ,
invalidFeatureFlagDescription : 'Feature flag value must be boolean.' ,
invalidFeatureFlagResolution : 'Normalize feature flag values to true or false.' ,
brokenPageDefinitionTitle : 'Broken page definition' ,
brokenPageDefinitionDescription : 'Page definition is incomplete.' ,
brokenPageDefinitionResolution : 'Add missing route, title, key, or sections.' ,
invalidNavigationTargetTitle : 'Invalid navigation target' ,
invalidNavigationTargetDescription : 'Navigation route does not match known routes.' ,
invalidNavigationTargetResolution : 'Update route target or add matching route surface.' ,
missingTranslationTitle : 'Missing translation' ,
missingTranslationDescription : 'Translation key resolves to itself.' ,
missingTranslationResolution : 'Add missing key to translation resources.' ,
missingMediaTitle : 'Missing media' ,
missingMediaDescription : 'Expected branding media is missing.' ,
missingMediaResolution : 'Provide valid media URLs in bootstrap branding config.' ,
runtimeNotInitializedTitle : 'Runtime not initialized' ,
runtimeNotInitializedDescription : 'Platform runtime state has not been marked initialized.' ,
runtimeNotInitializedResolution : 'Verify PlatformRuntimeService initialize sequence.' ,
configFallbackUsageTitle : 'Configuration fallback in use' ,
configFallbackUsageDescription : 'Development runtime is using fallback or mock configuration.' ,
configFallbackUsageResolution : 'Switch provider mode if real bootstrap validation is needed.' ,
missingDatasourceTitle : 'Missing datasource' ,
missingDatasourceDescription : 'Widget supports datasource selection but none was declared.' ,
missingDatasourceResolution : 'Define source in widget props or manifest default settings.' ,
widgetRenderFailureTitle : 'Widget render failure' ,
widgetRenderFailureDescription : 'Widget fell back to unknown widget renderer.' ,
widgetRenderFailureResolution : 'Register widget component or fix manifest component key.' ,
brokenRouteTitle : 'Broken route expectation' ,
brokenRouteDescription : 'Expected route surface is missing.' ,
brokenRouteResolution : 'Restore route registration or update diagnostics expectation.' ,
imageLoadFailedTitle : 'Image load failed' ,
imageLoadFailedDescription : 'Rendered image failed to load.' ,
imageLoadFailedResolution : 'Verify asset path, CORS, and media availability.' ,
optionalDataMissingTitle : 'Optional data missing' ,
optionalDataMissingDescription : 'Optional configuration data is absent.' ,
optionalDataMissingResolution : 'Add optional value if UX depends on it.' ,
} ,
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 : 'Search by customer, product, or review text…' ,
2026-07-20 00:03:46 +04:00
selectAllRows : 'Select all reviews' ,
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 : 'All statuses' ,
allRatings : 'All ratings' ,
rating : 'Rating' ,
customer : 'Customer' ,
product : 'Product' ,
reviewText : 'Review' ,
photos : 'Photos' ,
workflow : 'Actions' ,
approve : 'Approve' ,
reject : 'Reject' ,
markSpam : 'Mark as spam' ,
hide : 'Hide' ,
restore : 'Restore' ,
pin : 'Pin' ,
unpin : 'Unpin' ,
feature : 'Feature' ,
unfeature : 'Unfeature' ,
featureDisabledHint : 'Only approved reviews can be featured.' ,
moderatorNotes : 'Moderator notes' ,
notAvailable : 'Not available yet' ,
changeStatus : 'Change status' ,
hideSelected : 'Hide' ,
archiveSelected : 'Archive' ,
reportsQueue : 'Reports queue' ,
reportsColumn : 'Reports' ,
reportTarget : 'Reported item' ,
reportType : 'Type' ,
reportReason : 'Reason' ,
resolve : 'Resolve' ,
dismiss : 'Dismiss' ,
reportsEmptyTitle : 'No reports' ,
reportsEmptyDescription : 'Customer reports about products, reviews, or accounts will show up here.' ,
reportedCount : 'Reported' ,
averageRating : 'Average rating' ,
moderationHealth : 'Moderation health' ,
emptyTitle : 'No reviews yet' ,
emptyDescription : 'Reviews will appear here once customers start leaving feedback.' ,
emptyGuide : 'Customers leave a star rating and text after purchase. New reviews start as Pending until a moderator approves, rejects, or marks them as spam — approved reviews become visible on the storefront. Aim to clear the pending queue regularly.' ,
healthRating : 'Rating' ,
healthText : 'Text' ,
healthMedia : 'Media' ,
healthModeration : 'Moderated' ,
healthReportStatus : 'No open reports' ,
healthVisibility : 'Visible' ,
health : 'Health' ,
column_product : 'Product' ,
column_rating : 'Rating' ,
column_status : 'Status' ,
column_reports : 'Reports' ,
column_created : 'Submitted' ,
status : {
pending : 'Pending' ,
approved : 'Approved' ,
rejected : 'Rejected' ,
spam : 'Spam' ,
} ,
targetType : {
product : 'Product' ,
review : 'Review' ,
customer : 'Customer' ,
category : 'Category' ,
unknown : 'Unknown' ,
} ,
reportStatus : {
open : 'Open' ,
resolved : 'Resolved' ,
dismissed : 'Dismissed' ,
} ,
} ,
2026-07-18 21:47:54 +04:00
adminOrders : {
back : 'Back to orders' ,
search : 'Search by order number, name, email, or phone…' ,
export : 'Export' ,
2026-07-20 00:00:29 +04:00
selectAllRows : 'Select all orders' ,
selectRow : 'Select order' ,
2026-07-18 21:47:54 +04:00
view : 'View' ,
orderNumber : 'Order' ,
customer : 'Customer' ,
payment : 'Payment' ,
delivery : 'Delivery' ,
trackingNumber : 'Tracking number' ,
createdAt : 'Placed' ,
items : 'Items' ,
timeline : 'Timeline' ,
notes : 'Notes to customer' ,
internalNotes : 'Internal notes' ,
addNote : 'Add note' ,
changeStatus : 'Change status' ,
applyStatus : 'Apply' ,
archiveSelected : 'Archive' ,
printSelected : 'Print' ,
printInvoice : 'Print invoice' ,
requestRefund : 'Request refund' ,
cancelOrder : 'Cancel order' ,
confirmCancel : 'Cancel this order?' ,
confirmRefund : 'Request a refund for this order?' ,
emptyTitle : 'No orders yet' ,
emptyDescription : 'Orders will show up here as customers check out.' ,
column_customer : 'Customer' ,
column_status : 'Status' ,
column_payment : 'Payment' ,
column_total : 'Total' ,
column_created : 'Placed' ,
status : {
2026-07-19 23:04:51 +04:00
all : 'All statuses' ,
2026-07-18 21:47:54 +04:00
pending : 'Pending' ,
processing : 'Packing' ,
shipped : 'Shipping' ,
delivered : 'Completed' ,
cancelled : 'Cancelled' ,
refunded : 'Refunded' ,
} ,
paymentStatus : {
unpaid : 'Unpaid' ,
paid : 'Paid' ,
refund_requested : 'Refund requested' ,
refunded : 'Refunded' ,
} ,
ordersToday : 'Orders today' ,
paidCount : 'Paid' ,
customersCount : 'Customers' ,
returningCustomers : 'Returning customers' ,
averageOrder : 'Average order' ,
recentActivity : 'Recent activity' ,
noRecentActivity : 'No activity yet.' ,
alertStuckPending : 'orders have been pending for over 48 hours' ,
alertRefundRequested : 'orders have a refund request waiting' ,
} ,
adminCustomers : {
search : 'Search by name, email, or phone…' ,
name : 'Name' ,
email : 'Email' ,
phone : 'Phone' ,
orderCount : 'Orders' ,
lifetimeValue : 'Lifetime value' ,
returning : 'Returning' ,
profile : 'Profile' ,
statistics : 'Statistics' ,
firstOrder : 'First order' ,
lastOrder : 'Last order' ,
addresses : 'Addresses' ,
notes : 'Notes' ,
notesUnavailable : 'No customer-level notes yet — add a note on one of their orders instead.' ,
orders : 'Orders' ,
activity : 'Activity' ,
emptyTitle : 'No customers yet' ,
emptyDescription : 'Customers appear here once they place their first order.' ,
} ,
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 : 'Media Library' ,
upload : 'Upload' ,
uploading : 'Uploading...' ,
searchPlaceholder : 'Search files...' ,
delete : 'Delete' ,
deleteConfirmTitle : 'Delete file?' ,
deleteConfirmBody : 'This cannot be undone.' ,
cancel : 'Cancel' ,
confirm : 'Delete' ,
emptyTitle : 'No files yet' ,
emptyDescription : 'Upload an image or document to get started.' ,
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 : 'All folders' ,
newFolder : 'New folder' ,
editTags : 'Edit tags' ,
totalAssets : 'Total assets' ,
logos : 'Logos' ,
unused : 'Unused' ,
storageUsed : 'Storage used' ,
altCoverage : 'Alt text coverage' ,
allTypes : 'All types' ,
typeImage : 'Images' ,
typeSvg : 'SVG' ,
typePdf : 'PDF' ,
sortRecent : 'Recent' ,
sortName : 'Name' ,
sortSize : 'Size' ,
viewMode : 'View' ,
viewGrid : 'Grid' ,
viewList : 'List' ,
dropHint : 'Drag and drop images here, or use Upload above.' ,
cancelUpload : 'Cancel' ,
retry : 'Retry' ,
errorTooLarge : 'That file is too large. Try a smaller file.' ,
errorUnsupportedType : 'That file type is not supported. Use JPG, PNG, WebP, GIF, SVG, or PDF.' ,
errorGeneric : 'Upload failed. Please try again.' ,
selectedCount : 'selected' ,
download : 'Download' ,
exportMetadata : 'Export metadata' ,
bulkDelete : 'Delete selected' ,
bulkDeleteConfirm : 'Delete the selected files? This cannot be undone.' ,
clearSelection : 'Clear selection' ,
guideCopy : 'Reusing an existing asset avoids duplicate uploads and keeps your storage tidy. For best results upload images around 1200× 1200px for hero/banner use and compress large photos before uploading.' ,
missingAlt : 'Missing alt text' ,
usageCount : 'uses' ,
detailsTitle : 'Asset details' ,
filename : 'Filename' ,
format : 'Format' ,
fileSize : 'File size' ,
dimensions : 'Dimensions' ,
uploadDate : 'Uploaded' ,
lastUsed : 'Last used' ,
usageCountLabel : 'Usage count' ,
usedIn : 'Used in' ,
notUsed : 'Not currently used anywhere.' ,
unknownValue : 'Unknown' ,
altText : 'Alt text' ,
altTextHelp : 'Describes the image for screen readers and search engines.' ,
decorative : 'Decorative (no alt text needed)' ,
missingAltWarning : 'This image has no alt text and is not marked decorative — screen reader users won’ t know what it shows.' ,
caption : 'Caption' ,
description : 'Description' ,
usage : {
brand : 'Logo' ,
theme : 'Theme' ,
header : 'Header' ,
footer : 'Footer' ,
staticPage : 'Static page' ,
homepage : 'Homepage' ,
catalog : 'Catalog' ,
productPage : 'Product page' ,
widget : 'Widget' ,
company : 'Company info' ,
seo : 'SEO' ,
navigation : 'Navigation' ,
other : '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 : 'Choose image' ,
2026-07-17 15:22:45 +04:00
replaceImage : 'Replace image' ,
2026-07-18 17:04:11 +04:00
search : 'Search categories…' ,
showDeleted : 'Show deleted' ,
2026-07-19 23:57:49 +04:00
selectAllRows : 'Select all categories' ,
selectRow : 'Select category' ,
toggleVisibility : 'Toggle visibility' ,
2026-07-18 17:04:11 +04:00
create : 'Create category' ,
edit : 'Edit category' ,
title : 'Title' ,
slug : 'URL slug' ,
slugTaken : 'This slug is already used by another category.' ,
parent : 'Parent category' ,
noParent : 'No parent (top level)' ,
icon : 'Icon' ,
image : 'Image' ,
imageHint : 'Shown in category listings and navigation.' ,
description : 'Description' ,
items : 'products' ,
status : { draft : 'Draft' , published : 'Published' } ,
restore : 'Restore' ,
saveDraft : 'Save draft' ,
publish : 'Publish' ,
confirmDelete : 'Delete this category? This cannot be undone.' ,
confirmLeaveUnsaved : 'You have unsaved changes. Leave without saving?' ,
deleteBlocked : 'This category can\'t be deleted while it has subcategories or assigned products.' ,
emptyTitle : 'No categories yet' ,
emptyDescription : 'Create your first category to start organizing products.' ,
emptyGuide : 'Categories help customers browse and find products. Start with a few broad top-level categories (e.g. Clothing, Electronics), then add subcategories as your catalog grows — avoid nesting more than 2-3 levels deep.' ,
viewTree : 'Tree' ,
viewCards : 'Cards' ,
expandAll : 'Expand all' ,
collapseAll : 'Collapse all' ,
expandNode : 'Expand' ,
collapseNode : 'Collapse' ,
jumpToParent : 'Jump to parent' ,
deletedBadge : 'Deleted' ,
column_slug : 'Slug' ,
column_items : 'Products' ,
column_status : 'Status' ,
column_visibility : 'Visibility' ,
column_updated : 'Last updated' ,
bulkAssignParent : 'Assign parent' ,
bulkAssignImage : 'Assign image' ,
groupGeneral : 'General' ,
groupMedia : 'Media' ,
groupSeo : 'SEO' ,
groupVisibility : 'Visibility' ,
groupNavigation : 'Navigation' ,
groupAttributes : 'Attributes' ,
groupAdvanced : 'Advanced' ,
visibilityExplain : 'A hidden category and its products stay out of the storefront navigation and search until you make it visible again.' ,
navBreadcrumb : 'Breadcrumb' ,
2026-07-19 08:35:18 +04:00
navBreadcrumbHint : 'This is the path customers see above this category, e.g. Home › Electronics › Phones. It comes from the parent category you choose.' ,
iconHint : 'A small emoji or symbol shown next to the category name in menus, e.g. 📱. Leave empty for none.' ,
2026-07-18 17:04:11 +04:00
navRoot : 'This is a top-level category.' ,
navChildren : 'Subcategories' ,
navNoChildren : 'No subcategories yet.' ,
navAppearsIn : 'Where this appears' ,
navAppearsVisible : 'Visible in catalog navigation and search.' ,
navAppearsHidden : 'Hidden — not shown in catalog navigation while hidden.' ,
itemsCountLabel : 'Assigned products' ,
createdAtLabel : 'Created' ,
healthImage : 'Image' ,
healthSeo : 'SEO' ,
healthDescription : 'Description' ,
healthParent : 'Parent' ,
healthVisibility : 'Visibility' ,
healthProducts : 'Products assigned' ,
totalCategories : 'Total categories' ,
visibleCount : 'Visible' ,
hiddenCount : 'Hidden' ,
emptyCount : 'Empty' ,
rootCount : 'Root categories' ,
subCount : 'Subcategories' ,
missingImagesCount : 'Missing images' ,
missingSeoCount : 'Missing SEO' ,
lastModified : 'Last modified' ,
lastModifiedNever : 'Never' ,
completionLabel : 'Completion' ,
recommendedNext : 'Recommended next step' ,
recommendAddImage : 'A category has no image — add one so it looks trustworthy in listings.' ,
recommendAddSeo : 'A category is missing a search title or description — add one so it can be found.' ,
recommendFillEmpty : 'A category has no products assigned — add products or consider hiding it.' ,
recommendNone : 'Nice work — your category structure is in good shape.' ,
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 : {
emptyTitle : 'No products found' ,
emptyDescription : 'Try adjusting your filters, or create a new product.' ,
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 : 'Good products have a clear title, at least one photo, a price, and a short description — that\'s enough to publish. You can always add more detail later.' ,
2026-07-19 23:55:11 +04:00
selectAllRows : 'Select all products' ,
selectRow : 'Select product' ,
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 : 'Search products…' ,
category : 'Category' ,
allCategories : 'All categories' ,
visibility : 'Visibility' ,
allVisibility : 'All visibility' ,
visible : 'Visible' ,
hidden : 'Hidden' ,
stockStatus : 'Stock status' ,
allStock : 'All stock levels' ,
inStock : 'In stock' ,
lowStock : 'Low stock' ,
outOfStock : 'Out of stock' ,
sortTitle : 'Name' ,
sortPrice : 'Price' ,
sortPriority : 'Priority' ,
sortStock : 'Stock' ,
sortUpdated : 'Last updated' ,
showArchived : 'Show archived' ,
infiniteScroll : 'Infinite scroll' ,
viewMode : 'View' ,
viewTable : 'Table' ,
viewGrid : 'Grid' ,
density : 'Density' ,
densityComfortable : 'Comfortable' ,
densityCompact : 'Compact' ,
columns : 'Columns' ,
column_sku : 'SKU' ,
column_brand : 'Brand' ,
column_price : 'Price' ,
column_stock : 'Stock' ,
column_visibility : 'Visibility' ,
column_updated : 'Last updated' ,
create : 'Create product' ,
edit : 'Edit product' ,
duplicate : 'Duplicate' ,
selectedCount : 'selected' ,
bulkShow : 'Publish' ,
bulkHide : 'Hide' ,
bulkAssignCategory : 'Assign category' ,
bulkAssignTags : 'Assign tags' ,
bulkDuplicateAction : 'Duplicate' ,
bulkExportAction : 'Export' ,
bulkDelete : 'Delete' ,
tagsPlaceholder : 'e.g. summer, sale' ,
name : 'Name' ,
brand : 'Brand' ,
healthColumn : 'Health' ,
actions : 'Actions' ,
archive : 'Archive' ,
delete : 'Delete' ,
items : 'products' ,
loadMore : 'Load more' ,
noImage : 'No image' ,
slug : 'URL slug' ,
barcode : 'Barcode' ,
priority : 'Priority' ,
shortDescription : 'Short description' ,
translations : 'Translations' ,
primaryImage : 'Primary image' ,
primaryImageHint : 'The main photo shown in listings and search results.' ,
gallery : 'Gallery' ,
galleryHint : 'Additional photos shown on the product page. Drag order with the arrows.' ,
moveLeft : 'Move earlier' ,
moveRight : 'Move later' ,
videos : 'Videos (one URL per line)' ,
discount : 'Discount %' ,
currency : 'Currency' ,
stockQuantity : 'Stock quantity' ,
stockQuantityHint : 'How many units are available to sell right now.' ,
availabilityStatus : 'Availability' ,
availabilityStatusHint : 'What customers see: in stock, running low, or out of stock.' ,
availabilityNote : 'Availability note' ,
availabilityNoteHint : 'Optional extra detail shown to customers, e.g. "Ships in 3 days".' ,
reservedNote : 'Reserved stock isn\'t tracked separately yet — quantity shown here is total available stock.' ,
relatedProducts : 'Related products' ,
specifications : 'Specifications' ,
attributes : 'Attributes' ,
addRow : 'Add row' ,
removeRow : 'Remove' ,
rowKey : 'Name' ,
rowValue : 'Value' ,
addVariant : 'Add variant' ,
variantName : 'Variant name' ,
variantsHint : 'Each variant is a purchasable option of this product, e.g. a size or color, with its own price and stock.' ,
2026-07-18 22:44:39 +04:00
variants : '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 : 'Options' ,
variantAttributesHint : 'Add options like Color or Size, then list the values customers can choose from. Combinations below are generated automatically.' ,
colorAttribute : 'Color' ,
removeAttribute : 'Remove option' ,
removeValue : 'Remove value' ,
pickColor : 'Pick a color' ,
newValuePlaceholder : 'e.g. Small' ,
addValue : 'Add' ,
newAttributePlaceholder : 'e.g. Size' ,
addAttribute : 'Add option' ,
generateVariants : 'Generate variants' ,
variantsList : 'Variants' ,
remaining : 'Stock' ,
variantImage : 'Image' ,
2026-07-18 22:44:39 +04:00
archived : '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 : 'The web address of this product. Filled in automatically from the name - edit only if you need a custom URL.' ,
skuHint : 'SKU (stock keeping unit) is your internal product code, used for inventory and order lookups. Any unique text works.' ,
generate : 'Generate' ,
seoGenerate : 'Fill from product details' ,
seoGenerateHint : 'Fills empty fields from the product name and short description. Your existing text is kept.' ,
2026-07-19 08:40:30 +04:00
translationsHint : 'The main fields above are shown in your default store language. Add translations here for other languages - if a translation is empty, customers see the default text instead.' ,
2026-07-19 08:44:20 +04:00
badgesHint : 'Badges are the small colored labels customers see on the product photo. Pick from the standard set or add your own.' ,
addBadge : 'Add' ,
removeBadge : 'Remove badge' ,
customBadgePlaceholder : 'Your own badge text…' ,
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 : 'This is what shows up in search results — a clear title and description help customers find this product.' ,
searchTitle : 'Search title' ,
searchTitleHint : 'The headline shown in search results. Keep it short and descriptive.' ,
searchDescription : 'Search description' ,
searchDescriptionHint : 'A short summary shown under the title in search results.' ,
seoMissingTitle : 'Add a search title so this product can be found.' ,
seoMissingDescription : 'Add a search description to improve how this product appears in results.' ,
keywords : 'Keywords' ,
featured : 'Featured' ,
recommended : 'Recommended' ,
new : 'New' ,
bestseller : 'Bestseller' ,
badges : 'Badges (comma-separated)' ,
htmlDescription : 'Detailed description' ,
customer : 'Customer feedback' ,
reviewsReadonly : 'Reviews' ,
noReviews : 'No reviews yet.' ,
questionsReadonly : 'Questions' ,
noQuestions : 'No questions yet.' ,
save : 'Save product' ,
groupGeneral : 'General' ,
groupMedia : 'Media' ,
groupPricing : 'Pricing' ,
groupInventory : 'Inventory' ,
groupCategories : 'Categories' ,
groupAttributes : 'Attributes' ,
groupSeo : 'SEO' ,
groupVisibility : 'Visibility' ,
groupAdvanced : 'Advanced' ,
healthImages : 'Images' ,
healthSeo : 'SEO' ,
healthPrice : 'Price' ,
healthCategory : 'Category' ,
healthDescription : 'Description' ,
healthInventory : 'Inventory' ,
totalProducts : 'Total products' ,
publishedCount : 'Published' ,
draftsCount : 'Drafts' ,
outOfStockCount : 'Out of stock' ,
hiddenCount : 'Hidden' ,
missingImagesCount : 'Missing images' ,
missingSeoCount : 'Missing SEO' ,
lowQualityCount : 'Low-quality' ,
recentlyEdited : 'Recently edited' ,
recommendedNext : 'Recommended next step' ,
openAction : 'Open' ,
recommendAddImages : 'A product has no photos — add at least one image so it looks trustworthy.' ,
recommendAddSeo : 'A product is missing a search title or description — add one so it can be found.' ,
recommendRestock : 'A product is out of stock — restock it or mark it unavailable.' ,
recommendNone : 'Nice work — your catalog is in good shape.' ,
2026-07-16 00:19:41 +04:00
} ,
adminUsers : {
emptyTitle : 'No users found' ,
emptyDescription : 'Invite a teammate to get started.' ,
invitationsEmptyTitle : 'No pending invitations' ,
2026-07-18 22:44:39 +04:00
title : 'Team members' ,
name : 'Name' ,
email : 'Email' ,
scope : 'Workspace' ,
role : 'Role' ,
roles : 'Roles' ,
lastLogin : 'Last sign-in' ,
sessions : 'Active sessions' ,
currentSession : 'This session' ,
invite : 'Invite member' ,
sendInvite : 'Send invitation' ,
revoke : 'Revoke' ,
passwordlessHint : 'Team members sign in with Telegram - no passwords to manage.' ,
confirmSuspend : 'Suspend this team member? They will lose access immediately.' ,
2026-07-19 23:04:51 +04:00
suspend : 'Suspend' ,
reactivate : 'Reactivate' ,
2026-07-18 22:44:39 +04:00
scopeValue : {
marketplace : 'Storefront' ,
office : 'Back office' ,
} ,
statusValue : {
active : 'Active' ,
invited : 'Invited' ,
suspended : 'Suspended' ,
} ,
invitationStatus : {
pending : 'Pending' ,
accepted : 'Accepted' ,
expired : 'Expired' ,
revoked : 'Revoked' ,
} ,
} ,
adminTransactions : {
search : 'Search transactions' ,
type : 'Type' ,
method : 'Payment method' ,
fraud : 'Fraud check' ,
flagged : 'Flagged' ,
2026-07-19 08:25:29 +04:00
flag : 'Flag as suspicious' ,
clearFlag : 'Clear flag' ,
2026-07-18 22:44:39 +04:00
retry : 'Retry' ,
audit : 'History' ,
emptyTitle : 'No transactions found' ,
emptyDescription : 'Try a different filter or search term.' ,
status : {
all : 'All statuses' ,
pending : 'Pending' ,
success : 'Successful' ,
failed : 'Failed' ,
retried : 'Retried' ,
} ,
typeValue : {
all : 'All types' ,
payment : 'Payment' ,
refund : 'Refund' ,
qr_payment : 'QR payment' ,
} ,
2026-07-16 00:19:41 +04:00
} ,
adminMonitoring : {
eventsEmptyTitle : 'No events found' ,
eventsEmptyDescription : 'Try a different category filter or search term.' ,
2026-07-18 22:44:39 +04:00
health : 'Health checks' ,
queues : 'Background queues' ,
depth : 'Waiting' ,
webhooks : 'Webhook deliveries' ,
endpoint : 'Destination' ,
event : 'Event' ,
events : 'Activity log' ,
category : 'Category' ,
level : 'Severity' ,
message : 'Description' ,
categoryValue : {
all : 'All categories' ,
audit : 'Admin activity' ,
security : 'Security' ,
login : 'Sign-in' ,
failed_login : 'Failed sign-in' ,
api : 'API' ,
error : 'Error' ,
warning : 'Warning' ,
} ,
queueStatus : {
healthy : 'Running smoothly' ,
degraded : 'Slowed down' ,
down : 'Stopped' ,
} ,
webhookStatus : {
delivered : 'Delivered' ,
failed : 'Failed' ,
pending : 'Pending' ,
} ,
levelValue : {
info : 'Info' ,
warning : 'Warning' ,
error : '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 : 'System state' ,
backendConnectivity : 'Backend' ,
connected : 'Connected' ,
loading : 'Loading' ,
draftState : 'Draft' ,
unsavedChanges : 'Unsaved changes' ,
noDraft : 'No draft' ,
lastSaved : 'Last saved' ,
lastPublished : 'Last published' ,
syncStatus : 'Sync' ,
2026-07-16 00:19:41 +04:00
} ,
adminAnalytics : {
topProductsEmptyTitle : 'No product sales in this period' ,
topProductsEmptyDescription : 'Try a wider date range.' ,
2026-07-18 22:44:39 +04:00
topProducts : 'Top products' ,
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 : 'Print' ,
tabsLabel : 'Analytics sections' ,
tab : {
overview : 'Overview' ,
health : 'Health' ,
products : 'Products' ,
customers : 'Customers' ,
search : 'Search' ,
traffic : 'Traffic' ,
recommendations : 'Recommendations' ,
} ,
revenue : 'Revenue' ,
orders : 'Orders' ,
customers : 'Customers' ,
avgOrderValue : 'Avg. Order Value' ,
conversion : 'Conversion' ,
completionPercent : 'Completion' ,
unknown : 'Unknown' ,
salesChart : 'Sales' ,
quantitySold : 'Qty sold' ,
lowStock : 'Low stock' ,
lowStockEmptyTitle : 'No low-stock products' ,
quantity : 'Quantity' ,
status : 'Status' ,
recentActivity : 'Recent activity' ,
recentActivityEmptyTitle : 'No recent activity' ,
activityDraftSaved : 'Draft saved' ,
activityPublished : 'Published' ,
warnings : 'Warnings' ,
topViewed : 'Top viewed' ,
hiddenProducts : 'Hidden products' ,
archivedProducts : 'Archived products' ,
mostReviewed : 'Most reviewed' ,
worstRated : 'Worst rated' ,
noReviewedProducts : 'No reviewed products yet' ,
reviewCount : 'Reviews' ,
avgRating : 'Avg. rating' ,
newCustomers : 'New customers' ,
returningCustomers : 'Returning customers' ,
averageSpend : 'Average spend' ,
retention : 'Retention' ,
searchAnalytics : 'Search analytics' ,
trafficAnalytics : 'Traffic' ,
availableAfterBackend : 'Available after backend integration.' ,
pendingBackend : 'Pending backend' ,
pendingBackendHint : 'No search-query tracking exists yet.' ,
funnelsHeatmaps : 'Funnels & heatmaps' ,
visitors : 'Visitors' ,
products : 'Products' ,
categories : 'Categories' ,
} ,
adminMarketplaceHealth : {
title : 'Marketplace health' ,
complete : 'complete' ,
recommendationsTitle : 'Recommendations' ,
recommendNone : 'Everything looks good.' ,
checkImages : 'Products have images' ,
checkSeo : 'Products have SEO metadata' ,
checkCategories : 'Categories have products' ,
checkReviews : 'Reviews are moderated' ,
checkOrders : 'Orders are processed' ,
checkTranslations : 'Translations are complete' ,
checkHomepage : 'Homepage is configured' ,
checkBackend : 'Backend connectivity' ,
checkPerformance : 'Performance' ,
recommendImages : 'Add images to products missing them' ,
recommendImagesCount : 'Products without images hurt conversion.' ,
recommendSeo : 'Add SEO metadata to products missing it' ,
recommendSeoCount : 'Missing SEO titles/descriptions hurt search visibility.' ,
recommendCategory : 'Assign a category to uncategorized products' ,
recommendCategoryCount : 'Products without a category are harder to discover.' ,
recommendEmptyCategories : 'Categories without products' ,
recommendEmptyCategoriesCount : 'Consider merging or removing empty categories.' ,
recommendHomepage : 'Homepage is incomplete' ,
recommendStaticPages : 'Static pages are unpublished' ,
severity : {
info : 'Info' ,
warning : 'Warning' ,
critical : '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 : 'Skip to content' ,
openSidebar : 'Open menu' ,
closeSidebar : 'Close menu' ,
collapseSidebar : 'Collapse menu' ,
expandSidebar : 'Expand menu' ,
nav : {
dashboard : 'Dashboard' ,
catalogGroup : 'Catalog' ,
products : 'Products' ,
categories : 'Categories' ,
orders : 'Orders' ,
2026-07-18 21:47:54 +04:00
customers : 'Customers' ,
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 : 'Transactions' ,
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 : 'Reviews & 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
reviews : 'Reviews' ,
reports : 'Reports' ,
content : 'Content' ,
mediaLibrary : 'Media Library' ,
marketplaceBuilder : 'Marketplace Builder' ,
users : 'Users' ,
settings : 'Settings' ,
monitoring : 'Monitoring' ,
analytics : 'Analytics' ,
documentation : 'Documentation' ,
help : 'Help' ,
logout : 'Log out' ,
comingSoonBadge : 'Soon' ,
} ,
topbar : {
searchLabel : 'Search the admin panel' ,
searchPlaceholder : 'Search products, orders, pages...' ,
notifications : 'Notifications' ,
notificationsEmpty : 'No new notifications' ,
account : 'Admin account' ,
tenantSelector : 'Store' ,
tenantSelectorComingSoon : 'Switching between stores is coming soon' ,
quickPublish : 'Publish' ,
quickPublishComingSoon : 'Quick publish is coming soon' ,
} ,
breadcrumbHome : 'Admin' ,
pages : {
dashboard : { title : 'Dashboard' , description : 'An overview of your marketplace' } ,
products : { title : 'Products' , description : 'Manage product listings and their visibility' } ,
productCreate : { title : 'New product' , description : 'Fill in the details to add a product to the catalog' } ,
productEdit : { title : 'Edit product' , description : 'Change this product\'s details' } ,
productDuplicate : { title : 'Duplicate product' , description : 'Create a new product based on an existing one' } ,
categories : { title : 'Categories' , description : 'Build your catalog\'s category tree' } ,
categoryCreate : { title : 'New category' , description : 'Add a category to the catalog tree' } ,
categoryEdit : { title : 'Edit category' , description : 'Change this category\'s details' } ,
orders : { title : 'Orders' , description : 'View and process customer orders' } ,
orderDetail : { title : 'Order' , description : 'Order details and status' } ,
2026-07-18 21:47:54 +04:00
customers : { title : 'Customers' , description : 'Everyone who has placed an order' } ,
customerDetail : { title : 'Customer' , description : 'Customer profile, orders, and activity' } ,
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 : 'Reviews & Moderation' , description : 'Review and moderate customer feedback' } ,
reviewDetail : { title : 'Review' , description : 'Review details and moderation actions' } ,
reportsQueue : { title : 'Reports queue' , description : 'Content reported by customers' } ,
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 : 'Transactions' , description : 'Payments, refunds, and fraud review' } ,
media : { title : 'Media Library' , description : 'Images and files for products and pages' } ,
users : { title : 'Users' , description : 'Admin team members and permissions' } ,
monitoring : { title : 'Monitoring' , description : 'Queue, webhook, and system event status' } ,
analytics : { title : 'Analytics' , description : 'Sales, products, and shopper behavior' } ,
} ,
} ,
2026-02-26 23:09:20 +04:00
} ;