1 Commits

Author SHA1 Message Date
sdarbinyan
905c8be8c5 translations 2026-07-04 23:34:00 +04:00
10 changed files with 39 additions and 13 deletions

View File

@@ -31,8 +31,14 @@ export interface Subcategory {
itemCount?: number;
hasItems?: boolean;
subcategories?: Subcategory[];
names?: ItemName[];
translations?: Record<string, SubcategoryTranslation>;
}
interface CategoryTranslation {
name?: string;
}
interface SubcategoryTranslation {
name?: string;
}

View File

@@ -401,7 +401,7 @@ export class CartComponent implements OnDestroy {
telegramUserId: telegramUserId,
items: this.paidItems.map((item: CartItem) => ({
itemID: item.itemID,
name: item.name,
name: this.itemName(item),
price: item.discount > 0
? item.price * (1 - item.discount / 100)
: item.price,
@@ -470,7 +470,7 @@ export class CartComponent implements OnDestroy {
telegramUserId: this.getTelegramUserId(),
items: this.paidItems.map((item: CartItem) => ({
itemID: item.itemID,
name: item.name,
name: this.itemName(item),
price: item.discount > 0
? item.price * (1 - item.discount / 100)
: item.price,

View File

@@ -52,7 +52,7 @@
</div>
</a>
<button class="add-to-cart-btn" (click)="addToCart(item.itemID, $event)" [attr.aria-label]="('category.addToCart' | translate) + ': ' + item.name">
<button class="add-to-cart-btn" (click)="addToCart(item.itemID, $event)" [attr.aria-label]="('category.addToCart' | translate) + ': ' + itemName(item)">
{{ 'category.addToCart' | translate }}
</button>
</div>

View File

@@ -25,13 +25,13 @@
<a [routerLink]="['/category', sub.id] | langRoute" class="category-card">
<div class="category-image">
@if (sub.img) {
<img [src]="sub.img" [alt]="sub.name" loading="lazy" decoding="async" />
<img [src]="sub.img" [alt]="categoryName(sub)" loading="lazy" decoding="async" />
} @else {
<div class="category-fallback">{{ sub.name.charAt(0) }}</div>
<div class="category-fallback">{{ categoryName(sub).charAt(0) }}</div>
}
</div>
<div class="category-info">
<h3 class="category-name">{{ sub.name }}</h3>
<h3 class="category-name">{{ categoryName(sub) }}</h3>
@if (sub.itemCount) {
<span class="category-count">{{ sub.itemCount }}</span>
}

View File

@@ -150,5 +150,5 @@ export class SubcategoriesComponent implements OnInit, OnDestroy {
itemName(item: Item): string { return getTranslatedField(item, 'name', this.langService.currentLanguage()); }
categoryName(cat: Category): string { return getTranslatedCategoryName(cat, this.langService.currentLanguage()); }
categoryName(cat: Category | Subcategory): string { return getTranslatedCategoryName(cat, this.langService.currentLanguage()); }
}

View File

@@ -23,7 +23,7 @@
@if (item()!.photos![selectedPhotoIndex()]?.video) {
<video [src]="item()!.photos![selectedPhotoIndex()].url" controls></video>
} @else {
<img [src]="item()!.photos![selectedPhotoIndex()].url" [alt]="item()!.name" />
<img [src]="item()!.photos![selectedPhotoIndex()].url" [alt]="getItemName()" />
}
</div>
@@ -337,7 +337,7 @@
@if (item()!.photos![selectedPhotoIndex()]?.video) {
<video [src]="item()!.photos![selectedPhotoIndex()].url" controls></video>
} @else {
<img [src]="item()!.photos![selectedPhotoIndex()].url" [alt]="item()!.name" fetchpriority="high" decoding="async" />
<img [src]="item()!.photos![selectedPhotoIndex()].url" [alt]="getItemName()" fetchpriority="high" decoding="async" />
}
} @else {
<div class="dx-no-image">

View File

@@ -218,7 +218,7 @@ export class ItemDetailComponent implements OnInit, OnDestroy {
getSimpleDescription(): string {
const currentItem = this.item();
if (!currentItem) return '';
return currentItem.simpleDescription || currentItem.description || '';
return getTranslatedField(currentItem, 'simpleDescription', this.languageService.currentLanguage());
}
hasDescriptionFields(): boolean {

View File

@@ -105,7 +105,7 @@
</div>
</a>
<button class="add-to-cart-btn" (click)="addToCart(item.itemID, $event)" [attr.aria-label]="('search.addToCart' | translate) + ': ' + item.name">
<button class="add-to-cart-btn" (click)="addToCart(item.itemID, $event)" [attr.aria-label]="('search.addToCart' | translate) + ': ' + itemName(item)">
{{ 'search.addToCart' | translate }}
</button>
</div>

View File

@@ -147,6 +147,23 @@ export class ApiService {
: [],
};
if (raw.names && Array.isArray(raw.names)) {
subcategory.names = raw.names;
subcategory.translations = subcategory.translations || {};
for (const entry of raw.names) {
const lang = this.normalizeLang(entry.language);
const val = entry.value || entry.valuue || '';
if (val) {
if (!subcategory.translations[lang]) subcategory.translations[lang] = {};
subcategory.translations[lang].name = val;
}
}
if (!subcategory.name && raw.names.length > 0) {
const ruName = raw.names.find((n: any) => n.language === 'RU' || n.language === 'ru');
subcategory.name = ruName?.value || ruName?.valuue || raw.names[0].value || raw.names[0].valuue || '';
}
}
return subcategory;
}

View File

@@ -1,5 +1,5 @@
import { Item } from '../models';
import { Category } from '../models/category.model';
import { Category, Subcategory } from '../models/category.model';
export function getDiscountedPrice(item: Item): number {
return item.price * (1 - (item.discount || 0) / 100);
@@ -68,6 +68,9 @@ export function getTranslatedField(
const val = entry?.value || (entry as any)?.valuue || '';
if (val) return val;
}
if (field === 'simpleDescription' && item.translations?.[lang]?.simpleDescription) {
return item.translations[lang].simpleDescription!;
}
// 3. Fallback to base field
if (field === 'name') return item.name;
if (field === 'simpleDescription') return item.simpleDescription || item.description || '';
@@ -77,7 +80,7 @@ export function getTranslatedField(
/**
* Get translated category name for the current language.
*/
export function getTranslatedCategoryName(cat: Category, lang: string): string {
export function getTranslatedCategoryName(cat: Category | Subcategory, lang: string): string {
const translation = cat.translations?.[lang];
if (translation?.name) return translation.name;