language
This commit is contained in:
@@ -2,24 +2,24 @@
|
||||
<div class="card">
|
||||
|
||||
<div class="card__header">
|
||||
<a class="back" routerLink="/" aria-label="Назад">
|
||||
<a class="back" routerLink="/" [attr.aria-label]="'create.back_label' | translate">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M15 18l-6-6 6-6" />
|
||||
</svg>
|
||||
</a>
|
||||
<h1 class="card__title">
|
||||
Новый
|
||||
{{ 'create.title' | translate }}
|
||||
<span class="brand"><span class="brand__fast">fast</span><span class="brand__check">CHECK</span></span>
|
||||
</h1>
|
||||
<p class="card__subtitle">Укажите сумму для пополнения</p>
|
||||
<p class="card__subtitle">{{ 'create.subtitle' | translate }}</p>
|
||||
</div>
|
||||
|
||||
<div class="card__body">
|
||||
|
||||
<!-- Payment methods -->
|
||||
<div class="field">
|
||||
<span class="field__label">Способ оплаты</span>
|
||||
<span class="field__label">{{ 'create.payment_label' | translate }}</span>
|
||||
<div class="methods">
|
||||
<button type="button" class="method" [class.method--active]="payment() === 'sbp'"
|
||||
(click)="selectPayment('sbp', true)" aria-label="СБП">
|
||||
@@ -41,31 +41,26 @@
|
||||
|
||||
<!-- Currencies -->
|
||||
<div class="field">
|
||||
<span class="field__label">Валюта</span>
|
||||
<span class="field__label">{{ 'create.currency_label' | translate }}</span>
|
||||
<div class="currencies">
|
||||
<button type="button" class="chip" [class.chip--active]="currency() === 'RUB'"
|
||||
(click)="selectCurrency('RUB', true)">
|
||||
<!-- <span class="chip__flag">🇷🇺</span> -->
|
||||
<span class="chip__sign">₽</span>
|
||||
<span class="chip__code">RUB</span>
|
||||
</button>
|
||||
<button type="button" class="chip chip--disabled" disabled>
|
||||
<!-- <span class="chip__flag">🇨🇳</span> -->
|
||||
<span class="chip__sign">¥</span>
|
||||
<span class="chip__code">CNY</span>
|
||||
</button>
|
||||
<button type="button" class="chip chip--disabled" disabled>
|
||||
<!-- <span class="chip__flag">🇺🇸</span> -->
|
||||
<span class="chip__sign">$</span>
|
||||
<span class="chip__code">USD</span>
|
||||
</button>
|
||||
<button type="button" class="chip chip--disabled" disabled>
|
||||
<!-- <span class="chip__flag">🇪🇺</span> -->
|
||||
<span class="chip__sign">€</span>
|
||||
<span class="chip__code">EUR</span>
|
||||
</button>
|
||||
<button type="button" class="chip chip--disabled" disabled>
|
||||
<!-- <span class="chip__flag">🇦🇲</span> -->
|
||||
<span class="chip__sign">֏</span>
|
||||
<span class="chip__code">AMD</span>
|
||||
</button>
|
||||
@@ -73,7 +68,7 @@
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="field__label" for="amount">Сумма платежа</label>
|
||||
<label class="field__label" for="amount">{{ 'create.amount_label' | translate }}</label>
|
||||
<div class="input-wrap" [class.input-wrap--error]="error()">
|
||||
<span class="input-wrap__prefix">₽</span>
|
||||
<input
|
||||
@@ -95,13 +90,13 @@
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="field__label" for="note">Примечание</label>
|
||||
<label class="field__label" for="note">{{ 'create.note_label' | translate }}</label>
|
||||
<textarea
|
||||
id="note"
|
||||
class="note-input"
|
||||
[ngModel]="note()"
|
||||
(ngModelChange)="onNoteChange($event)"
|
||||
placeholder="Причина платежа..."
|
||||
[placeholder]="'create.note_placeholder' | translate"
|
||||
rows="3"
|
||||
maxlength="500"
|
||||
></textarea>
|
||||
@@ -115,9 +110,9 @@
|
||||
</svg>
|
||||
</span>
|
||||
@if (loading()) {
|
||||
Создание…
|
||||
{{ 'create.creating' | translate }}
|
||||
} @else {
|
||||
Создать
|
||||
{{ 'create.create_btn' | translate }}
|
||||
<span class="brand"><span class="brand__fast">fast</span><span class="brand__check">CHECK</span></span>
|
||||
}
|
||||
</button>
|
||||
@@ -129,7 +124,7 @@
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
|
||||
</svg>
|
||||
Защищённое соединение
|
||||
{{ 'common.secure' | translate }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Router, RouterLink } from '@angular/router';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { FastcheckService } from '../../fastcheck.service';
|
||||
import { FASTCHECK_API } from '../../api';
|
||||
import { TranslatePipe } from '../../translate/translate.pipe';
|
||||
|
||||
interface CreateFastcheckResponse {
|
||||
fastcheck: string;
|
||||
@@ -17,7 +18,7 @@ type Currency = 'RUB' | 'CNY' | 'USD' | 'EUR' | 'AMD';
|
||||
|
||||
@Component({
|
||||
selector: 'app-create-page',
|
||||
imports: [FormsModule, RouterLink],
|
||||
imports: [FormsModule, RouterLink, TranslatePipe],
|
||||
templateUrl: './create-page.html',
|
||||
styleUrl: './create-page.scss'
|
||||
})
|
||||
|
||||
@@ -5,9 +5,7 @@
|
||||
<img class="card__brand" src="/logo_big.png"
|
||||
alt="fastCHECK" width="220" height="60" />
|
||||
<p class="card__subtitle">
|
||||
Введите данные
|
||||
<span class="brand"><span class="brand__fast">fast</span><span class="brand__check">CHECK</span></span>
|
||||
или создайте новый
|
||||
{{ 'fastcheck.subtitle' | translate }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -16,8 +14,7 @@
|
||||
<!-- Fastcheck number + new -->
|
||||
<div class="field">
|
||||
<label class="field__label" for="fcNumber">
|
||||
Номер
|
||||
<span class="brand"><span class="brand__fast">fast</span><span class="brand__check">CHECK</span></span>
|
||||
{{ 'fastcheck.number_label' | translate }}
|
||||
</label>
|
||||
<div class="row">
|
||||
<input
|
||||
@@ -26,18 +23,18 @@
|
||||
class="input"
|
||||
[ngModel]="fastcheckNumber()"
|
||||
(ngModelChange)="onNumberChange($event)"
|
||||
placeholder="1234-5678-0001"
|
||||
[placeholder]="'fastcheck.number_placeholder' | translate"
|
||||
inputmode="numeric"
|
||||
autocomplete="off"
|
||||
maxlength="14"
|
||||
/>
|
||||
<a class="btn btn--ghost" routerLink="/new" aria-label="Создать новый fastCHECK">Новый</a>
|
||||
<a class="btn btn--ghost" routerLink="/new" aria-label="Создать новый fastCHECK">{{ 'fastcheck.number_new' | translate }}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Amount -->
|
||||
<div class="field">
|
||||
<label class="field__label" for="fcAmount">Сумма</label>
|
||||
<label class="field__label" for="fcAmount">{{ 'fastcheck.amount_label' | translate }}</label>
|
||||
<div class="input-wrap">
|
||||
<span class="input-wrap__prefix">₽</span>
|
||||
<input
|
||||
@@ -54,20 +51,20 @@
|
||||
/>
|
||||
</div>
|
||||
@if (amountLoading()) {
|
||||
<span class="field__hint">Проверяем…</span>
|
||||
<span class="field__hint">{{ 'fastcheck.amount_checking' | translate }}</span>
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- Code -->
|
||||
<div class="field">
|
||||
<label class="field__label" for="fcCode">Код</label>
|
||||
<label class="field__label" for="fcCode">{{ 'fastcheck.code_label' | translate }}</label>
|
||||
<input
|
||||
id="fcCode"
|
||||
type="text"
|
||||
class="input"
|
||||
[ngModel]="fastcheckCode()"
|
||||
(ngModelChange)="onCodeChange($event)"
|
||||
placeholder="00000"
|
||||
[placeholder]="'fastcheck.code_placeholder' | translate"
|
||||
inputmode="numeric"
|
||||
maxlength="5"
|
||||
autocomplete="one-time-code"
|
||||
@@ -85,7 +82,7 @@
|
||||
<line x1="1" y1="10" x2="23" y2="10" />
|
||||
</svg>
|
||||
</span>
|
||||
Оплатить
|
||||
{{ 'fastcheck.pay_btn' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -95,7 +92,7 @@
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
|
||||
</svg>
|
||||
Защищённое соединение
|
||||
{{ 'common.secure' | translate }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -113,21 +110,21 @@
|
||||
stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M20 6L9 17l-5-5" />
|
||||
</svg>
|
||||
<h2 class="modal__title">Оплачено</h2>
|
||||
<h2 class="modal__title">{{ 'fastcheck.modal_paid_title' | translate }}</h2>
|
||||
<p class="modal__sub">
|
||||
<span class="brand"><span class="brand__fast">fast</span><span class="brand__check">CHECK</span></span>
|
||||
успешно принят.
|
||||
{{ 'fastcheck.modal_paid_sub' | translate }}
|
||||
</p>
|
||||
</div>
|
||||
} @else {
|
||||
<img class="brand-logo brand-logo--small" src="/logo_small.png"
|
||||
alt="fastCHECK" width="32" height="32" />
|
||||
<h2 class="modal__title">Войти через Telegram</h2>
|
||||
<p class="modal__sub">Отсканируйте QR или откройте ссылку</p>
|
||||
<h2 class="modal__title">{{ 'fastcheck.modal_title' | translate }}</h2>
|
||||
<p class="modal__sub">{{ 'fastcheck.modal_sub' | translate }}</p>
|
||||
|
||||
<div class="qr">
|
||||
@if (popupLoading() && !webSessionId()) {
|
||||
<div class="qr__placeholder">Загрузка…</div>
|
||||
<div class="qr__placeholder">{{ 'fastcheck.modal_loading' | translate }}</div>
|
||||
} @else if (webSessionId()) {
|
||||
<img [src]="qrUrl()" width="240" height="240" alt="QR Telegram" />
|
||||
}
|
||||
@@ -138,14 +135,14 @@
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M9.04 15.65l-.36 4.06c.51 0 .73-.22.99-.48l2.38-2.27 4.93 3.6c.9.5 1.55.24 1.79-.83l3.24-15.18h.01c.29-1.34-.48-1.86-1.36-1.54L1.13 9.66c-1.32.5-1.3 1.23-.22 1.56l4.92 1.53L17.27 5.6c.54-.34 1.03-.15.62.19" />
|
||||
</svg>
|
||||
Открыть в Telegram
|
||||
{{ 'fastcheck.modal_open_tg' | translate }}
|
||||
</a>
|
||||
}
|
||||
|
||||
@if (popupLoading() && webSessionId()) {
|
||||
<p class="modal__hint">Подтверждение оплаты…</p>
|
||||
<p class="modal__hint">{{ 'fastcheck.modal_confirming' | translate }}</p>
|
||||
} @else if (webSessionId()) {
|
||||
<p class="modal__hint">Ожидание входа…</p>
|
||||
<p class="modal__hint">{{ 'fastcheck.modal_waiting' | translate }}</p>
|
||||
}
|
||||
|
||||
@if (popupError()) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Router, RouterLink } from '@angular/router';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { FastcheckService } from '../../fastcheck.service';
|
||||
import { FASTCHECK_API } from '../../api';
|
||||
import { TranslatePipe } from '../../translate/translate.pipe';
|
||||
|
||||
interface WebSessionResponse {
|
||||
sessionId: string;
|
||||
@@ -22,7 +23,7 @@ interface CheckFastcheckResponse {
|
||||
|
||||
@Component({
|
||||
selector: 'app-fastcheck-page',
|
||||
imports: [FormsModule, RouterLink],
|
||||
imports: [FormsModule, RouterLink, TranslatePipe],
|
||||
templateUrl: './fastcheck-page.html',
|
||||
styleUrl: './fastcheck-page.scss'
|
||||
})
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
<img src="https://sbp.nspk.ru/storage/settings/common/logo/0645d335-8b62-43a1-9a33-0d4c9d1dc0e0.svg"
|
||||
alt="СБП" />
|
||||
</div>
|
||||
<h1 class="card__title">Оплата через СБП</h1>
|
||||
<p class="card__subtitle">Система быстрых платежей</p>
|
||||
<h1 class="card__title">{{ 'sbp.title' | translate }}</h1>
|
||||
<p class="card__subtitle">{{ 'sbp.subtitle' | translate }}</p>
|
||||
</div>
|
||||
|
||||
<div class="card__body">
|
||||
|
||||
<div class="field">
|
||||
<label class="field__label" for="amount">Сумма платежа</label>
|
||||
<label class="field__label" for="amount">{{ 'sbp.amount_label' | translate }}</label>
|
||||
<div class="input-wrap" [class.input-wrap--error]="error()">
|
||||
<span class="input-wrap__prefix">₽</span>
|
||||
<input
|
||||
@@ -37,17 +37,17 @@
|
||||
<div class="currency-badge">
|
||||
<span class="currency-badge__flag">🇷🇺</span>
|
||||
<span class="currency-badge__code">RUB</span>
|
||||
<span class="currency-badge__name">Российский рубль</span>
|
||||
<span class="currency-badge__name">{{ 'sbp.currency_name' | translate }}</span>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="field__label" for="note">Примечание</label>
|
||||
<label class="field__label" for="note">{{ 'sbp.note_label' | translate }}</label>
|
||||
<textarea
|
||||
id="note"
|
||||
class="note-input"
|
||||
[ngModel]="note()"
|
||||
(ngModelChange)="onNoteChange($event)"
|
||||
placeholder="Причина платежа..."
|
||||
[placeholder]="'sbp.note_placeholder' | translate"
|
||||
rows="3"
|
||||
maxlength="500"
|
||||
></textarea>
|
||||
@@ -61,7 +61,11 @@
|
||||
<line x1="1" y1="10" x2="23" y2="10" />
|
||||
</svg>
|
||||
</span>
|
||||
{{ loading() ? 'Подождите...' : 'Перейти к оплате' }}
|
||||
@if (loading()) {
|
||||
{{ 'sbp.pay_loading' | translate }}
|
||||
} @else {
|
||||
{{ 'sbp.pay_btn' | translate }}
|
||||
}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -71,7 +75,7 @@
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
|
||||
</svg>
|
||||
Защищённое соединение
|
||||
{{ 'common.secure' | translate }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Component, computed, inject, signal } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { TranslatePipe } from '../../translate/translate.pipe';
|
||||
|
||||
interface LegacyPayResponse {
|
||||
payload?: string;
|
||||
@@ -17,7 +18,7 @@ interface LegacyPayResponse {
|
||||
*/
|
||||
@Component({
|
||||
selector: 'app-legacy-pay-page',
|
||||
imports: [FormsModule],
|
||||
imports: [FormsModule, TranslatePipe],
|
||||
templateUrl: './legacy-pay-page.html',
|
||||
styleUrl: './legacy-pay-page.scss'
|
||||
})
|
||||
|
||||
@@ -9,23 +9,20 @@
|
||||
<span class="wm-fast">fast</span><span class="wm-check">CHECK</span>
|
||||
</span>
|
||||
</a>
|
||||
<p class="site-footer__desc" id="about">
|
||||
Инновационный сервис виртуальных чеков для физических лиц.
|
||||
Создавайте цифровые чеки онлайн и обналичивайте их через банкоматы банков-партнёров 24/7.
|
||||
</p>
|
||||
<p class="site-footer__desc" id="about">{{ 'footer.desc' | translate }}</p>
|
||||
</div>
|
||||
|
||||
<!-- Contacts -->
|
||||
<div class="site-footer__col" id="contacts">
|
||||
<h3 class="site-footer__heading">Контакты</h3>
|
||||
<h3 class="site-footer__heading">{{ 'footer.contacts_heading' | translate }}</h3>
|
||||
<ul class="site-footer__list">
|
||||
<li>
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07A19.5 19.5 0 0 1 4.07 10.5a19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 3 2h3a2 2 0 0 1 2 1.72c.127.96.361 1.903.7 2.81a2 2 0 0 1-.45 2.11L7.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.907.339 1.85.573 2.81.7A2 2 0 0 1 21 16.92z"/></svg>
|
||||
<a href="tel:+79299037443">+7 (929) 903-74-43</a> <span class="site-footer__note">Россия</span>
|
||||
<a href="tel:+79299037443">+7 (929) 903-74-43</a> <span class="site-footer__note">{{ 'footer.russia' | translate }}</span>
|
||||
</li>
|
||||
<li>
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07A19.5 19.5 0 0 1 4.07 10.5a19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 3 2h3a2 2 0 0 1 2 1.72c.127.96.361 1.903.7 2.81a2 2 0 0 1-.45 2.11L7.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.907.339 1.85.573 2.81.7A2 2 0 0 1 21 16.92z"/></svg>
|
||||
<a href="tel:+37498632421">+374 98 632421</a> <span class="site-footer__note">Армения</span>
|
||||
<a href="tel:+37498632421">+374 98 632421</a> <span class="site-footer__note">{{ 'footer.armenia' | translate }}</span>
|
||||
</li>
|
||||
<li>
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg>
|
||||
@@ -33,28 +30,28 @@
|
||||
</li>
|
||||
</ul>
|
||||
<div class="site-footer__hours">
|
||||
<p><strong>Техподдержка:</strong> 24/7</p>
|
||||
<p><strong>Вопросы:</strong> 10:00–19:00 МСК</p>
|
||||
<p><strong>{{ 'footer.support_label' | translate }}:</strong> {{ 'footer.support_hours' | translate }}</p>
|
||||
<p><strong>{{ 'footer.questions_label' | translate }}:</strong> {{ 'footer.questions_hours' | translate }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Legal -->
|
||||
<div class="site-footer__col">
|
||||
<h3 class="site-footer__heading">Реквизиты</h3>
|
||||
<h3 class="site-footer__heading">{{ 'footer.legal_heading' | translate }}</h3>
|
||||
<ul class="site-footer__list site-footer__list--legal">
|
||||
<li>ООО «ВИАЭКСПОРТ»</li>
|
||||
<li>ИНН (РФ): 9909675800</li>
|
||||
<li>ИНН (AM): 01051049</li>
|
||||
<li>КПП: 770287001</li>
|
||||
<li>ОГРН: 282.110.1296681</li>
|
||||
<li class="site-footer__address">Армения, 0201, Ереван,<br>ул. Минская, дом 21-23, кв. 44</li>
|
||||
<li>{{ 'footer.legal_company' | translate }}</li>
|
||||
<li>{{ 'footer.legal_inn_ru' | translate }}</li>
|
||||
<li>{{ 'footer.legal_inn_am' | translate }}</li>
|
||||
<li>{{ 'footer.legal_kpp' | translate }}</li>
|
||||
<li>{{ 'footer.legal_ogrn' | translate }}</li>
|
||||
<li class="site-footer__address">{{ 'footer.legal_address' | translate }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="site-footer__bottom">
|
||||
<p>© {{ year }} ООО «ВИАЭКСПОРТ». Все права защищены.</p>
|
||||
<p>Директор: Амирханян Саргис Арташесович</p>
|
||||
<p>© {{ year }} {{ 'footer.rights' | translate }}</p>
|
||||
<p>{{ 'footer.director' | translate }}</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { TranslatePipe } from '../translate/translate.pipe';
|
||||
|
||||
@Component({
|
||||
selector: 'app-site-footer',
|
||||
imports: [TranslatePipe],
|
||||
templateUrl: './site-footer.html',
|
||||
styleUrl: './site-footer.scss'
|
||||
})
|
||||
|
||||
@@ -10,16 +10,23 @@
|
||||
</a>
|
||||
|
||||
<!-- Desktop nav -->
|
||||
<nav class="site-header__nav" aria-label="Навигация">
|
||||
<a class="site-header__link" href="#about">О сервисе</a>
|
||||
<a class="site-header__link" href="#contacts">Контакты</a>
|
||||
<a class="site-header__link" href="mailto:info@viaexport.store">Поддержка</a>
|
||||
<nav class="site-header__nav" [attr.aria-label]="'header.aria_nav' | translate">
|
||||
<a class="site-header__link" href="#about">{{ 'header.nav_about' | translate }}</a>
|
||||
<a class="site-header__link" href="#contacts">{{ 'header.nav_contacts' | translate }}</a>
|
||||
<a class="site-header__link" href="mailto:info@viaexport.store">{{ 'header.nav_support' | translate }}</a>
|
||||
</nav>
|
||||
|
||||
<!-- Language switcher -->
|
||||
<div class="site-header__langs">
|
||||
<button type="button" class="site-header__lang" [class.site-header__lang--active]="currentLang() === 'ru'" (click)="setLang('ru')">RU</button>
|
||||
<button type="button" class="site-header__lang" [class.site-header__lang--active]="currentLang() === 'en'" (click)="setLang('en')">EN</button>
|
||||
<button type="button" class="site-header__lang" [class.site-header__lang--active]="currentLang() === 'hy'" (click)="setLang('hy')">HY</button>
|
||||
</div>
|
||||
|
||||
<!-- Mobile hamburger -->
|
||||
<button class="site-header__burger" type="button"
|
||||
[attr.aria-expanded]="menuOpen()"
|
||||
aria-label="Меню"
|
||||
[attr.aria-label]="'header.aria_burger' | translate"
|
||||
(click)="toggleMenu()">
|
||||
@if (menuOpen()) {
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
@@ -37,10 +44,15 @@
|
||||
|
||||
<!-- Mobile dropdown -->
|
||||
@if (menuOpen()) {
|
||||
<nav class="site-header__mobile-menu" (click)="closeMenu()" aria-label="Мобильное меню">
|
||||
<a class="site-header__mobile-link" href="#about">О сервисе</a>
|
||||
<a class="site-header__mobile-link" href="#contacts">Контакты</a>
|
||||
<a class="site-header__mobile-link" href="mailto:info@viaexport.store">Поддержка</a>
|
||||
<nav class="site-header__mobile-menu" (click)="closeMenu()" [attr.aria-label]="'header.aria_menu' | translate">
|
||||
<a class="site-header__mobile-link" href="#about">{{ 'header.nav_about' | translate }}</a>
|
||||
<a class="site-header__mobile-link" href="#contacts">{{ 'header.nav_contacts' | translate }}</a>
|
||||
<a class="site-header__mobile-link" href="mailto:info@viaexport.store">{{ 'header.nav_support' | translate }}</a>
|
||||
<div class="site-header__mobile-langs">
|
||||
<button type="button" class="site-header__lang" [class.site-header__lang--active]="currentLang() === 'ru'" (click)="setLang('ru')">RU</button>
|
||||
<button type="button" class="site-header__lang" [class.site-header__lang--active]="currentLang() === 'en'" (click)="setLang('en')">EN</button>
|
||||
<button type="button" class="site-header__lang" [class.site-header__lang--active]="currentLang() === 'hy'" (click)="setLang('hy')">HY</button>
|
||||
</div>
|
||||
</nav>
|
||||
}
|
||||
</header>
|
||||
|
||||
@@ -71,6 +71,44 @@
|
||||
}
|
||||
}
|
||||
|
||||
&__langs {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
margin-left: 8px;
|
||||
|
||||
@media (max-width: 600px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&__lang {
|
||||
padding: 5px 8px;
|
||||
border-radius: 6px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.04em;
|
||||
color: #94a3b8;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s, color 0.15s;
|
||||
font-family: inherit;
|
||||
|
||||
&:hover { background: #f1f5f9; color: #475569; }
|
||||
|
||||
&--active {
|
||||
background: #eff6ff;
|
||||
color: #1e40af;
|
||||
}
|
||||
}
|
||||
|
||||
&__mobile-langs {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
padding: 8px 14px 4px;
|
||||
}
|
||||
|
||||
&__burger {
|
||||
display: none;
|
||||
margin-left: auto;
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
import { Component, signal } from '@angular/core';
|
||||
import { Component, inject, signal } from '@angular/core';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { TranslatePipe } from '../translate/translate.pipe';
|
||||
import { TranslationService, Lang } from '../translate/translation.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-site-header',
|
||||
imports: [RouterLink],
|
||||
imports: [RouterLink, TranslatePipe],
|
||||
templateUrl: './site-header.html',
|
||||
styleUrl: './site-header.scss'
|
||||
})
|
||||
export class SiteHeader {
|
||||
private i18n = inject(TranslationService);
|
||||
|
||||
menuOpen = signal(false);
|
||||
currentLang = this.i18n.currentLang;
|
||||
|
||||
toggleMenu(): void { this.menuOpen.update(v => !v); }
|
||||
closeMenu(): void { this.menuOpen.set(false); }
|
||||
setLang(lang: Lang): void { this.i18n.setLanguage(lang); }
|
||||
}
|
||||
|
||||
11
src/app/translate/translate.pipe.ts
Normal file
11
src/app/translate/translate.pipe.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { Pipe, PipeTransform, inject } from '@angular/core';
|
||||
import { TranslationService } from './translation.service';
|
||||
|
||||
@Pipe({ name: 'translate', pure: false, standalone: true })
|
||||
export class TranslatePipe implements PipeTransform {
|
||||
private svc = inject(TranslationService);
|
||||
|
||||
transform(key: string): string {
|
||||
return this.svc.translate(key);
|
||||
}
|
||||
}
|
||||
36
src/app/translate/translation.service.ts
Normal file
36
src/app/translate/translation.service.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { Injectable, inject, signal } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
|
||||
export type Lang = 'ru' | 'en' | 'hy';
|
||||
type Translations = Record<string, Record<string, string>>;
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class TranslationService {
|
||||
private http = inject(HttpClient);
|
||||
|
||||
currentLang = signal<Lang>('ru');
|
||||
private translations = signal<Translations>({});
|
||||
|
||||
constructor() {
|
||||
this.load('ru');
|
||||
}
|
||||
|
||||
setLanguage(lang: Lang): void {
|
||||
this.currentLang.set(lang);
|
||||
this.load(lang);
|
||||
}
|
||||
|
||||
private load(lang: Lang): void {
|
||||
this.http.get<Translations>(`/i18n/${lang}.json`).subscribe({
|
||||
next: data => this.translations.set(data),
|
||||
});
|
||||
}
|
||||
|
||||
translate(key: string): string {
|
||||
const dot = key.indexOf('.');
|
||||
if (dot === -1) return key;
|
||||
const section = key.slice(0, dot);
|
||||
const k = key.slice(dot + 1);
|
||||
return this.translations()[section]?.[k] ?? key;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user