1
Some checks failed
Deploy / deploy (push) Has been cancelled

This commit is contained in:
ssww23
2026-03-17 01:59:00 +03:00
parent 93a655235a
commit 0ee9f05416
48 changed files with 1193 additions and 413 deletions

View File

@@ -0,0 +1,20 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class LocaleController extends Controller
{
public function __invoke(Request $request, string $locale): RedirectResponse
{
$supportedLocales = array_keys((array) config('app.supported_locales', []));
abort_unless(in_array($locale, $supportedLocales, true), 404);
$request->session()->put('locale', $locale);
return back();
}
}

View File

@@ -28,6 +28,6 @@ class AccountController extends Controller
$request->user()->update($validated); $request->user()->update($validated);
return back()->with('status', 'Данные профиля обновлены.'); return back()->with('status', __('Данные профиля обновлены.'));
} }
} }

View File

@@ -34,7 +34,7 @@ class AuthController extends Controller
if (!$this->captchaIsValid($request, self::LOGIN_CAPTCHA_CONTEXT)) { if (!$this->captchaIsValid($request, self::LOGIN_CAPTCHA_CONTEXT)) {
return back() return back()
->withInput($request->only('email', 'remember')) ->withInput($request->only('email', 'remember'))
->withErrors(['captcha' => 'Неверный ответ на капчу.']); ->withErrors(['captcha' => __('Неверный ответ на капчу.')]);
} }
$credentials = [ $credentials = [
@@ -47,7 +47,7 @@ class AuthController extends Controller
if (!Auth::attempt($credentials, $remember)) { if (!Auth::attempt($credentials, $remember)) {
return back() return back()
->withInput($request->only('email', 'remember')) ->withInput($request->only('email', 'remember'))
->withErrors(['email' => 'Неверный email или пароль.']); ->withErrors(['email' => __('Неверный email или пароль.')]);
} }
$request->session()->regenerate(); $request->session()->regenerate();
@@ -75,7 +75,7 @@ class AuthController extends Controller
if (!$this->captchaIsValid($request, self::REGISTER_CAPTCHA_CONTEXT)) { if (!$this->captchaIsValid($request, self::REGISTER_CAPTCHA_CONTEXT)) {
return back() return back()
->withInput($request->only('name', 'email')) ->withInput($request->only('name', 'email'))
->withErrors(['captcha' => 'Неверный ответ на капчу.']); ->withErrors(['captcha' => __('Неверный ответ на капчу.')]);
} }
$user = User::create([ $user = User::create([

View File

@@ -46,20 +46,20 @@ class CartController extends Controller
public function add(Product $product) public function add(Product $product)
{ {
if (!$product->is_active || $product->stock < 1) { if (!$product->is_active || $product->stock < 1) {
return back()->with('status', 'Товар сейчас недоступен для заказа.'); return back()->with('status', __('Товар сейчас недоступен для заказа.'));
} }
$cart = (array) session()->get('cart', []); $cart = (array) session()->get('cart', []);
$current = (int) ($cart[$product->id] ?? 0); $current = (int) ($cart[$product->id] ?? 0);
if ($current >= $product->stock) { if ($current >= $product->stock) {
return back()->with('status', 'В корзине уже максимальное доступное количество.'); return back()->with('status', __('В корзине уже максимальное доступное количество.'));
} }
$cart[$product->id] = $current + 1; $cart[$product->id] = $current + 1;
session()->put('cart', $cart); session()->put('cart', $cart);
return back()->with('status', "Товар \"{$product->name}\" добавлен в корзину."); return back()->with('status', __('Товар ":name" добавлен в корзину.', ['name' => $product->name]));
} }
public function update(Request $request, Product $product) public function update(Request $request, Product $product)
@@ -80,15 +80,15 @@ class CartController extends Controller
unset($cart[$product->id]); unset($cart[$product->id]);
session()->put('cart', $cart); session()->put('cart', $cart);
return back()->with('status', "Товар \"{$product->name}\" удален из корзины."); return back()->with('status', __('Товар ":name" удален из корзины.', ['name' => $product->name]));
} }
$cart[$product->id] = $quantity; $cart[$product->id] = $quantity;
session()->put('cart', $cart); session()->put('cart', $cart);
$message = $quantity < (int) $validated['quantity'] $message = $quantity < (int) $validated['quantity']
? 'Количество ограничено текущим остатком.' ? __('Количество ограничено текущим остатком.')
: 'Количество товара обновлено.'; : __('Количество товара обновлено.');
return back()->with('status', $message); return back()->with('status', $message);
} }
@@ -101,6 +101,6 @@ class CartController extends Controller
session()->put('cart', $cart); session()->put('cart', $cart);
} }
return back()->with('status', "Товар \"{$product->name}\" удален из корзины."); return back()->with('status', __('Товар ":name" удален из корзины.', ['name' => $product->name]));
} }
} }

View File

@@ -40,7 +40,7 @@ class ChatController extends Controller
$messageText = $this->sanitizeMessage((string) $validated['message']); $messageText = $this->sanitizeMessage((string) $validated['message']);
if ($messageText === '') { if ($messageText === '') {
throw ValidationException::withMessages([ throw ValidationException::withMessages([
'message' => 'Сообщение содержит недопустимые символы.', 'message' => __('Сообщение содержит недопустимые символы.'),
]); ]);
} }
@@ -156,7 +156,7 @@ class ChatController extends Controller
'status' => $conversation->status, 'status' => $conversation->status,
'is_closed' => $conversation->isClosed(), 'is_closed' => $conversation->isClosed(),
'notice' => $conversation->isClosed() 'notice' => $conversation->isClosed()
? 'Чат закрыт администратором. Отправьте новое сообщение, чтобы начать новый диалог.' ? __('Чат закрыт администратором. Отправьте новое сообщение, чтобы начать новый диалог.')
: null, : null,
]; ];
} }

View File

@@ -19,7 +19,7 @@ class CheckoutController extends Controller
$items = $this->cartItems($request); $items = $this->cartItems($request);
if ($items->isEmpty()) { if ($items->isEmpty()) {
return redirect()->route('cart.index')->with('status', 'Корзина пустая. Добавьте товары перед оформлением.'); return redirect()->route('cart.index')->with('status', __('Корзина пустая. Добавьте товары перед оформлением.'));
} }
return view('shop.checkout', [ return view('shop.checkout', [
@@ -34,7 +34,7 @@ class CheckoutController extends Controller
$items = $this->cartItems($request); $items = $this->cartItems($request);
if ($items->isEmpty()) { if ($items->isEmpty()) {
return redirect()->route('cart.index')->with('status', 'Корзина пустая. Добавьте товары перед оформлением.'); return redirect()->route('cart.index')->with('status', __('Корзина пустая. Добавьте товары перед оформлением.'));
} }
$validated = $request->validate([ $validated = $request->validate([
@@ -56,12 +56,12 @@ class CheckoutController extends Controller
$items = $this->cartItems($request); $items = $this->cartItems($request);
if ($items->isEmpty()) { if ($items->isEmpty()) {
return redirect()->route('cart.index')->with('status', 'Корзина пустая. Добавьте товары перед оформлением.'); return redirect()->route('cart.index')->with('status', __('Корзина пустая. Добавьте товары перед оформлением.'));
} }
$customer = $request->session()->get(self::CHECKOUT_CUSTOMER_KEY); $customer = $request->session()->get(self::CHECKOUT_CUSTOMER_KEY);
if (!is_array($customer)) { if (!is_array($customer)) {
return redirect()->route('checkout.show')->with('status', 'Сначала заполните данные получателя.'); return redirect()->route('checkout.show')->with('status', __('Сначала заполните данные получателя.'));
} }
return view('shop.checkout-payment', [ return view('shop.checkout-payment', [
@@ -77,12 +77,12 @@ class CheckoutController extends Controller
$items = $this->cartItems($request); $items = $this->cartItems($request);
if ($items->isEmpty()) { if ($items->isEmpty()) {
return redirect()->route('cart.index')->with('status', 'Корзина пустая. Добавьте товары перед оформлением.'); return redirect()->route('cart.index')->with('status', __('Корзина пустая. Добавьте товары перед оформлением.'));
} }
$validated = $request->session()->get(self::CHECKOUT_CUSTOMER_KEY); $validated = $request->session()->get(self::CHECKOUT_CUSTOMER_KEY);
if (!is_array($validated)) { if (!is_array($validated)) {
return redirect()->route('checkout.show')->with('status', 'Сначала заполните данные получателя.'); return redirect()->route('checkout.show')->with('status', __('Сначала заполните данные получателя.'));
} }
$validator = validator($validated, [ $validator = validator($validated, [

View File

@@ -44,24 +44,24 @@ class CompareController extends Controller
$compare = array_values(array_filter($compare, fn (int $id) => $id !== $product->id)); $compare = array_values(array_filter($compare, fn (int $id) => $id !== $product->id));
session()->put('compare', $compare); session()->put('compare', $compare);
return back()->with('status', "Товар \"{$product->name}\" удален из сравнения."); return back()->with('status', __('Товар ":name" удален из сравнения.', ['name' => $product->name]));
} }
if (count($compare) >= 4) { if (count($compare) >= 4) {
return back()->with('status', 'Можно сравнить не более 4 товаров одновременно.'); return back()->with('status', __('Можно сравнить не более 4 товаров одновременно.'));
} }
$compare[] = $product->id; $compare[] = $product->id;
session()->put('compare', array_values(array_unique($compare))); session()->put('compare', array_values(array_unique($compare)));
return back()->with('status', "Товар \"{$product->name}\" добавлен в сравнение."); return back()->with('status', __('Товар ":name" добавлен в сравнение.', ['name' => $product->name]));
} }
public function clear() public function clear()
{ {
session()->forget('compare'); session()->forget('compare');
return back()->with('status', 'Список сравнения очищен.'); return back()->with('status', __('Список сравнения очищен.'));
} }
private function compareIds(): array private function compareIds(): array

View File

@@ -24,7 +24,7 @@ class ContactController extends Controller
if ($botToken === '' || $chatId === '') { if ($botToken === '' || $chatId === '') {
return back() return back()
->withInput() ->withInput()
->withErrors(['contact' => 'Не настроена отправка в Telegram. Заполните SHOP_TELEGRAM_BOT_TOKEN и SHOP_TELEGRAM_CHAT_ID.']); ->withErrors(['contact' => __('Не настроена отправка в Telegram. Заполните SHOP_TELEGRAM_BOT_TOKEN и SHOP_TELEGRAM_CHAT_ID.')]);
} }
$message = $this->buildTelegramMessage($validated, $request); $message = $this->buildTelegramMessage($validated, $request);
@@ -41,16 +41,16 @@ class ContactController extends Controller
} catch (Throwable) { } catch (Throwable) {
return back() return back()
->withInput() ->withInput()
->withErrors(['contact' => 'Не удалось отправить заявку в Telegram. Попробуйте еще раз.']); ->withErrors(['contact' => __('Не удалось отправить заявку в Telegram. Попробуйте еще раз.')]);
} }
if (!$response->successful() || $response->json('ok') !== true) { if (!$response->successful() || $response->json('ok') !== true) {
return back() return back()
->withInput() ->withInput()
->withErrors(['contact' => 'Telegram не принял заявку. Проверьте токен бота и chat id.']); ->withErrors(['contact' => __('Telegram не принял заявку. Проверьте токен бота и chat id.')]);
} }
return back()->with('status', 'Заявка отправлена. Мы свяжемся с вами в ближайшее время.'); return back()->with('status', __('Заявка отправлена. Мы свяжемся с вами в ближайшее время.'));
} }
private function buildTelegramMessage(array $data, Request $request): string private function buildTelegramMessage(array $data, Request $request): string

View File

@@ -34,13 +34,13 @@ class FavoriteController extends Controller
$favorites = array_values(array_filter($favorites, fn (int $id) => $id !== $product->id)); $favorites = array_values(array_filter($favorites, fn (int $id) => $id !== $product->id));
session()->put('favorites', $favorites); session()->put('favorites', $favorites);
return back()->with('status', "Товар \"{$product->name}\" удален из избранного."); return back()->with('status', __('Товар ":name" удален из избранного.', ['name' => $product->name]));
} }
$favorites[] = $product->id; $favorites[] = $product->id;
session()->put('favorites', array_values(array_unique($favorites))); session()->put('favorites', array_values(array_unique($favorites)));
return back()->with('status', "Товар \"{$product->name}\" добавлен в избранное."); return back()->with('status', __('Товар ":name" добавлен в избранное.', ['name' => $product->name]));
} }
private function favoriteIds(): array private function favoriteIds(): array

View File

@@ -0,0 +1,25 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class SetLocale
{
public function handle(Request $request, Closure $next): Response
{
$supportedLocales = array_keys((array) config('app.supported_locales', []));
$defaultLocale = (string) config('app.locale', 'ru');
$locale = (string) $request->session()->get('locale', $defaultLocale);
if (!in_array($locale, $supportedLocales, true)) {
$locale = $defaultLocale;
}
app()->setLocale($locale);
return $next($request);
}
}

View File

@@ -47,7 +47,7 @@ class ChatConversation extends Model
return $this->user->name; return $this->user->name;
} }
return 'Гость #' . $this->id; return __('Гость #:number', ['number' => $this->id]);
} }
public function isClosed(): bool public function isClosed(): bool

View File

@@ -43,8 +43,21 @@ class Order extends Model
public function getPaymentMethodLabelAttribute(): string public function getPaymentMethodLabelAttribute(): string
{ {
return match ($this->payment_method) { return match ($this->payment_method) {
'card_transfer' => 'Перевод по реквизитам (на карту)', 'card_transfer' => __('Перевод по реквизитам (на карту)'),
default => 'Не указан', default => __('Не указан'),
};
}
public function getStatusLabelAttribute(): string
{
return match ($this->status) {
'new' => __('Новый'),
'processing' => __('В обработке'),
'paid' => __('Оплачен'),
'shipped' => __('Отправлен'),
'completed' => __('Завершен'),
'cancelled' => __('Отменен'),
default => (string) $this->status,
}; };
} }
} }

View File

@@ -1,5 +1,6 @@
<?php <?php
use App\Http\Middleware\SetLocale;
use Illuminate\Foundation\Application; use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions; use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware; use Illuminate\Foundation\Configuration\Middleware;
@@ -11,7 +12,9 @@ return Application::configure(basePath: dirname(__DIR__))
health: '/up', health: '/up',
) )
->withMiddleware(function (Middleware $middleware): void { ->withMiddleware(function (Middleware $middleware): void {
// $middleware->web(append: [
SetLocale::class,
]);
}) })
->withExceptions(function (Exceptions $exceptions): void { ->withExceptions(function (Exceptions $exceptions): void {
// //

View File

@@ -78,11 +78,30 @@ return [
| |
*/ */
'locale' => env('APP_LOCALE', 'en'), 'locale' => env('APP_LOCALE', 'ru'),
'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'), 'fallback_locale' => env('APP_FALLBACK_LOCALE', 'ru'),
'faker_locale' => env('APP_FAKER_LOCALE', 'en_US'), 'faker_locale' => env('APP_FAKER_LOCALE', 'ru_RU'),
'supported_locales' => [
'ru' => [
'label' => 'Русский',
'native' => 'Русский',
'short' => 'Рус',
'flag' => '🇷🇺',
'hreflang' => 'ru-RU',
'og_locale' => 'ru_RU',
],
'kk' => [
'label' => 'Kazakh',
'native' => 'Қазақша',
'short' => 'Қаз',
'flag' => '🇰🇿',
'hreflang' => 'kk-KZ',
'og_locale' => 'kk_KZ',
],
],
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------

View File

@@ -1,7 +1,7 @@
server { server {
listen 80; listen 80;
listen [::]:80; listen [::]:80;
server_name shop.example.com www.shop.example.com; server_name tehnobox.shop www.tehnobox.shop;
root /var/www/pc-shop/public; root /var/www/pc-shop/public;
location ^~ /.well-known/acme-challenge/ { location ^~ /.well-known/acme-challenge/ {
@@ -17,12 +17,12 @@ server {
server { server {
listen 443 ssl http2; listen 443 ssl http2;
listen [::]:443 ssl http2; listen [::]:443 ssl http2;
server_name shop.example.com www.shop.example.com; server_name tehnobox.shop www.tehnobox.shop;
root /var/www/pc-shop/public; root /var/www/pc-shop/public;
index index.php; index index.php;
ssl_certificate /etc/letsencrypt/live/shop.example.com/fullchain.pem; ssl_certificate /etc/letsencrypt/live/tehnobox.shop/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/shop.example.com/privkey.pem; ssl_certificate_key /etc/letsencrypt/live/tehnobox.shop/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf; include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

402
lang/kk.json Normal file
View File

@@ -0,0 +1,402 @@
{
"(c) :year :company. Все права защищены.": "(c) :year :company. Барлық құқықтар қорғалған.",
"1-3 дня по стране": "Ел бойынша 1-3 күн",
"8 ядер, 16 потоков, до 5.4 ГГц.": "8 ядро, 16 ағын, 5.4 ГГц-ке дейін.",
"12 ГБ GDDR6X, DLSS 3.": "12 ГБ GDDR6X, DLSS 3.",
"13.5\\\", компактный ультрабук.": "13.5\\\", ықшам ультрабук.",
"13.6\\\", чип M2, 8/256 ГБ.": "13.6\\\", M2 чипі, 8/256 ГБ.",
"14\\\", легкий для работы.": "14\\\", жұмысқа жеңіл.",
"15.6\\\", Ryzen 7, RTX 4060.": "15.6\\\", Ryzen 7, RTX 4060.",
"16 ГБ GDDR6, отличная производительность.": "16 ГБ GDDR6, жоғары өнімділік.",
"16 ядер, для мощных систем.": "16 ядро, қуатты жүйелерге арналған.",
"43\\\", 4K UHD, Android TV.": "43\\\", 4K UHD, Android TV.",
"50\\\", NanoCell, webOS.": "50\\\", NanoCell, webOS.",
"55\\\", 4K UHD, Smart TV.": "55\\\", 4K UHD, Smart TV.",
"6.1\\\", 128 ГБ, отличное состояние.": "6.1\\\", 128 ГБ, өте жақсы күйде.",
"650 Вт, стабильная линия питания.": "650 Вт, тұрақты қорек желісі.",
"750 Вт, 80 Plus Gold.": "750 Вт, 80 Plus Gold.",
"850 Вт, тихий режим работы.": "850 Вт, тыныш жұмыс режимі.",
":category, комплектующие, купить, фильтры товаров": ":category, жинақтаушы, сатып алу, тауар сүзгілері",
":company работает для тех, кому важно собрать быстрый и надежный ПК без ошибок по совместимости. В каталоге есть комплектующие для домашних, рабочих и игровых систем: процессоры, материнские платы, видеокарты, память, накопители, блоки питания, корпуса, системы охлаждения, ноутбуки и периферия.": ":company үйлесімділік қателерінсіз жылдам әрі сенімді ПК жинау маңызды адамдар үшін жұмыс істейді. Каталогта үйге, жұмысқа және ойынға арналған жүйелерге керек бөлшектер бар: процессорлар, аналық платалар, бейнекарталар, жад, жинақтауыштар, қуат блоктары, корпустар, салқындату жүйелері, ноутбуктер және периферия.",
":company — интернет-магазин компьютерных комплектующих.": ":company — компьютер бөлшектері интернет-дүкені.",
":company — поддержка клиентов": ":company — клиенттерге қолдау",
":label: :from - :to": ":label: :from - :to",
":product - миниатюра :number": ":product - миниатюра :number",
":product - фото :number": ":product - сурет :number",
":product, :category, купить": ":product, :category, сатып алу",
"AM5, усиленное питание, PCIe 4.0.": "AM5, күшейтілген қорек, PCIe 4.0.",
"ATX, сетчатый фронт.": "ATX, торлы алдыңғы панель.",
"Apple": "Apple",
"Smart TV": "Smart TV",
"Telegram не принял заявку. Проверьте токен бота и chat id.": "Telegram өтінімді қабылдамады. Бот токені мен chat id тексеріңіз.",
"Telegram": "Telegram",
"DDR4 3200 МГц, 2x8 ГБ.": "DDR4 3200 МГц, 2x8 ГБ.",
"DDR4 3600 МГц, 2x16 ГБ.": "DDR4 3600 МГц, 2x16 ГБ.",
"DDR5 6000 МГц, 2x16 ГБ.": "DDR5 6000 МГц, 2x16 ГБ.",
"GPU": "GPU",
"Email": "Email",
"NVMe SSD с высокой скоростью.": "Жоғары жылдамдықты NVMe SSD.",
"SSD и HDD для хранения данных.": "Деректерді сақтауға арналған SSD және HDD.",
"AM5": "AM5",
"Android TV": "Android TV",
"DLSS 3.": "DLSS 3.",
"mATX": "mATX",
"WiFi": "WiFi",
"Wi-Fi": "Wi-Fi",
"Адрес доставки": "Жеткізу мекенжайы",
"Артикул:": "Артикул:",
"Банк": "Банк",
"Банковский перевод": "Банктік аударым",
"Безналичный расчет для юрлиц": "Заңды тұлғаларға қолма-қолсыз есеп айырысу",
"Белый": "Ақ",
"Блоки питания": "Қуат блоктары",
"Блоки питания.": "Қуат блоктары.",
"Быстрая доставка и удобная оплата.": "Жылдам жеткізу және ыңғайлы төлем.",
"Б/у": "Қолданылған",
"В избранное": "Таңдаулыларға",
"В корзине": "Себетте",
"В корзине уже максимальное доступное количество.": "Себетте қолжетімді ең көп саны бар.",
"В корзину": "Себетке",
"В обработке": "Өңделуде",
"В сравнение": "Салыстыруға",
"Варианты доставки": "Жеткізу нұсқалары",
"Ваш заказ": "Сіздің тапсырысыңыз",
"Ваше имя": "Атыңыз",
"Введите email и пароль для доступа к заказам и профилю.": "Тапсырыстар мен профильге кіру үшін email мен құпиясөзді енгізіңіз.",
"Введите запрос в строку поиска, чтобы открыть список найденных товаров.": "Табылған тауарлар тізімін ашу үшін іздеу жолына сұраныс енгізіңіз.",
"Введите название товара, чтобы увидеть найденные позиции.": "Табылған тауарларды көру үшін атауын енгізіңіз.",
"Введите сообщение...": "Хабарлама енгізіңіз...",
"Видеокарты": "Бейнекарталар",
"Войти": "Кіру",
"Вперед": "Алға",
"Все": "Барлығы",
"Все категории": "Барлық санаттар",
"Вход": "Кіру",
"Выбирайте курьера или доставку по времени с безопасной оплатой.": "Курьерді не уақыт бойынша жеткізуді таңдап, қауіпсіз төлем жасаңыз.",
"Выбор языка": "Тілді таңдау",
"Выйти": "Шығу",
"Главная": "Басты бет",
"Гость #:number": "Қонақ №:number",
"Данные аккаунта": "Аккаунт деректері",
"Данные получателя": "Алушы деректері",
"Данные профиля обновлены.": "Профиль деректері жаңартылды.",
"День в день в пределах города": "Қала ішінде сол күні",
"Для нас важны прозрачность и сервис: актуальные цены, понятные характеристики и честная обратная связь. Мы стремимся, чтобы покупка техники была удобной как для новичков, так и для опытных пользователей, которые собирают ПК самостоятельно.": "Біз үшін ашықтық пен сервис маңызды: өзекті бағалар, түсінікті сипаттамалар және адал кері байланыс. Жаңадан бастағандарға да, компьютерді өздері жинайтын тәжірибелі қолданушыларға да техника сатып алу ыңғайлы болғанын қалаймыз.",
"Для этой категории фильтры пока не заданы.": "Бұл санат үшін сүзгілер әлі берілмеген.",
"До": "Дейін",
"Добавить в избранное": "Таңдаулыларға қосу",
"Добавить в сравнение": "Салыстыруға қосу",
"Добавьте товары в избранное из каталога или со страницы товара.": "Тауарларды каталогтан немесе тауар бетінен таңдаулыларға қосыңыз.",
"Добавьте товары в сравнение из карточек каталога.": "Тауарларды каталог карточкаларынан салыстыруға қосыңыз.",
"Добавьте товары из каталога, чтобы оформить заказ.": "Тапсырысты рәсімдеу үшін каталогтан тауар қосыңыз.",
"Дополнительные изображения товара": "Тауардың қосымша суреттері",
"Доставка": "Жеткізу",
"Доставка и оплата": "Жеткізу және төлем",
"Доставка курьером по городу": "Қала бойынша курьермен жеткізу",
"Если вам нужна консультация перед покупкой, команда :company поможет подобрать комплектующие и предложит сбалансированные варианты под ваши задачи.": "Сатып алар алдында кеңес керек болса, :company командасы қажетті бөлшектерді таңдап, міндеттеріңізге сай теңгерімді нұсқаларды ұсынады.",
"Жесткие диски": "Қатты дискілер",
"Жидкостное охлаждение 240 мм.": "240 мм сұйық салқындату.",
"Завершен": "Аяқталды",
"Задайте вопрос — администратор ответит в этом окне.": "Сұрақ қойыңыз — әкімші осы терезеде жауап береді.",
"Заказ #:number": "Тапсырыс №:number",
"Заказ оформлен": "Тапсырыс рәсімделді",
"Заказ №:number успешно оформлен": "Тапсырыс №:number сәтті рәсімделді",
"Закрыть меню": "Мәзірді жабу",
"Заполните контакты и перейдите на страницу с реквизитами для оплаты.": "Байланыс деректерін толтырып, төлем деректемелері бетіне өтіңіз.",
"Запомнить меня": "Мені есте сақтау",
"Запрос: \":query\"": "Сұраныс: \":query\"",
"Зарегистрироваться": "Тіркелу",
"Заявка отправлена. Мы свяжемся с вами в ближайшее время.": "Өтінім жіберілді. Жақын арада хабарласамыз.",
"Золотой": "Алтын түсті",
"Избранное": "Таңдаулылар",
"Избранные товары": "Таңдаулы тауарлар",
"Изменить данные": "Деректерді өзгерту",
"Имя": "Аты",
"Имя получателя": "Алушының аты",
"Интернет-магазин компьютерных комплектующих": "Компьютер бөлшектері интернет-дүкені",
"Интернет-магазин компьютерных комплектующих, ноутбуков и периферии. Подбор, сравнение и заказ в одном месте.": "Компьютер бөлшектері, ноутбуктер және периферия интернет-дүкені. Таңдау, салыстыру және тапсырыс — бәрі бір жерде.",
"Интернет-магазин комплектующих для ПК: процессоры, материнские платы, видеокарты, ноутбуки и периферия.": "ПК бөлшектерінің интернет-дүкені: процессорлар, аналық платалар, бейнекарталар, ноутбуктер және периферия.",
"Искать": "Іздеу",
"Итого": "Барлығы",
"Кабинет": "Кабинет",
"Как мы помогаем клиентам": "Клиенттерге қалай көмектесеміз",
"Капча: решите пример :question": "Капча: :question мысалын шешіңіз",
"Каталог": "Каталог",
"Каталог компьютерных комплектующих и техники.": "Компьютер бөлшектері мен техниканың каталогы.",
"Каталог компьютерных комплектующих: процессоры, материнские платы, видеокарты, память, накопители и ноутбуки.": "Компьютер бөлшектерінің каталогы: процессорлар, аналық платалар, бейнекарталар, жад, жинақтауыштар және ноутбуктер.",
"Каталог товаров": "Тауарлар каталогы",
"Категории": "Санаттар",
"Категории пока не добавлены.": "Санаттар әлі қосылмаған.",
"Категории товаров": "Тауар санаттары",
"Категория": "Санат",
"Категория товаров :category": ":category санаты",
"Количество вентиляторов": "Желдеткіш саны",
"Количество модулей": "Модуль саны",
"Количество ограничено текущим остатком.": "Саны ағымдағы қалдықпен шектелді.",
"Количество товара обновлено.": "Тауар саны жаңартылды.",
"Количество ядер": "Ядро саны",
"Комментарий к заказу": "Тапсырысқа түсініктеме",
"Комментарий:": "Түсініктеме:",
"Компания": "Компания",
"Компактная mATX для LGA1700.": "LGA1700 үшін ықшам mATX.",
"Компактный и продуваемый.": "Ықшам әрі жақсы желдетіледі.",
"Контакты": "Байланыс",
"Контакты магазина: телефон, email, адрес и часы работы поддержки.": "Дүкен байланыстары: телефон, email, мекенжай және қолдау уақыты.",
"Корзина": "Себет",
"Корзина пустая": "Себет бос",
"Корзина пустая. Добавьте товары перед оформлением.": "Себет бос. Рәсімдеу алдында тауар қосыңыз.",
"Корпуса": "Корпустар",
"Корпуса с отличным airflow.": "Ауа айналымы жақсы корпустар.",
"Кто мы": "Біз кімбіз",
"Купить :product по выгодной цене.": ":product-ті тиімді бағамен сатып алыңыз.",
"Кэш көлемі": "Кэш көлемі",
"Личный кабинет": "Жеке кабинет",
"Макс. длина видеокарты": "Бейнекартаның ең ұзын өлшемі",
"Максимальный объем памяти": "Жадтың ең көп көлемі",
"Максимальный объем памяти (ГБ)": "Жадтың ең көп көлемі (ГБ)",
"Материнские платы": "Аналық платалар",
"Меню": "Мәзір",
"Мини‑корпус для ITX.": "ITX үшін шағын корпус.",
"Модель": "Модель",
"Модель видеокарты": "Бейнекарта моделі",
"Модель процессора": "Процессор моделі",
"Можно сравнить не более 4 товаров одновременно.": "Бір уақытта 4 тауардан артық салыстыруға болмайды.",
"Мои заказы": "Менің тапсырыстарым",
"Мощность": "Қуаты",
"Мы делаем акцент на понятном выборе: категории с фильтрами, сравнение товаров, избранное, корзина и личный кабинет с историей заказов. Это помогает быстрее принять решение и не потерять важные позиции при подборе сборки.": "Біз түсінікті таңдауға мән береміз: сүзгілері бар санаттар, тауарларды салыстыру, таңдаулылар, себет және тапсырыс тарихы бар жеке кабинет. Бұл шешімді тезірек қабылдауға және маңызды позицияларды жоғалтпауға көмектеседі.",
"Мы помогаем подобрать совместимую сборку, оформить заказ и получить технику с понятной поддержкой после покупки.": "Біз үйлесімді жинақ таңдауға, тапсырыс рәсімдеуге және сатып алғаннан кейін түсінікті қолдаумен техниканы алуға көмектесеміз.",
"Мы приняли заказ в обработку. Статус заказа:": "Тапсырысыңызды өңдеуге қабылдадық. Тапсырыс мәртебесі:",
"Назад": "Артқа",
"Назначение платежа:": "Төлем мақсаты:",
"Найденные товары по запросу «:query». Выберите подходящий товар и откройте подробную карточку.": "«:query» сұранысы бойынша табылған тауарлар. Сәйкес тауарды таңдап, толық карточканы ашыңыз.",
"Найдено товаров:": "Табылған тауар саны:",
"Найдено:": "Табылды:",
"Найти": "Іздеу",
"Например, Ryzen 7 или RTX 4060": "Мысалы, Ryzen 7 немесе RTX 4060",
"Начать новый чат": "Жаңа чатты бастау",
"Наш подход": "Біздің ұстаным",
"Не настроена отправка в Telegram. Заполните SHOP_TELEGRAM_BOT_TOKEN и SHOP_TELEGRAM_CHAT_ID.": "Telegram-ға жіберу бапталмаған. SHOP_TELEGRAM_BOT_TOKEN және SHOP_TELEGRAM_CHAT_ID толтырыңыз.",
"Не удалось отправить заявку в Telegram. Попробуйте еще раз.": "Telegram-ға өтінімді жіберу мүмкін болмады. Қайта көріңіз.",
"Не указан": "Көрсетілмеген",
"Неверный email или пароль.": "Email немесе құпиясөз қате.",
"Неверный ответ на капчу.": "Капчаға жауап қате.",
"Надежные блоки питания.": "Сенімді қуат блоктары.",
"Надежные платы для любых конфигураций.": "Кез келген конфигурацияға арналған сенімді платалар.",
"Надежный HDD для хранения.": "Сақтауға арналған сенімді HDD.",
"Нет в наличии": "Қоймада жоқ",
"Новые товары": "Жаңа тауарлар",
"Новый": "Жаңа",
"Новое": "Жаңа",
"Номер заказа будет присвоен после подтверждения": "Тапсырыс нөмірі растаудан кейін беріледі",
"Номер карты": "Карта нөмірі",
"Ноутбуки": "Ноутбуктер",
"Ноутбуки для работы и игр.": "Жұмыс пен ойынға арналған ноутбуктер.",
"О компании": "Компания туралы",
"О компании: помощь в подборе комплектующих, консультации и поддержка при сборке ПК.": "Компания туралы: бөлшектерді таңдауға көмек, кеңес және ПК жинауға қолдау.",
"О нас": "Біз туралы",
"Обновить": "Жаңарту",
"Обновление": "Жаңарту",
"Объем": "Көлемі",
"Объем видеопамяти": "Бейнежад көлемі",
"Объем кэша": "Кэш көлемі",
"Объем накопителя": "Жинақтауыш көлемі",
"Объем памяти": "Жад көлемі",
"Объясняем условия доставки, оплаты, возврата и гарантии простым языком.": "Жеткізу, төлем, қайтару және кепілдік шарттарын қарапайым тілмен түсіндіреміз.",
"Онлайн-чат": "Онлайн-чат",
"Онлайн‑треккинг": "Онлайн бақылау",
"Описание": "Сипаттама",
"Описание товара будет добавлено позже.": "Тауар сипаттамасы кейін қосылады.",
"Оперативная память": "Жедел жад",
"Оплата": "Төлем",
"Оплата банковской картой": "Банк картасымен төлеу",
"Оплата картой онлайн": "Картамен онлайн төлем",
"Оплата по реквизитам": "Деректемелер бойынша төлем",
"Оплачен": "Төленген",
"Оптимален для игровых сборок.": "Ойын жинақтары үшін оңтайлы.",
"Оставьте заявку — поможем подобрать комплектующие и ответим по доставке.": "Өтінім қалдырыңыз — бөлшектерді таңдауға көмектесіп, жеткізу бойынша жауап береміз.",
"От": "Бастап",
"Открыть заказ": "Тапсырысты ашу",
"Открыть каталог": "Каталогты ашу",
"Отменен": "Бас тартылды",
"Отправить": "Жіберу",
"Отправить сообщение": "Хабарлама жіберу",
"Отправка по стране 1-3 дня": "Ел бойынша жеткізу 1-3 күн",
"Отправлен": "Жіберілген",
"Отличная производительность.": "Жоғары өнімділік.",
"Очистить": "Тазарту",
"Очистить сравнение": "Салыстыруды тазарту",
"Пагинация": "Беттеу",
"Пароль": "Құпиясөз",
"Переведите сумму заказа по реквизитам ниже и подтвердите оформление.": "Төлемді төмендегі деректемелер бойынша аударып, рәсімдеуді растаңыз.",
"Перевод по реквизитам (на карту)": "Деректемелер бойынша аударым (картаға)",
"Перейти в каталог": "Каталогқа өту",
"Перейти к оформлению": "Рәсімдеуге өту",
"Перейти к реквизитам": "Төлем деректеріне өту",
"По вашему запросу ничего не найдено.": "Сұранысыңыз бойынша ештеңе табылмады.",
"По названию": "Атауы бойынша",
"Поддержка": "Қолдау",
"Подробнее": "Толығырақ",
"Подсказываем оптимальные варианты под бюджет и задачи.": "Бюджет пен міндетке сай оңтайлы нұсқаларды ұсынамыз.",
"Подтвердить оформление заказа": "Тапсырысты рәсімдеуді растау",
"Подтверждение оплаты в личном кабинете": "Төлемді жеке кабинетте растау",
"Подтверждение пароля": "Құпиясөзді растау",
"Поиск": "Іздеу",
"Поиск товаров": "Тауар іздеу",
"Поиск товаров по наименованию": "Тауарларды атауы бойынша іздеу",
"Поиск товаров по наименованию: процессоры, видеокарты, материнские платы, ноутбуки и периферия.": "Атауы бойынша тауар іздеу: процессорлар, бейнекарталар, аналық платалар, ноутбуктер және периферия.",
"Поиск: :query": "Іздеу: :query",
"Пока нет заказов.": "Тапсырыстар әлі жоқ.",
"Пока нет новых товаров.": "Жаңа тауарлар әзірге жоқ.",
"Пока нет популярных товаров.": "Танымал тауарлар әзірге жоқ.",
"Пока нет товаров в этой категории.": "Бұл санатта әзірге тауар жоқ.",
"Пока нет товаров.": "Тауарлар әзірге жоқ.",
"Показать": "Көрсету",
"Показать фото :number": ":number суретті көрсету",
"Получатель": "Алушы",
"Покупателю": "Сатып алушыға",
"Поможем с вашей сборкой.": "Жинағыңызды таңдауға көмектесеміз.",
"Популярные товары": "Танымал тауарлар",
"После оплаты отправьте чек в поддержку для подтверждения заказа.": "Төлемнен кейін тапсырысты растау үшін чекті қолдауға жіберіңіз.",
"Почта": "Email",
"Почта:": "Email:",
"Предыдущие товары": "Алдыңғы тауарлар",
"Предыдущий слайд": "Алдыңғы слайд",
"Проверяем ключевые характеристики и совместимость комплектующих.": "Бөлшектердің негізгі сипаттамалары мен үйлесімділігін тексереміз.",
"Продолжить покупки": "Сатып алуды жалғастыру",
"Производитель": "Өндіруші",
"Производитель видеокарты": "Бейнекарта өндірушісі",
"Производитель процессора": "Процессор өндірушісі",
"Процессоры": "Процессорлар",
"Процессоры для игровых и рабочих сборок.": "Ойын және жұмыс жинақтарына арналған процессорлар.",
"Процессоры, видеокарты, материнские платы, ноутбуки и периферия в одном каталоге.": "Процессорлар, бейнекарталар, аналық платалар, ноутбуктер және периферия бір каталогта.",
"Процессоры, видеокарты, материнские платы, ноутбуки и периферия с доставкой по стране.": "Процессорлар, бейнекарталар, аналық платалар, ноутбуктер және периферия ел бойынша жеткізіледі.",
"Процессоры, материнские платы, видеокарты, ноутбуки и периферия в одном каталоге.": "Процессорлар, аналық платалар, бейнекарталар, ноутбуктер және периферия бір каталогта.",
"Разделы сайта": "Сайт бөлімдері",
"Разрешение экрана": "Экран ажыратымдылығы",
"Расскажите о вашей сборке": "Жинағыңыз туралы жазыңыз",
"Рассрочка на крупные заказы": "Ірі тапсырыстарға бөліп төлеу",
"Регистрация": "Тіркелу",
"Результаты по запросу: \":query\"": "\":query\" сұранысы бойынша нәтижелер",
"Результаты поиска": "Іздеу нәтижелері",
"Результаты поиска по запросу «:query». Подберите нужные комплектующие по наименованию.": "«:query» сұранысы бойынша нәтижелер. Қажетті бөлшектерді атауы бойынша таңдаңыз.",
"Результаты поиска: :query": "Іздеу нәтижелері: :query",
"Реквизиты для оплаты": "Төлем деректемелері",
"Сбербанк": "Сбербанк",
"Самовывоз из пункта выдачи": "Беру пунктінен алып кету",
"Сбросить": "Тазарту",
"Свернуть чат": "Чатты жинау",
"Свяжитесь с нами для консультации по вашей сборке.": "Жинағыңыз бойынша кеңес алу үшін бізге хабарласыңыз.",
"Сервис": "Сервис",
"Серебристый": "Күміс түсті",
"Сертификат 80 Plus": "80 Plus сертификаты",
"Синий": "Көк",
"Системы охлаждения": "Салқындату жүйелері",
"Слайд на главной странице": "Басты беттегі слайд",
"Следующие товары": "Келесі тауарлар",
"Следующий слайд": "Келесі слайд",
"Сначала дешевле": "Алдымен арзаны",
"Сначала дороже": "Алдымен қымбаты",
"Сначала заполните данные получателя.": "Алдымен алушы деректерін толтырыңыз.",
"Сначала новые": "Алдымен жаңалары",
"Собирайте ПК быстрее": "ПК-ні тезірек жинаңыз",
"Создайте аккаунт, чтобы отслеживать заказы и сохранять избранное.": "Тапсырыстарды қадағалау және таңдаулыларды сақтау үшін аккаунт жасаңыз.",
"Создать аккаунт": "Аккаунт жасау",
"Сообщение": "Хабарлама",
"Сообщение содержит недопустимые символы.": "Хабарламада рұқсат етілмеген таңбалар бар.",
"Сопровождаем заказ от оформления до получения.": "Тапсырысты рәсімдеуден бастап алғанға дейін бірге жүреміз.",
"Сортировка:": "Сұрыптау:",
"Состав заказа": "Тапсырыс құрамы",
"Сохранить": "Сақтау",
"Список пуст": "Тізім бос",
"Список сравнения очищен.": "Салыстыру тізімі тазартылды.",
"Список сравнения пуст": "Салыстыру тізімі бос",
"Способ оплаты:": "Төлем тәсілі:",
"Способы оплаты": "Төлем тәсілдері",
"Сравнение": "Салыстыру",
"Сравнение товаров": "Тауарларды салыстыру",
"Сравнить": "Салыстыру",
"Стабильная линия питания.": "Тұрақты қорек желісі.",
"Стандарт Wi-Fi": "Wi-Fi стандарты",
"Статус:": "Мәртебе:",
"Сумма": "Сома",
"Сумма заказа:": "Тапсырыс сомасы:",
"Сумма к оплате:": "Төлем сомасы:",
"Система охлаждения": "Салқындату жүйесі",
"Телевизоры": "Теледидарлар",
"Телевизоры для дома и офиса.": "Үй мен офиске арналған теледидарлар.",
"Телефон": "Телефон",
"Телефон:": "Телефон:",
"Тихая работа и охлаждение.": "Тыныш жұмыс және салқындату.",
"Тихий режим работы.": "Тыныш жұмыс режимі.",
"Товар \":name\" добавлен в избранное.": "«:name» тауары таңдаулыларға қосылды.",
"Товар \":name\" добавлен в корзину.": "«:name» тауары себетке қосылды.",
"Товар \":name\" добавлен в сравнение.": "«:name» тауары салыстыруға қосылды.",
"Товар \":name\" удален из избранного.": "«:name» тауары таңдаулылардан алынды.",
"Товар \":name\" удален из корзины.": "«:name» тауары себеттен алынды.",
"Товар \":name\" удален из сравнения.": "«:name» тауары салыстырудан алынды.",
"Товар сейчас недоступен для заказа.": "Бұл тауарға қазір тапсырыс беруге болмайды.",
"Товаров": "Тауар",
"Товары в корзине": "Себеттегі тауарлар",
"Товары категории :category. Фильтры и сортировка для быстрого подбора.": ":category санатындағы тауарлар. Жылдам таңдау үшін сүзгілер мен сұрыптау.",
"Товар": "Тауар",
"Топовый воздушный кулер.": "Үздік ауа кулері.",
"Тип": "Түрі",
"Тип видеопамяти": "Бейнежад түрі",
"Тип матрицы": "Матрица түрі",
"Тип памяти": "Жад түрі",
"Тип поддерживаемой памяти": "Қолдайтын жад түрі",
"Тип процессора": "Процессор түрі",
"Тип сокета": "Сокет түрі",
"Тип устройства": "Құрылғы түрі",
"Типоразмер": "Өлшемі",
"Топовый воздушный кулер": "Үздік ауа кулері",
"Убрать из избранного": "Таңдаулылардан алып тастау",
"Убрать из сравнения": "Салыстырудан алып тастау",
"Удалить": "Жою",
"Уже есть аккаунт": "Аккаунтым бар",
"Узнайте сроки доставки и способы оплаты заказа.": "Жеткізу мерзімдері мен тапсырыс төлеу тәсілдерін біліңіз.",
"Управляйте данными профиля и просматривайте историю заказов.": "Профиль деректерін басқарып, тапсырыстар тарихын қараңыз.",
"Условия доставки и способы оплаты заказов в интернет-магазине комплектующих.": "Бөлшектер интернет-дүкеніндегі жеткізу шарттары мен төлем тәсілдері.",
"Условия доставки, способы оплаты и сроки отправки.": "Жеткізу шарттары, төлем тәсілдері және жөнелту мерзімі.",
"Устройства Apple: ноутбуки, планшеты и смартфоны.": "Apple құрылғылары: ноутбуктер, планшеттер және смартфондар.",
"Фиолетовый": "Күлгін",
"Фильтр": "Сүзгі",
"Фильтры": "Сүзгілер",
"Форм-фактор": "Форм-фактор",
"Характеристика": "Сипаттама",
"Характеристики": "Сипаттамалар",
"Характеристики еще не добавлены.": "Сипаттамалар әлі қосылмаған.",
"Хлебные крошки": "Навигация жолы",
"Цвет": "Түсі",
"Цена": "Баға",
"Цена: :from - :to": "Баға: :from - :to",
"Часы:": "Жұмыс уақыты:",
"Частота": "Жиілігі",
"Частота обновления": "Жаңарту жиілігі",
"Чат": "Чат",
"Чат закрыт администратором. Отправьте новое сообщение, чтобы начать новый диалог.": "Чатты әкімші жапты. Жаңа диалог бастау үшін жаңа хабарлама жіберіңіз.",
"Чем занимаемся и как помогаем выбрать комплектующие.": "Не істейтініміз және жинақтаушыны қалай таңдауға көмектесетініміз.",
"Черный": "Қара",
"Что еще посмотреть в этой категории": "Осы санатта тағы не көруге болады",
"Чипсет": "Чипсет",
"Электронная почта": "Электрондық пошта",
"Ядро": "Ядро",
"о компании, магазин комплектующих, поддержка": "компания туралы, бөлшектер дүкені, қолдау",
"доставка, оплата, условия заказа": "жеткізу, төлем, тапсырыс шарттары",
"интернет-магазин пк, комплектующие, процессоры, видеокарты, ноутбуки": "пк интернет-дүкені, бөлшектер, процессорлар, бейнекарталар, ноутбуктер",
"каталог комплектующих, поиск товаров, процессоры, материнские платы, видеокарты": "бөлшектер каталогы, тауар іздеу, процессорлар, аналық платалар, бейнекарталар",
"контакты магазина, телефон, email, адрес": "дүкен байланыстары, телефон, email, мекенжай",
"поиск товаров, результаты поиска, комплектующие пк, ноутбуки": "тауар іздеу, іздеу нәтижелері, пк бөлшектері, ноутбуктер",
"товар": "тауар",
"Пн-Вс: 10:00-20:00": "Дс-Жс: 10:00-20:00",
"Сбербанк": "Сбербанк",
"ул. Технопарк, 24, Техноград": "Технопарк көшесі, 24, Техноград",
"Материнские платы.": "Аналық платалар.",
"Производитель": "Өндіруші",
"Производитель видеокарты": "Бейнекарта өндірушісі",
"Производитель процессора": "Процессор өндірушісі",
"Память": "Жад",
"Оперативная память": "Жедел жад",
"Системы охлаждения.": "Салқындату жүйелері.",
"Төлем": "Төлем"
}

View File

@@ -138,12 +138,150 @@ body.pc-body {
justify-content: center; justify-content: center;
} }
.pc-header-tools {
display: flex;
align-items: center;
}
.pc-header-icons { .pc-header-icons {
display: flex; display: flex;
gap: 14px; gap: 14px;
align-items: flex-start; align-items: flex-start;
} }
.pc-lang-switcher {
position: relative;
}
.pc-lang-switcher-trigger {
list-style: none;
display: inline-flex;
align-items: center;
justify-content: space-between;
gap: 8px;
min-height: 40px;
padding: 8px 12px;
border-radius: 999px;
border: 1px solid var(--border);
background: #ffffff;
color: var(--ink);
cursor: pointer;
font-size: 0.82rem;
font-weight: 700;
transition:
border-color 0.2s ease,
background 0.2s ease,
box-shadow 0.2s ease;
}
.pc-lang-switcher-trigger::-webkit-details-marker {
display: none;
}
.pc-lang-switcher-trigger:hover {
border-color: rgba(15, 23, 42, 0.2);
background: #f8fafc;
}
.pc-lang-switcher-trigger:focus-visible {
outline: 2px solid rgba(226, 74, 74, 0.25);
outline-offset: 2px;
}
.pc-lang-switcher[open] .pc-lang-switcher-trigger {
border-color: rgba(199, 58, 58, 0.24);
box-shadow: 0 0 0 4px rgba(226, 74, 74, 0.08);
}
.pc-lang-switcher-current {
display: inline-flex;
align-items: center;
gap: 8px;
}
.pc-lang-switcher-chevron {
width: 18px;
height: 18px;
display: inline-flex;
align-items: center;
justify-content: center;
color: var(--muted);
transition: transform 0.2s ease, color 0.2s ease;
}
.pc-lang-switcher-chevron svg {
width: 14px;
height: 14px;
fill: currentColor;
}
.pc-lang-switcher[open] .pc-lang-switcher-chevron {
transform: rotate(180deg);
color: var(--ink);
}
.pc-lang-switcher-menu {
position: absolute;
top: calc(100% + 8px);
right: 0;
min-width: 170px;
padding: 8px;
border-radius: 14px;
border: 1px solid var(--border);
background: rgba(255, 255, 255, 0.98);
box-shadow: var(--shadow);
display: grid;
gap: 6px;
z-index: 120;
}
.pc-lang-switcher-option {
width: 100%;
display: inline-flex;
align-items: center;
justify-content: space-between;
gap: 8px;
padding: 9px 10px;
border: 0;
border-radius: 10px;
background: transparent;
color: var(--ink);
font: inherit;
text-align: left;
cursor: pointer;
transition: background 0.2s ease, color 0.2s ease;
}
.pc-lang-switcher-option:hover:not(:disabled) {
background: #f8fafc;
}
.pc-lang-switcher-option:disabled {
opacity: 1;
cursor: default;
}
.pc-lang-switcher-option-main {
display: inline-flex;
align-items: center;
gap: 8px;
}
.pc-lang-switcher-option.is-active {
background: rgba(226, 74, 74, 0.08);
color: #b23434;
}
.pc-lang-switcher-check {
font-size: 1.1rem;
line-height: 1;
}
.pc-lang-switcher-flag {
font-size: 1rem;
line-height: 1;
}
.pc-mobile-menu-toggle { .pc-mobile-menu-toggle {
display: none; display: none;
} }
@@ -2560,14 +2698,18 @@ body.pc-body {
letter-spacing: 0.08em; letter-spacing: 0.08em;
} }
.pc-header-tools {
display: none;
}
.pc-catalog-btn { .pc-catalog-btn {
display: none; display: none;
} }
.pc-hamburger { .pc-hamburger {
display: inline-flex; display: inline-flex;
order: 2; order: 3;
margin-left: auto; margin-left: 0;
} }
.pc-mobile-menu-head { .pc-mobile-menu-head {
@@ -2610,11 +2752,33 @@ body.pc-body {
flex: 0 0 100%; flex: 0 0 100%;
} }
.pc-mobile-menu-toggle:checked ~ .pc-header-tools {
display: flex;
order: 3;
margin-left: 0;
width: 100%;
}
.pc-mobile-menu-toggle:checked ~ .pc-header-tools .pc-lang-switcher {
width: 100%;
}
.pc-mobile-menu-toggle:checked ~ .pc-header-tools .pc-lang-switcher-trigger {
width: 100%;
}
.pc-mobile-menu-toggle:checked ~ .pc-header-tools .pc-lang-switcher-menu {
left: 0;
right: auto;
width: 100%;
min-width: 0;
}
.pc-mobile-menu-toggle:checked ~ .pc-header-center { .pc-mobile-menu-toggle:checked ~ .pc-header-center {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 10px; gap: 10px;
order: 3; order: 4;
width: 100%; width: 100%;
padding-top: 0; padding-top: 0;
border-top: 0; border-top: 0;
@@ -2625,7 +2789,7 @@ body.pc-body {
display: grid; display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr)); grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 8px; gap: 8px;
order: 4; order: 5;
width: 100%; width: 100%;
} }
@@ -2634,6 +2798,7 @@ body.pc-body {
grid-template-columns: 1fr; grid-template-columns: 1fr;
gap: 6px; gap: 6px;
width: 100%; width: 100%;
order: 6;
max-height: none; max-height: none;
opacity: 1; opacity: 1;
overflow: visible; overflow: visible;

View File

@@ -54,6 +54,8 @@ const initChatWidget = () => {
const fetchUrl = widget.dataset.fetchUrl; const fetchUrl = widget.dataset.fetchUrl;
const sendUrl = widget.dataset.sendUrl; const sendUrl = widget.dataset.sendUrl;
const csrf = widget.dataset.csrf; const csrf = widget.dataset.csrf;
const sendLabel = widget.dataset.sendLabel || 'Send';
const restartLabel = widget.dataset.restartLabel || 'Restart';
const textarea = form.querySelector('textarea[name="message"]'); const textarea = form.querySelector('textarea[name="message"]');
const submitButton = form.querySelector('button[type="submit"]'); const submitButton = form.querySelector('button[type="submit"]');
@@ -83,7 +85,7 @@ const initChatWidget = () => {
note.textContent = conversationClosed && closedNotice !== '' ? closedNotice : defaultNoteText; note.textContent = conversationClosed && closedNotice !== '' ? closedNotice : defaultNoteText;
} }
submitButton.textContent = conversationClosed ? 'Начать новый чат' : 'Отправить'; submitButton.textContent = conversationClosed ? restartLabel : sendLabel;
if (conversationClosed) { if (conversationClosed) {
stopPolling(); stopPolling();
@@ -560,6 +562,46 @@ const initCategoryFilterToggle = () => {
}); });
}; };
const initLanguageSwitchers = () => {
const switchers = Array.from(document.querySelectorAll('[data-locale-switcher]')).filter(
(switcher) => switcher instanceof HTMLDetailsElement,
);
if (switchers.length === 0) {
return;
}
document.addEventListener('click', (event) => {
switchers.forEach((switcher) => {
if (!(switcher instanceof HTMLDetailsElement) || !switcher.open) {
return;
}
if (event.target instanceof Node && switcher.contains(event.target)) {
return;
}
switcher.open = false;
});
});
switchers.forEach((switcher) => {
const summary = switcher.querySelector('summary');
switcher.addEventListener('keydown', (event) => {
if (event.key !== 'Escape') {
return;
}
switcher.open = false;
if (summary instanceof HTMLElement) {
summary.focus();
}
});
});
};
document.addEventListener('submit', (event) => { document.addEventListener('submit', (event) => {
const form = event.target; const form = event.target;
if (!(form instanceof HTMLFormElement)) { if (!(form instanceof HTMLFormElement)) {
@@ -620,3 +662,4 @@ initHomeSliders();
initProductCarousels(); initProductCarousels();
initProductGallery(); initProductGallery();
initCategoryFilterToggle(); initCategoryFilterToggle();
initLanguageSwitchers();

View File

@@ -4,32 +4,34 @@
data-fetch-url="{{ route('chat.messages') }}" data-fetch-url="{{ route('chat.messages') }}"
data-send-url="{{ route('chat.send') }}" data-send-url="{{ route('chat.send') }}"
data-csrf="{{ csrf_token() }}" data-csrf="{{ csrf_token() }}"
data-send-label="{{ __('Отправить') }}"
data-restart-label="{{ __('Начать новый чат') }}"
> >
<button class="pc-chat-toggle" type="button" data-chat-toggle> <button class="pc-chat-toggle" type="button" data-chat-toggle>
<svg viewBox="0 0 24 24" aria-hidden="true"> <svg viewBox="0 0 24 24" aria-hidden="true">
<path d="M4 5h16v10H8l-4 4V5zm2 2v7.17L7.17 13H18V7H6z"></path> <path d="M4 5h16v10H8l-4 4V5zm2 2v7.17L7.17 13H18V7H6z"></path>
</svg> </svg>
<span>Чат</span> <span>{{ __('Чат') }}</span>
</button> </button>
<section class="pc-chat-panel" data-chat-panel hidden> <section class="pc-chat-panel" data-chat-panel hidden>
<header class="pc-chat-header"> <header class="pc-chat-header">
<h3>Онлайн-чат</h3> <h3>{{ __('Онлайн-чат') }}</h3>
<button class="pc-chat-close" type="button" data-chat-close aria-label="Свернуть чат">×</button> <button class="pc-chat-close" type="button" data-chat-close aria-label="{{ __('Свернуть чат') }}">×</button>
</header> </header>
<p class="pc-chat-note" data-chat-note>Задайте вопрос администратор ответит в этом окне.</p> <p class="pc-chat-note" data-chat-note>{{ __('Задайте вопросадминистратор ответит в этом окне.') }}</p>
<div class="pc-chat-messages" data-chat-messages></div> <div class="pc-chat-messages" data-chat-messages></div>
<form class="pc-chat-form" data-chat-form> <form class="pc-chat-form" data-chat-form>
<textarea <textarea
name="message" name="message"
placeholder="Введите сообщение..." placeholder="{{ __('Введите сообщение...') }}"
maxlength="2000" maxlength="2000"
rows="3" rows="3"
required required
></textarea> ></textarea>
<button class="pc-btn primary" type="submit">Отправить</button> <button class="pc-btn primary" type="submit">{{ __('Отправить') }}</button>
</form> </form>
</section> </section>
</div> </div>

View File

@@ -1,10 +1,10 @@
@php @php
$companyName = config('shop.company_name', config('app.name')); $companyName = config('shop.company_name', config('app.name'));
$companyDescription = config('shop.company_description'); $companyDescription = __(config('shop.company_description'));
$contactPhone = trim((string) config('shop.contact_phone')); $contactPhone = trim((string) config('shop.contact_phone'));
$contactEmail = trim((string) config('shop.contact_email')); $contactEmail = trim((string) config('shop.contact_email'));
$contactTelegram = trim((string) config('shop.contact_telegram')); $contactTelegram = trim((string) config('shop.contact_telegram'));
$contactHours = trim((string) config('shop.contact_hours')); $contactHours = trim((string) __(config('shop.contact_hours')));
$telegramUrl = ''; $telegramUrl = '';
$phoneUrl = ''; $phoneUrl = '';
$emailUrl = ''; $emailUrl = '';
@@ -32,28 +32,28 @@
</div> </div>
<div class="pc-footer-columns"> <div class="pc-footer-columns">
<div class="pc-footer-col"> <div class="pc-footer-col">
<h4>Каталог</h4> <h4>{{ __('Каталог') }}</h4>
<ul class="pc-footer-list"> <ul class="pc-footer-list">
<li><a href="{{ route('catalog.index') }}">Все категории</a></li> <li><a href="{{ route('catalog.index') }}">{{ __('Все категории') }}</a></li>
<li><a href="{{ route('catalog.category', 'processors') }}">Процессоры</a></li> <li><a href="{{ route('catalog.category', 'processors') }}">{{ __('Процессоры') }}</a></li>
<li><a href="{{ route('catalog.category', 'graphics-cards') }}">Видеокарты</a></li> <li><a href="{{ route('catalog.category', 'graphics-cards') }}">{{ __('Видеокарты') }}</a></li>
<li><a href="{{ route('catalog.category', 'laptops') }}">Ноутбуки</a></li> <li><a href="{{ route('catalog.category', 'laptops') }}">{{ __('Ноутбуки') }}</a></li>
</ul> </ul>
</div> </div>
<div class="pc-footer-col"> <div class="pc-footer-col">
<h4>Покупателю</h4> <h4>{{ __('Покупателю') }}</h4>
<ul class="pc-footer-list"> <ul class="pc-footer-list">
<li><a href="{{ route('cart.index') }}">Корзина</a></li> <li><a href="{{ route('cart.index') }}">{{ __('Корзина') }}</a></li>
<li><a href="{{ route('favorites.index') }}">Избранное</a></li> <li><a href="{{ route('favorites.index') }}">{{ __('Избранное') }}</a></li>
<li><a href="{{ route('compare.index') }}">Сравнение</a></li> <li><a href="{{ route('compare.index') }}">{{ __('Сравнение') }}</a></li>
<li><a href="{{ route('pages.shipping-payment') }}">Доставка и оплата</a></li> <li><a href="{{ route('pages.shipping-payment') }}">{{ __('Доставка и оплата') }}</a></li>
</ul> </ul>
</div> </div>
<div class="pc-footer-col"> <div class="pc-footer-col">
<h4>Контакты</h4> <h4>{{ __('Контакты') }}</h4>
<div class="pc-footer-contact"> <div class="pc-footer-contact">
@if ($phoneUrl !== '') @if ($phoneUrl !== '')
<span>Телефон: <a href="{{ $phoneUrl }}">{{ $contactPhone }}</a></span> <span>{{ __('Телефон') }}: <a href="{{ $phoneUrl }}">{{ $contactPhone }}</a></span>
@endif @endif
@if ($emailUrl !== '') @if ($emailUrl !== '')
<span>Email: <a href="{{ $emailUrl }}">{{ $contactEmail }}</a></span> <span>Email: <a href="{{ $emailUrl }}">{{ $contactEmail }}</a></span>
@@ -69,7 +69,7 @@
</div> </div>
</div> </div>
<div class="pc-footer-bottom"> <div class="pc-footer-bottom">
<span>(c) {{ date('Y') }} {{ $companyName }}. Все права защищены.</span> <span>{{ __('(c) :year :company. Все права защищены.', ['year' => date('Y'), 'company' => $companyName]) }}</span>
<span><a href="{{ route('pages.about') }}">О компании</a> / <a href="{{ route('pages.contacts') }}">Контакты</a></span> <span><a href="{{ route('pages.about') }}">{{ __('О компании') }}</a> / <a href="{{ route('pages.contacts') }}">{{ __('Контакты') }}</a></span>
</div> </div>
</footer> </footer>

View File

@@ -3,52 +3,90 @@
$compareCount = count((array) session('compare', [])); $compareCount = count((array) session('compare', []));
$cartCount = collect((array) session('cart', []))->sum(fn ($quantity) => (int) $quantity); $cartCount = collect((array) session('cart', []))->sum(fn ($quantity) => (int) $quantity);
$companyName = config('shop.company_name', config('app.name')); $companyName = config('shop.company_name', config('app.name'));
$supportedLocales = (array) config('app.supported_locales', []);
$currentLocale = app()->getLocale();
$currentLocaleData = $supportedLocales[$currentLocale] ?? $supportedLocales[config('app.locale', 'ru')] ?? [
'native' => 'Русский',
'short' => 'Рус',
'flag' => '🇷🇺',
];
$navItems = [ $navItems = [
['label' => 'Главная', 'route' => route('home'), 'active' => request()->routeIs('home')], ['label' => __('Главная'), 'route' => route('home'), 'active' => request()->routeIs('home')],
[ [
'label' => 'Каталог', 'label' => __('Каталог'),
'route' => route('catalog.index'), 'route' => route('catalog.index'),
'active' => request()->routeIs('catalog.*') || request()->routeIs('products.show') || request()->routeIs('search.index'), 'active' => request()->routeIs('catalog.*') || request()->routeIs('products.show') || request()->routeIs('search.index'),
], ],
['label' => 'О нас', 'route' => route('pages.about'), 'active' => request()->routeIs('pages.about')], ['label' => __('О нас'), 'route' => route('pages.about'), 'active' => request()->routeIs('pages.about')],
[ [
'label' => 'Доставка и оплата', 'label' => __('Доставка и оплата'),
'route' => route('pages.shipping-payment'), 'route' => route('pages.shipping-payment'),
'active' => request()->routeIs('pages.shipping-payment'), 'active' => request()->routeIs('pages.shipping-payment'),
], ],
['label' => 'Контакты', 'route' => route('pages.contacts'), 'active' => request()->routeIs('pages.contacts')], ['label' => __('Контакты'), 'route' => route('pages.contacts'), 'active' => request()->routeIs('pages.contacts')],
]; ];
@endphp @endphp
<header class="pc-header pc-animate" style="--delay: 0s"> <header class="pc-header pc-animate" style="--delay: 0s">
<input type="checkbox" id="pc-mobile-menu-toggle" class="pc-mobile-menu-toggle"> <input type="checkbox" id="pc-mobile-menu-toggle" class="pc-mobile-menu-toggle">
<label for="pc-mobile-menu-toggle" class="pc-hamburger" aria-label="Меню"> <label for="pc-mobile-menu-toggle" class="pc-hamburger" aria-label="{{ __('Меню') }}">
<span></span> <span></span>
<span></span> <span></span>
<span></span> <span></span>
</label> </label>
<div class="pc-mobile-menu-head"> <div class="pc-mobile-menu-head">
<label for="pc-mobile-menu-toggle" class="pc-mobile-menu-close" aria-label="Закрыть меню">&times;</label> <label for="pc-mobile-menu-toggle" class="pc-mobile-menu-close" aria-label="{{ __('Закрыть меню') }}">&times;</label>
</div> </div>
<div class="pc-header-left"> <div class="pc-header-left">
<a class="pc-logo" href="{{ route('home') }}"> <a class="pc-logo" href="{{ route('home') }}">
<span class="pc-logo-mark"></span> <span class="pc-logo-mark"></span>
{{ $companyName }} {{ $companyName }}
</a> </a>
<a class="pc-btn pc-catalog-btn" href="{{ route('catalog.index') }}">Каталог</a> <a class="pc-btn pc-catalog-btn" href="{{ route('catalog.index') }}">{{ __('Каталог') }}</a>
</div> </div>
<div class="pc-header-center"> <div class="pc-header-center">
<form class="pc-search" action="{{ route('search.index') }}" method="get"> <form class="pc-search" action="{{ route('search.index') }}" method="get">
<input type="text" name="q" placeholder="Поиск товаров по наименованию" value="{{ request('q') }}" /> <input type="text" name="q" placeholder="{{ __('Поиск товаров по наименованию') }}" value="{{ request('q') }}" />
<button class="pc-search-submit" type="submit" aria-label="Искать"> <button class="pc-search-submit" type="submit" aria-label="{{ __('Искать') }}">
<svg viewBox="0 0 24 24" aria-hidden="true"> <svg viewBox="0 0 24 24" aria-hidden="true">
<path d="M15.5 14h-.79l-.28-.27a6 6 0 1 0-.71.71l.27.28v.79L20 20.5 21.5 19 15.5 14zm-5.5 0A4.5 4.5 0 1 1 10 5a4.5 4.5 0 0 1 0 9z"></path> <path d="M15.5 14h-.79l-.28-.27a6 6 0 1 0-.71.71l.27.28v.79L20 20.5 21.5 19 15.5 14zm-5.5 0A4.5 4.5 0 1 1 10 5a4.5 4.5 0 0 1 0 9z"></path>
</svg> </svg>
</button> </button>
</form> </form>
</div> </div>
<div class="pc-header-tools">
<details class="pc-lang-switcher" data-locale-switcher>
<summary class="pc-lang-switcher-trigger" aria-label="{{ __('Выбор языка') }}">
<span class="pc-lang-switcher-current">
<span class="pc-lang-switcher-flag" aria-hidden="true">{{ $currentLocaleData['flag'] ?? '🌐' }}</span>
<span class="pc-lang-switcher-label">{{ $currentLocaleData['short'] ?? strtoupper($currentLocale) }}</span>
</span>
<span class="pc-lang-switcher-chevron" aria-hidden="true">
<svg viewBox="0 0 20 20">
<path d="M5.3 7.8a1 1 0 0 1 1.4 0L10 11l3.3-3.2a1 1 0 1 1 1.4 1.4l-4 3.9a1 1 0 0 1-1.4 0l-4-3.9a1 1 0 0 1 0-1.4z"></path>
</svg>
</span>
</summary>
<div class="pc-lang-switcher-menu">
@foreach ($supportedLocales as $locale => $localeData)
<form method="post" action="{{ route('locale.switch', $locale) }}" data-preserve-scroll="true">
@csrf
<button class="pc-lang-switcher-option {{ $locale === $currentLocale ? 'is-active' : '' }}" type="submit" @disabled($locale === $currentLocale)>
<span class="pc-lang-switcher-option-main">
<span class="pc-lang-switcher-flag" aria-hidden="true">{{ $localeData['flag'] ?? '🌐' }}</span>
<span>{{ $localeData['native'] ?? strtoupper($locale) }}</span>
</span>
@if ($locale === $currentLocale)
<span class="pc-lang-switcher-check" aria-hidden="true"></span>
@endif
</button>
</form>
@endforeach
</div>
</details>
</div>
<div class="pc-header-icons"> <div class="pc-header-icons">
<a class="pc-icon-link" href="{{ route('favorites.index') }}" aria-label="Избранное"> <a class="pc-icon-link" href="{{ route('favorites.index') }}" aria-label="{{ __('Избранное') }}">
<span class="pc-icon"> <span class="pc-icon">
<svg viewBox="0 0 24 24" aria-hidden="true"> <svg viewBox="0 0 24 24" aria-hidden="true">
<path d="M12 20s-7-4.5-9-9c-1.2-2.7.7-6 4.2-6 2 0 3.2 1 3.8 2 0.6-1 1.8-2 3.8-2 3.5 0 5.4 3.3 4.2 6-2 4.5-9 9-9 9z"></path> <path d="M12 20s-7-4.5-9-9c-1.2-2.7.7-6 4.2-6 2 0 3.2 1 3.8 2 0.6-1 1.8-2 3.8-2 3.5 0 5.4 3.3 4.2 6-2 4.5-9 9-9 9z"></path>
@@ -57,9 +95,9 @@
<span class="pc-icon-count">{{ $favoritesCount }}</span> <span class="pc-icon-count">{{ $favoritesCount }}</span>
@endif @endif
</span> </span>
<span class="pc-icon-label">Избранное</span> <span class="pc-icon-label">{{ __('Избранное') }}</span>
</a> </a>
<a class="pc-icon-link" href="{{ route('compare.index') }}" aria-label="Сравнение"> <a class="pc-icon-link" href="{{ route('compare.index') }}" aria-label="{{ __('Сравнение') }}">
<span class="pc-icon"> <span class="pc-icon">
<svg viewBox="0 0 24 24" aria-hidden="true"> <svg viewBox="0 0 24 24" aria-hidden="true">
<path d="M5 4h3v16H5zM16 4h3v16h-3zM10.5 8h3v12h-3z"></path> <path d="M5 4h3v16H5zM16 4h3v16h-3zM10.5 8h3v12h-3z"></path>
@@ -68,9 +106,9 @@
<span class="pc-icon-count">{{ $compareCount }}</span> <span class="pc-icon-count">{{ $compareCount }}</span>
@endif @endif
</span> </span>
<span class="pc-icon-label">Сравнение</span> <span class="pc-icon-label">{{ __('Сравнение') }}</span>
</a> </a>
<a class="pc-icon-link" href="{{ route('cart.index') }}" aria-label="Корзина"> <a class="pc-icon-link" href="{{ route('cart.index') }}" aria-label="{{ __('Корзина') }}">
<span class="pc-icon"> <span class="pc-icon">
<svg viewBox="0 0 24 24" aria-hidden="true"> <svg viewBox="0 0 24 24" aria-hidden="true">
<path d="M6 6h14l-2 9H8L6 6zm-2-2h3l1 2h-4zM9 20a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zm8 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z"></path> <path d="M6 6h14l-2 9H8L6 6zm-2-2h3l1 2h-4zM9 20a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zm8 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z"></path>
@@ -79,18 +117,18 @@
<span class="pc-icon-count">{{ $cartCount }}</span> <span class="pc-icon-count">{{ $cartCount }}</span>
@endif @endif
</span> </span>
<span class="pc-icon-label">Корзина</span> <span class="pc-icon-label">{{ __('Корзина') }}</span>
</a> </a>
<a class="pc-icon-link" href="{{ auth()->check() ? route('account') : route('login') }}" aria-label="Личный кабинет"> <a class="pc-icon-link" href="{{ auth()->check() ? route('account') : route('login') }}" aria-label="{{ __('Личный кабинет') }}">
<span class="pc-icon"> <span class="pc-icon">
<svg viewBox="0 0 24 24" aria-hidden="true"> <svg viewBox="0 0 24 24" aria-hidden="true">
<path d="M12 12a4 4 0 1 0-4-4 4 4 0 0 0 4 4zm0 2c-4.4 0-8 2.2-8 5v1h16v-1c0-2.8-3.6-5-8-5z"></path> <path d="M12 12a4 4 0 1 0-4-4 4 4 0 0 0 4 4zm0 2c-4.4 0-8 2.2-8 5v1h16v-1c0-2.8-3.6-5-8-5z"></path>
</svg> </svg>
</span> </span>
<span class="pc-icon-label">{{ auth()->check() ? 'Кабинет' : 'Войти' }}</span> <span class="pc-icon-label">{{ auth()->check() ? __('Кабинет') : __('Войти') }}</span>
</a> </a>
</div> </div>
<nav class="pc-header-nav" aria-label="Разделы сайта"> <nav class="pc-header-nav" aria-label="{{ __('Разделы сайта') }}">
@foreach ($navItems as $item) @foreach ($navItems as $item)
<a class="pc-header-nav-link {{ $item['active'] ? 'is-active' : '' }}" href="{{ $item['route'] }}"> <a class="pc-header-nav-link {{ $item['active'] ? 'is-active' : '' }}" href="{{ $item['route'] }}">
{{ $item['label'] }} {{ $item['label'] }}

View File

@@ -1,12 +1,15 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="ru"> <html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head> <head>
@php @php
$supportedLocales = (array) config('app.supported_locales', []);
$currentLocale = app()->getLocale();
$currentLocaleData = $supportedLocales[$currentLocale] ?? $supportedLocales[config('app.locale', 'ru')] ?? [];
$siteName = config('seo.site_name', config('app.name', 'PC Shop')); $siteName = config('seo.site_name', config('app.name', 'PC Shop'));
$metaTitleRaw = trim($__env->yieldContent('meta_title')); $metaTitleRaw = trim($__env->yieldContent('meta_title'));
$metaTitle = $metaTitleRaw !== '' ? "{$metaTitleRaw} - {$siteName}" : config('seo.default_title', $siteName); $metaTitle = $metaTitleRaw !== '' ? "{$metaTitleRaw} - {$siteName}" : __(config('seo.default_title', $siteName));
$metaDescription = trim($__env->yieldContent('meta_description')) ?: config('seo.default_description'); $metaDescription = trim($__env->yieldContent('meta_description')) ?: __(config('seo.default_description'));
$metaKeywords = trim($__env->yieldContent('meta_keywords')) ?: config('seo.default_keywords'); $metaKeywords = trim($__env->yieldContent('meta_keywords')) ?: __(config('seo.default_keywords'));
$metaCanonical = trim($__env->yieldContent('meta_canonical')) ?: url()->current(); $metaCanonical = trim($__env->yieldContent('meta_canonical')) ?: url()->current();
$metaOgType = trim($__env->yieldContent('meta_og_type')) ?: 'website'; $metaOgType = trim($__env->yieldContent('meta_og_type')) ?: 'website';
$request = request(); $request = request();
@@ -30,10 +33,10 @@
$metaImageAlt = trim($__env->yieldContent('meta_image_alt')) ?: $metaTitle; $metaImageAlt = trim($__env->yieldContent('meta_image_alt')) ?: $metaTitle;
$siteUrl = url('/'); $siteUrl = url('/');
$companyName = config('shop.company_name', $siteName); $companyName = config('shop.company_name', $siteName);
$companyDescription = config('shop.company_description', $metaDescription); $companyDescription = __(config('shop.company_description', $metaDescription));
$companyPhone = trim((string) config('shop.contact_phone', '')); $companyPhone = trim((string) config('shop.contact_phone', ''));
$companyEmail = trim((string) config('shop.contact_email', '')); $companyEmail = trim((string) config('shop.contact_email', ''));
$companyAddress = trim((string) config('shop.contact_address', '')); $companyAddress = trim((string) __(config('shop.contact_address', '')));
$companyTelegram = trim((string) config('shop.contact_telegram', '')); $companyTelegram = trim((string) config('shop.contact_telegram', ''));
if ($companyTelegram !== '' && str_starts_with($companyTelegram, '@')) { if ($companyTelegram !== '' && str_starts_with($companyTelegram, '@')) {
$companyTelegram = 'https://t.me/' . ltrim($companyTelegram, '@'); $companyTelegram = 'https://t.me/' . ltrim($companyTelegram, '@');
@@ -86,10 +89,12 @@
<meta name="keywords" content="{{ $metaKeywords }}"> <meta name="keywords" content="{{ $metaKeywords }}">
<meta name="robots" content="{{ $metaRobots }}"> <meta name="robots" content="{{ $metaRobots }}">
<link rel="canonical" href="{{ $metaCanonical }}"> <link rel="canonical" href="{{ $metaCanonical }}">
<link rel="alternate" hreflang="ru-RU" href="{{ $metaCanonical }}"> @foreach ($supportedLocales as $localeData)
<link rel="alternate" hreflang="{{ $localeData['hreflang'] ?? 'ru-RU' }}" href="{{ $metaCanonical }}">
@endforeach
<link rel="alternate" hreflang="x-default" href="{{ $metaCanonical }}"> <link rel="alternate" hreflang="x-default" href="{{ $metaCanonical }}">
<meta property="og:type" content="{{ $metaOgType }}"> <meta property="og:type" content="{{ $metaOgType }}">
<meta property="og:locale" content="ru_RU"> <meta property="og:locale" content="{{ $currentLocaleData['og_locale'] ?? 'ru_RU' }}">
<meta property="og:site_name" content="{{ $siteName }}"> <meta property="og:site_name" content="{{ $siteName }}">
<meta property="og:title" content="{{ $metaTitle }}"> <meta property="og:title" content="{{ $metaTitle }}">
<meta property="og:description" content="{{ $metaDescription }}"> <meta property="og:description" content="{{ $metaDescription }}">

View File

@@ -1,8 +1,8 @@
@extends('layouts.shop') @extends('layouts.shop')
@section('meta_title', 'О компании') @section('meta_title', __('О компании'))
@section('meta_description', 'О компании: помощь в подборе комплектующих, консультации и поддержка при сборке ПК.') @section('meta_description', __('О компании: помощь в подборе комплектующих, консультации и поддержка при сборке ПК.'))
@section('meta_keywords', 'о компании, магазин комплектующих, поддержка') @section('meta_keywords', __('о компании, магазин комплектующих, поддержка'))
@section('meta_canonical', route('pages.about')) @section('meta_canonical', route('pages.about'))
@section('content') @section('content')
@@ -12,33 +12,33 @@
@include('partials.breadcrumbs', [ @include('partials.breadcrumbs', [
'items' => [ 'items' => [
['label' => 'Главная', 'url' => route('home')], ['label' => __('Главная'), 'url' => route('home')],
['label' => 'О нас', 'url' => null], ['label' => __('О нас'), 'url' => null],
], ],
]) ])
<section class="pc-section"> <section class="pc-section">
<div class="pc-section-title"> <div class="pc-section-title">
<h2>{{ $companyName }} интернет-магазин компьютерных комплектующих.</h2> <h2>{{ __(':company — интернет-магазин компьютерных комплектующих.', ['company' => $companyName]) }}</h2>
<p>Мы помогаем подобрать совместимую сборку, оформить заказ и получить технику с понятной поддержкой после покупки.</p> <p>{{ __('Мы помогаем подобрать совместимую сборку, оформить заказ и получить технику с понятной поддержкой после покупки.') }}</p>
</div> </div>
<div class="pc-about-content"> <div class="pc-about-content">
<h3>Кто мы</h3> <h3>{{ __('Кто мы') }}</h3>
<p>{{ $companyName }} работает для тех, кому важно собрать быстрый и надежный ПК без ошибок по совместимости. В каталоге есть комплектующие для домашних, рабочих и игровых систем: процессоры, материнские платы, видеокарты, память, накопители, блоки питания, корпуса, системы охлаждения, ноутбуки и периферия.</p> <p>{{ __(':company работает для тех, кому важно собрать быстрый и надежный ПК без ошибок по совместимости. В каталоге есть комплектующие для домашних, рабочих и игровых систем: процессоры, материнские платы, видеокарты, память, накопители, блоки питания, корпуса, системы охлаждения, ноутбуки и периферия.', ['company' => $companyName]) }}</p>
<p>Мы делаем акцент на понятном выборе: категории с фильтрами, сравнение товаров, избранное, корзина и личный кабинет с историей заказов. Это помогает быстрее принять решение и не потерять важные позиции при подборе сборки.</p> <p>{{ __('Мы делаем акцент на понятном выборе: категории с фильтрами, сравнение товаров, избранное, корзина и личный кабинет с историей заказов. Это помогает быстрее принять решение и не потерять важные позиции при подборе сборки.') }}</p>
<h3>Как мы помогаем клиентам</h3> <h3>{{ __('Как мы помогаем клиентам') }}</h3>
<ul class="pc-list"> <ul class="pc-list">
<li>Проверяем ключевые характеристики и совместимость комплектующих.</li> <li>{{ __('Проверяем ключевые характеристики и совместимость комплектующих.') }}</li>
<li>Подсказываем оптимальные варианты под бюджет и задачи.</li> <li>{{ __('Подсказываем оптимальные варианты под бюджет и задачи.') }}</li>
<li>Сопровождаем заказ от оформления до получения.</li> <li>{{ __('Сопровождаем заказ от оформления до получения.') }}</li>
<li>Объясняем условия доставки, оплаты, возврата и гарантии простым языком.</li> <li>{{ __('Объясняем условия доставки, оплаты, возврата и гарантии простым языком.') }}</li>
</ul> </ul>
<h3>Наш подход</h3> <h3>{{ __('Наш подход') }}</h3>
<p>Для нас важны прозрачность и сервис: актуальные цены, понятные характеристики и честная обратная связь. Мы стремимся, чтобы покупка техники была удобной как для новичков, так и для опытных пользователей, которые собирают ПК самостоятельно.</p> <p>{{ __('Для нас важны прозрачность и сервис: актуальные цены, понятные характеристики и честная обратная связь. Мы стремимся, чтобы покупка техники была удобной как для новичков, так и для опытных пользователей, которые собирают ПК самостоятельно.') }}</p>
<p>Если вам нужна консультация перед покупкой, команда {{ $companyName }} поможет подобрать комплектующие и предложит сбалансированные варианты под ваши задачи.</p> <p>{{ __('Если вам нужна консультация перед покупкой, команда :company поможет подобрать комплектующие и предложит сбалансированные варианты под ваши задачи.', ['company' => $companyName]) }}</p>
</div> </div>
</section> </section>
@endsection @endsection

View File

@@ -1,8 +1,8 @@
@extends('layouts.shop') @extends('layouts.shop')
@section('meta_title', 'Контакты') @section('meta_title', __('Контакты'))
@section('meta_description', 'Контакты магазина: телефон, email, адрес и часы работы поддержки.') @section('meta_description', __('Контакты магазина: телефон, email, адрес и часы работы поддержки.'))
@section('meta_keywords', 'контакты магазина, телефон, email, адрес') @section('meta_keywords', __('контакты магазина, телефон, email, адрес'))
@section('meta_canonical', route('pages.contacts')) @section('meta_canonical', route('pages.contacts'))
@section('content') @section('content')
@@ -11,7 +11,7 @@
$contactPhone = trim((string) config('shop.contact_phone')); $contactPhone = trim((string) config('shop.contact_phone'));
$contactEmail = trim((string) config('shop.contact_email')); $contactEmail = trim((string) config('shop.contact_email'));
$contactTelegram = trim((string) config('shop.contact_telegram')); $contactTelegram = trim((string) config('shop.contact_telegram'));
$contactHours = trim((string) config('shop.contact_hours')); $contactHours = trim((string) __(config('shop.contact_hours')));
$telegramUrl = ''; $telegramUrl = '';
$phoneUrl = ''; $phoneUrl = '';
$emailUrl = ''; $emailUrl = '';
@@ -33,48 +33,48 @@
@include('partials.breadcrumbs', [ @include('partials.breadcrumbs', [
'items' => [ 'items' => [
['label' => 'Главная', 'url' => route('home')], ['label' => __('Главная'), 'url' => route('home')],
['label' => 'Контакты', 'url' => null], ['label' => __('Контакты'), 'url' => null],
], ],
]) ])
<section class="pc-section"> <section class="pc-section">
<div class="pc-section-title"> <div class="pc-section-title">
<h2>Поможем с вашей сборкой.</h2> <h2>{{ __('Поможем с вашей сборкой.') }}</h2>
<p>Оставьте заявку поможем подобрать комплектующие и ответим по доставке.</p> <p>{{ __('Оставьте заявкупоможем подобрать комплектующие и ответим по доставке.') }}</p>
</div> </div>
<div class="pc-grid pc-grid-2"> <div class="pc-grid pc-grid-2">
<article class="pc-card"> <article class="pc-card">
<div class="pc-card-meta">Поддержка</div> <div class="pc-card-meta">{{ __('Поддержка') }}</div>
<h3>{{ $companyName }} поддержка клиентов</h3> <h3>{{ __(':company — поддержка клиентов', ['company' => $companyName]) }}</h3>
@if ($phoneUrl !== '') @if ($phoneUrl !== '')
<p>Телефон: <a class="pc-contact-link" href="{{ $phoneUrl }}">{{ $contactPhone }}</a></p> <p>{{ __('Телефон:') }} <a class="pc-contact-link" href="{{ $phoneUrl }}">{{ $contactPhone }}</a></p>
@endif @endif
@if ($emailUrl !== '') @if ($emailUrl !== '')
<p>Почта: <a class="pc-contact-link" href="{{ $emailUrl }}">{{ $contactEmail }}</a></p> <p>{{ __('Почта:') }} <a class="pc-contact-link" href="{{ $emailUrl }}">{{ $contactEmail }}</a></p>
@endif @endif
@if ($telegramUrl !== '') @if ($telegramUrl !== '')
<p>Telegram: <a class="pc-contact-link" href="{{ $telegramUrl }}" target="_blank" rel="noopener noreferrer">{{ $contactTelegram }}</a></p> <p>Telegram: <a class="pc-contact-link" href="{{ $telegramUrl }}" target="_blank" rel="noopener noreferrer">{{ $contactTelegram }}</a></p>
@endif @endif
@if ($contactHours !== '') @if ($contactHours !== '')
<p>Часы: {{ $contactHours }}</p> <p>{{ __('Часы:') }} {{ $contactHours }}</p>
@endif @endif
</article> </article>
<form class="pc-card pc-form" method="post" action="{{ route('pages.contacts.submit') }}"> <form class="pc-card pc-form" method="post" action="{{ route('pages.contacts.submit') }}">
@csrf @csrf
<label> <label>
Имя {{ __('Имя') }}
<input type="text" name="name" value="{{ old('name') }}" placeholder="Ваше имя" required /> <input type="text" name="name" value="{{ old('name') }}" placeholder="{{ __('Ваше имя') }}" required />
</label> </label>
<label> <label>
Почта {{ __('Почта') }}
<input type="email" name="email" value="{{ old('email') }}" placeholder="mail@example.com" required /> <input type="email" name="email" value="{{ old('email') }}" placeholder="mail@example.com" required />
</label> </label>
<label> <label>
Сообщение {{ __('Сообщение') }}
<textarea name="message" placeholder="Расскажите о вашей сборке" required>{{ old('message') }}</textarea> <textarea name="message" placeholder="{{ __('Расскажите о вашей сборке') }}" required>{{ old('message') }}</textarea>
</label> </label>
<button type="submit" class="pc-btn primary">Отправить сообщение</button> <button type="submit" class="pc-btn primary">{{ __('Отправить сообщение') }}</button>
</form> </form>
</div> </div>
</section> </section>

View File

@@ -1,40 +1,40 @@
@extends('layouts.shop') @extends('layouts.shop')
@section('meta_title', 'Доставка и оплата') @section('meta_title', __('Доставка и оплата'))
@section('meta_description', 'Условия доставки и способы оплаты заказов в интернет-магазине комплектующих.') @section('meta_description', __('Условия доставки и способы оплаты заказов в интернет-магазине комплектующих.'))
@section('meta_keywords', 'доставка, оплата, условия заказа') @section('meta_keywords', __('доставка, оплата, условия заказа'))
@section('meta_canonical', route('pages.shipping-payment')) @section('meta_canonical', route('pages.shipping-payment'))
@section('content') @section('content')
@include('partials.breadcrumbs', [ @include('partials.breadcrumbs', [
'items' => [ 'items' => [
['label' => 'Главная', 'url' => route('home')], ['label' => __('Главная'), 'url' => route('home')],
['label' => 'Доставка и оплата', 'url' => null], ['label' => __('Доставка и оплата'), 'url' => null],
], ],
]) ])
<section class="pc-section"> <section class="pc-section">
<div class="pc-section-title"> <div class="pc-section-title">
<h2>Быстрая доставка и удобная оплата.</h2> <h2>{{ __('Быстрая доставка и удобная оплата.') }}</h2>
<p>Выбирайте курьера или доставку по времени с безопасной оплатой.</p> <p>{{ __('Выбирайте курьера или доставку по времени с безопасной оплатой.') }}</p>
</div> </div>
<div class="pc-grid pc-grid-2"> <div class="pc-grid pc-grid-2">
<article class="pc-card"> <article class="pc-card">
<div class="pc-card-meta">Доставка</div> <div class="pc-card-meta">{{ __('Доставка') }}</div>
<h3>Варианты доставки</h3> <h3>{{ __('Варианты доставки') }}</h3>
<ul class="pc-list"> <ul class="pc-list">
<li>День в день в пределах города</li> <li>{{ __('День в день в пределах города') }}</li>
<li>1-3 дня по стране</li> <li>{{ __('1-3 дня по стране') }}</li>
<li>Онлайн‑треккинг</li> <li>{{ __('Онлайн‑треккинг') }}</li>
</ul> </ul>
</article> </article>
<article class="pc-card"> <article class="pc-card">
<div class="pc-card-meta">Оплата</div> <div class="pc-card-meta">{{ __('Оплата') }}</div>
<h3>Способы оплаты</h3> <h3>{{ __('Способы оплаты') }}</h3>
<ul class="pc-list"> <ul class="pc-list">
<li>Оплата банковской картой</li> <li>{{ __('Оплата банковской картой') }}</li>
<li>Безналичный расчет для юрлиц</li> <li>{{ __('Безналичный расчет для юрлиц') }}</li>
<li>Подтверждение оплаты в личном кабинете</li> <li>{{ __('Подтверждение оплаты в личном кабинете') }}</li>
</ul> </ul>
</article> </article>
</div> </div>

View File

@@ -31,7 +31,7 @@
]; ];
@endphp @endphp
<nav class="pc-breadcrumbs" aria-label="Хлебные крошки"> <nav class="pc-breadcrumbs" aria-label="{{ __('Хлебные крошки') }}">
@foreach ($items as $item) @foreach ($items as $item)
@if (!$loop->last && !empty($item['url'])) @if (!$loop->last && !empty($item['url']))
<a href="{{ $item['url'] }}">{{ $item['label'] }}</a> <a href="{{ $item['url'] }}">{{ $item['label'] }}</a>

View File

@@ -11,7 +11,7 @@
$hasSubtitle = $slide->show_subtitle && !empty($slide->subtitle); $hasSubtitle = $slide->show_subtitle && !empty($slide->subtitle);
$hasButton = $slide->show_button && !empty($slide->button_text) && !empty($slide->button_url); $hasButton = $slide->show_button && !empty($slide->button_text) && !empty($slide->button_url);
$hasContent = $hasTitle || $hasSubtitle || $hasButton; $hasContent = $hasTitle || $hasSubtitle || $hasButton;
$altText = $hasTitle ? $slide->title : 'Слайд на главной странице'; $altText = $hasTitle ? __($slide->title) : __('Слайд на главной странице');
@endphp @endphp
<article class="pc-home-slide {{ $loop->first ? 'is-active' : '' }}" data-home-slide> <article class="pc-home-slide {{ $loop->first ? 'is-active' : '' }}" data-home-slide>
<img src="{{ $slide->image_url }}" alt="{{ $altText }}" loading="{{ $loop->first ? 'eager' : 'lazy' }}"> <img src="{{ $slide->image_url }}" alt="{{ $altText }}" loading="{{ $loop->first ? 'eager' : 'lazy' }}">
@@ -19,13 +19,13 @@
@if ($hasContent) @if ($hasContent)
<div class="pc-home-slide-content"> <div class="pc-home-slide-content">
@if ($hasTitle) @if ($hasTitle)
<h2>{{ $slide->title }}</h2> <h2>{{ __($slide->title) }}</h2>
@endif @endif
@if ($hasSubtitle) @if ($hasSubtitle)
<p>{{ $slide->subtitle }}</p> <p>{{ __($slide->subtitle) }}</p>
@endif @endif
@if ($hasButton) @if ($hasButton)
<a class="pc-btn primary" href="{{ $slide->button_url }}">{{ $slide->button_text }}</a> <a class="pc-btn primary" href="{{ $slide->button_url }}">{{ __($slide->button_text) }}</a>
@endif @endif
</div> </div>
@endif @endif
@@ -34,16 +34,16 @@
<article class="pc-home-slide is-active is-fallback" data-home-slide> <article class="pc-home-slide is-active is-fallback" data-home-slide>
<div class="pc-home-slide-overlay"></div> <div class="pc-home-slide-overlay"></div>
<div class="pc-home-slide-content"> <div class="pc-home-slide-content">
<h2>{{ $fallbackTitle ?? 'Собирайте ПК быстрее' }}</h2> <h2>{{ __($fallbackTitle ?? 'Собирайте ПК быстрее') }}</h2>
<p>{{ $fallbackText ?? 'Загрузите баннеры в админке, чтобы вывести акции и подборки товаров на главной странице.' }}</p> <p>{{ __($fallbackText ?? 'Загрузите баннеры в админке, чтобы вывести акции и подборки товаров на главной странице.') }}</p>
@if (!empty($fallbackUrl)) @if (!empty($fallbackUrl))
<a class="pc-btn primary" href="{{ $fallbackUrl }}">{{ $fallbackButton ?? 'Открыть каталог' }}</a> <a class="pc-btn primary" href="{{ $fallbackUrl }}">{{ __($fallbackButton ?? 'Открыть каталог') }}</a>
@endif @endif
</div> </div>
</article> </article>
@endforelse @endforelse
</div> </div>
<button class="pc-home-slider-btn is-prev" type="button" data-home-slider-prev aria-label="Предыдущий слайд" @disabled($isSingle)></button> <button class="pc-home-slider-btn is-prev" type="button" data-home-slider-prev aria-label="{{ __('Предыдущий слайд') }}" @disabled($isSingle)></button>
<button class="pc-home-slider-btn is-next" type="button" data-home-slider-next aria-label="Следующий слайд" @disabled($isSingle)></button> <button class="pc-home-slider-btn is-next" type="button" data-home-slider-next aria-label="{{ __('Следующий слайд') }}" @disabled($isSingle)></button>
</div> </div>

View File

@@ -1,11 +1,11 @@
@if ($paginator->hasPages()) @if ($paginator->hasPages())
<nav class="pc-pager" role="navigation" aria-label="Пагинация"> <nav class="pc-pager" role="navigation" aria-label="{{ __('Пагинация') }}">
<ul class="pc-pager-list"> <ul class="pc-pager-list">
<li> <li>
@if ($paginator->onFirstPage()) @if ($paginator->onFirstPage())
<span class="pc-pager-link is-disabled" aria-disabled="true">Назад</span> <span class="pc-pager-link is-disabled" aria-disabled="true">{{ __('Назад') }}</span>
@else @else
<a class="pc-pager-link" href="{{ $paginator->previousPageUrl() }}" rel="prev">Назад</a> <a class="pc-pager-link" href="{{ $paginator->previousPageUrl() }}" rel="prev">{{ __('Назад') }}</a>
@endif @endif
</li> </li>
@@ -31,9 +31,9 @@
<li> <li>
@if ($paginator->hasMorePages()) @if ($paginator->hasMorePages())
<a class="pc-pager-link" href="{{ $paginator->nextPageUrl() }}" rel="next">Вперед</a> <a class="pc-pager-link" href="{{ $paginator->nextPageUrl() }}" rel="next">{{ __('Вперед') }}</a>
@else @else
<span class="pc-pager-link is-disabled" aria-disabled="true">Вперед</span> <span class="pc-pager-link is-disabled" aria-disabled="true">{{ __('Вперед') }}</span>
@endif @endif
</li> </li>
</ul> </ul>

View File

@@ -13,33 +13,33 @@
@endphp @endphp
<div class="pc-payment-details {{ $class ?? '' }}"> <div class="pc-payment-details {{ $class ?? '' }}">
<h3>{{ $title ?? 'Оплата по реквизитам' }}</h3> <h3>{{ __($title ?? 'Оплата по реквизитам') }}</h3>
@isset($amount) @isset($amount)
<p class="pc-payment-total">Сумма к оплате: <strong>{{ number_format((float) $amount, 0, '.', ' ') }} {{ config('shop.currency_symbol', '₽') }}</strong></p> <p class="pc-payment-total">{{ __('Сумма к оплате:') }} <strong>{{ number_format((float) $amount, 0, '.', ' ') }} {{ config('shop.currency_symbol', '₽') }}</strong></p>
@endisset @endisset
<div class="pc-payment-grid"> <div class="pc-payment-grid">
<div class="pc-payment-row"> <div class="pc-payment-row">
<span class="pc-payment-key">Банк</span> <span class="pc-payment-key">{{ __('Банк') }}</span>
<strong class="pc-payment-value">{{ $paymentBank }}</strong> <strong class="pc-payment-value">{{ __($paymentBank) }}</strong>
</div> </div>
<div class="pc-payment-row"> <div class="pc-payment-row">
<span class="pc-payment-key">Получатель</span> <span class="pc-payment-key">{{ __('Получатель') }}</span>
<strong class="pc-payment-value">{{ $paymentCardHolder }}</strong> <strong class="pc-payment-value">{{ $paymentCardHolder }}</strong>
</div> </div>
<div class="pc-payment-row"> <div class="pc-payment-row">
<span class="pc-payment-key">Номер карты</span> <span class="pc-payment-key">{{ __('Номер карты') }}</span>
<strong class="pc-payment-value">{{ $paymentCardNumber }}</strong> <strong class="pc-payment-value">{{ $paymentCardNumber }}</strong>
</div> </div>
</div> </div>
@isset($purpose) @isset($purpose)
<p class="pc-payment-purpose">Назначение платежа: <strong>{{ $purpose }}</strong></p> <p class="pc-payment-purpose">{{ __('Назначение платежа:') }} <strong>{{ $purpose }}</strong></p>
@endisset @endisset
@if (!empty($showHelp)) @if (!empty($showHelp))
<p class="pc-muted">После оплаты отправьте чек в поддержку для подтверждения заказа.</p> <p class="pc-muted">{{ __('После оплаты отправьте чек в поддержку для подтверждения заказа.') }}</p>
@if ($telegramUrl !== '') @if ($telegramUrl !== '')
<p class="pc-muted">Telegram: <a class="pc-contact-link" href="{{ $telegramUrl }}" target="_blank" rel="noopener noreferrer">{{ $telegram }}</a></p> <p class="pc-muted">Telegram: <a class="pc-contact-link" href="{{ $telegramUrl }}" target="_blank" rel="noopener noreferrer">{{ $telegram }}</a></p>
@endif @endif

View File

@@ -12,7 +12,7 @@
<div class="pc-product-tools"> <div class="pc-product-tools">
<form method="post" action="{{ route('favorites.toggle', $product) }}" class="pc-product-tool-form" data-preserve-scroll="true"> <form method="post" action="{{ route('favorites.toggle', $product) }}" class="pc-product-tool-form" data-preserve-scroll="true">
@csrf @csrf
<button class="pc-product-tool {{ $isFavorite ? 'is-active' : '' }}" type="submit" aria-label="Добавить в избранное" title="В избранное"> <button class="pc-product-tool {{ $isFavorite ? 'is-active' : '' }}" type="submit" aria-label="{{ __('Добавить в избранное') }}" title="{{ __('В избранное') }}">
<svg viewBox="0 0 24 24" aria-hidden="true"> <svg viewBox="0 0 24 24" aria-hidden="true">
<path d="M12 20s-7-4.5-9-9c-1.2-2.7.7-6 4.2-6 2 0 3.2 1 3.8 2 0.6-1 1.8-2 3.8-2 3.5 0 5.4 3.3 4.2 6-2 4.5-9 9-9 9z"></path> <path d="M12 20s-7-4.5-9-9c-1.2-2.7.7-6 4.2-6 2 0 3.2 1 3.8 2 0.6-1 1.8-2 3.8-2 3.5 0 5.4 3.3 4.2 6-2 4.5-9 9-9 9z"></path>
</svg> </svg>
@@ -20,7 +20,7 @@
</form> </form>
<form method="post" action="{{ route('compare.toggle', $product) }}" class="pc-product-tool-form" data-preserve-scroll="true"> <form method="post" action="{{ route('compare.toggle', $product) }}" class="pc-product-tool-form" data-preserve-scroll="true">
@csrf @csrf
<button class="pc-product-tool {{ $isCompared ? 'is-active' : '' }}" type="submit" aria-label="Добавить в сравнение" title="Сравнить"> <button class="pc-product-tool {{ $isCompared ? 'is-active' : '' }}" type="submit" aria-label="{{ __('Добавить в сравнение') }}" title="{{ __('Сравнить') }}">
<svg viewBox="0 0 24 24" aria-hidden="true"> <svg viewBox="0 0 24 24" aria-hidden="true">
<path d="M5 4h3v16H5zM16 4h3v16h-3zM10.5 8h3v12h-3z"></path> <path d="M5 4h3v16H5zM16 4h3v16h-3zM10.5 8h3v12h-3z"></path>
</svg> </svg>
@@ -37,7 +37,7 @@
<a class="pc-product-link" href="{{ route('products.show', $product) }}">{{ $product->name }}</a> <a class="pc-product-link" href="{{ route('products.show', $product) }}">{{ $product->name }}</a>
</h3> </h3>
@if (!empty($product->short_description)) @if (!empty($product->short_description))
<p>{{ $product->short_description }}</p> <p>{{ __($product->short_description) }}</p>
@endif @endif
<div class="pc-product-meta"> <div class="pc-product-meta">
<strong>{{ number_format($product->price, 0, '.', ' ') }} {{ config('shop.currency_symbol', '₽') }}</strong> <strong>{{ number_format($product->price, 0, '.', ' ') }} {{ config('shop.currency_symbol', '₽') }}</strong>
@@ -50,11 +50,11 @@
<form method="post" action="{{ route('cart.add', $product) }}" data-preserve-scroll="true"> <form method="post" action="{{ route('cart.add', $product) }}" data-preserve-scroll="true">
@csrf @csrf
<button class="pc-btn ghost {{ $isInCart ? 'is-active' : '' }}" type="submit"> <button class="pc-btn ghost {{ $isInCart ? 'is-active' : '' }}" type="submit">
{{ $isInCart ? 'В корзине' : 'В корзину' }} {{ $isInCart ? __('В корзине') : __('В корзину') }}
</button> </button>
</form> </form>
@else @else
<button class="pc-btn ghost" type="button" disabled>Нет в наличии</button> <button class="pc-btn ghost" type="button" disabled>{{ __('Нет в наличии') }}</button>
@endif @endif
</div> </div>
</article> </article>

View File

@@ -4,17 +4,17 @@
<section class="pc-section"> <section class="pc-section">
<div class="pc-section-title"> <div class="pc-section-title">
<h2>{{ $title ?? 'Товары' }}</h2> <h2>{{ __($title ?? 'Товары') }}</h2>
@if (!empty($description)) @if (!empty($description))
<p>{{ $description }}</p> <p>{{ __($description) }}</p>
@endif @endif
</div> </div>
@if ($items->isEmpty()) @if ($items->isEmpty())
<div class="pc-card">{{ $emptyText ?? 'Пока нет товаров.' }}</div> <div class="pc-card">{{ __($emptyText ?? 'Пока нет товаров.') }}</div>
@else @else
<div class="pc-product-carousel" data-product-carousel> <div class="pc-product-carousel" data-product-carousel>
<button class="pc-product-carousel-btn is-prev" type="button" data-product-carousel-prev aria-label="Предыдущие товары"></button> <button class="pc-product-carousel-btn is-prev" type="button" data-product-carousel-prev aria-label="{{ __('Предыдущие товары') }}"></button>
<div class="pc-product-carousel-track" data-product-carousel-track> <div class="pc-product-carousel-track" data-product-carousel-track>
@foreach ($items as $product) @foreach ($items as $product)
<div class="pc-product-carousel-item"> <div class="pc-product-carousel-item">
@@ -22,7 +22,7 @@
</div> </div>
@endforeach @endforeach
</div> </div>
<button class="pc-product-carousel-btn is-next" type="button" data-product-carousel-next aria-label="Следующие товары"></button> <button class="pc-product-carousel-btn is-next" type="button" data-product-carousel-next aria-label="{{ __('Следующие товары') }}"></button>
</div> </div>
@endif @endif
</section> </section>

View File

@@ -3,24 +3,24 @@
@section('content') @section('content')
@include('partials.breadcrumbs', [ @include('partials.breadcrumbs', [
'items' => [ 'items' => [
['label' => 'Главная', 'url' => route('home')], ['label' => __('Главная'), 'url' => route('home')],
['label' => 'Личный кабинет', 'url' => null], ['label' => __('Личный кабинет'), 'url' => null],
], ],
]) ])
<section class="pc-section"> <section class="pc-section">
<div class="pc-section-title"> <div class="pc-section-title">
<h2>Личный кабинет</h2> <h2>{{ __('Личный кабинет') }}</h2>
<p>Управляйте данными профиля и просматривайте историю заказов.</p> <p>{{ __('Управляйте данными профиля и просматривайте историю заказов.') }}</p>
</div> </div>
<div class="pc-grid pc-grid-2"> <div class="pc-grid pc-grid-2">
<div class="pc-card"> <div class="pc-card">
<form class="pc-form" method="post" action="{{ route('account.update') }}"> <form class="pc-form" method="post" action="{{ route('account.update') }}">
@csrf @csrf
<h3>Данные аккаунта</h3> <h3>{{ __('Данные аккаунта') }}</h3>
<label> <label>
Имя {{ __('Имя') }}
<input type="text" name="name" value="{{ old('name', $user->name) }}" required> <input type="text" name="name" value="{{ old('name', $user->name) }}" required>
</label> </label>
<label> <label>
@@ -28,25 +28,25 @@
<input type="email" name="email" value="{{ old('email', $user->email) }}" required> <input type="email" name="email" value="{{ old('email', $user->email) }}" required>
</label> </label>
<div class="pc-product-actions"> <div class="pc-product-actions">
<button class="pc-btn primary" type="submit">Сохранить</button> <button class="pc-btn primary" type="submit">{{ __('Сохранить') }}</button>
</div> </div>
</form> </form>
<form method="post" action="{{ route('logout') }}"> <form method="post" action="{{ route('logout') }}">
@csrf @csrf
<button class="pc-btn ghost" type="submit">Выйти</button> <button class="pc-btn ghost" type="submit">{{ __('Выйти') }}</button>
</form> </form>
</div> </div>
<div class="pc-card"> <div class="pc-card">
<h3>Мои заказы</h3> <h3>{{ __('Мои заказы') }}</h3>
@if ($orders->isEmpty()) @if ($orders->isEmpty())
<p>Пока нет заказов.</p> <p>{{ __('Пока нет заказов.') }}</p>
<a class="pc-btn ghost" href="{{ route('catalog.index') }}">Перейти в каталог</a> <a class="pc-btn ghost" href="{{ route('catalog.index') }}">{{ __('Перейти в каталог') }}</a>
@else @else
<div class="pc-account-orders"> <div class="pc-account-orders">
@foreach ($orders as $order) @foreach ($orders as $order)
<a class="pc-account-order" href="{{ route('account.orders.show', $order) }}"> <a class="pc-account-order" href="{{ route('account.orders.show', $order) }}">
<span>Заказ #{{ $order->id }}</span> <span>{{ __('Заказ #:number', ['number' => $order->id]) }}</span>
<strong>{{ number_format($order->total, 0, '.', ' ') }} {{ config('shop.currency_symbol', '₽') }}</strong> <strong>{{ number_format($order->total, 0, '.', ' ') }} {{ config('shop.currency_symbol', '₽') }}</strong>
</a> </a>
@endforeach @endforeach

View File

@@ -3,15 +3,15 @@
@section('content') @section('content')
@include('partials.breadcrumbs', [ @include('partials.breadcrumbs', [
'items' => [ 'items' => [
['label' => 'Главная', 'url' => route('home')], ['label' => __('Главная'), 'url' => route('home')],
['label' => 'Вход', 'url' => null], ['label' => __('Вход'), 'url' => null],
], ],
]) ])
<section class="pc-section pc-auth-section"> <section class="pc-section pc-auth-section">
<div class="pc-section-title"> <div class="pc-section-title">
<h2>Вход</h2> <h2>{{ __('Вход') }}</h2>
<p>Введите email и пароль для доступа к заказам и профилю.</p> <p>{{ __('Введите email и пароль для доступа к заказам и профилю.') }}</p>
</div> </div>
<form class="pc-card pc-form pc-auth-form" method="post" action="{{ route('login.attempt') }}"> <form class="pc-card pc-form pc-auth-form" method="post" action="{{ route('login.attempt') }}">
@@ -21,20 +21,20 @@
<input type="email" name="email" value="{{ old('email') }}" required> <input type="email" name="email" value="{{ old('email') }}" required>
</label> </label>
<label> <label>
Пароль {{ __('Пароль') }}
<input type="password" name="password" required> <input type="password" name="password" required>
</label> </label>
<label> <label>
Капча: решите пример {{ $captchaQuestion }} {{ __('Капча: решите пример :question', ['question' => $captchaQuestion]) }}
<input type="text" name="captcha" inputmode="numeric" autocomplete="off" required> <input type="text" name="captcha" inputmode="numeric" autocomplete="off" required>
</label> </label>
<label class="pc-checkbox"> <label class="pc-checkbox">
<input type="checkbox" name="remember" value="1" @checked(old('remember'))> <input type="checkbox" name="remember" value="1" @checked(old('remember'))>
<span>Запомнить меня</span> <span>{{ __('Запомнить меня') }}</span>
</label> </label>
<div class="pc-product-actions"> <div class="pc-product-actions">
<button class="pc-btn primary" type="submit">Войти</button> <button class="pc-btn primary" type="submit">{{ __('Войти') }}</button>
<a class="pc-btn ghost" href="{{ route('register') }}">Создать аккаунт</a> <a class="pc-btn ghost" href="{{ route('register') }}">{{ __('Создать аккаунт') }}</a>
</div> </div>
</form> </form>
</section> </section>

View File

@@ -3,21 +3,21 @@
@section('content') @section('content')
@include('partials.breadcrumbs', [ @include('partials.breadcrumbs', [
'items' => [ 'items' => [
['label' => 'Главная', 'url' => route('home')], ['label' => __('Главная'), 'url' => route('home')],
['label' => 'Регистрация', 'url' => null], ['label' => __('Регистрация'), 'url' => null],
], ],
]) ])
<section class="pc-section pc-auth-section"> <section class="pc-section pc-auth-section">
<div class="pc-section-title"> <div class="pc-section-title">
<h2>Регистрация</h2> <h2>{{ __('Регистрация') }}</h2>
<p>Создайте аккаунт, чтобы отслеживать заказы и сохранять избранное.</p> <p>{{ __('Создайте аккаунт, чтобы отслеживать заказы и сохранять избранное.') }}</p>
</div> </div>
<form class="pc-card pc-form pc-auth-form" method="post" action="{{ route('register.store') }}"> <form class="pc-card pc-form pc-auth-form" method="post" action="{{ route('register.store') }}">
@csrf @csrf
<label> <label>
Имя {{ __('Имя') }}
<input type="text" name="name" value="{{ old('name') }}" required> <input type="text" name="name" value="{{ old('name') }}" required>
</label> </label>
<label> <label>
@@ -25,20 +25,20 @@
<input type="email" name="email" value="{{ old('email') }}" required> <input type="email" name="email" value="{{ old('email') }}" required>
</label> </label>
<label> <label>
Пароль {{ __('Пароль') }}
<input type="password" name="password" required> <input type="password" name="password" required>
</label> </label>
<label> <label>
Подтверждение пароля {{ __('Подтверждение пароля') }}
<input type="password" name="password_confirmation" required> <input type="password" name="password_confirmation" required>
</label> </label>
<label> <label>
Капча: решите пример {{ $captchaQuestion }} {{ __('Капча: решите пример :question', ['question' => $captchaQuestion]) }}
<input type="text" name="captcha" inputmode="numeric" autocomplete="off" required> <input type="text" name="captcha" inputmode="numeric" autocomplete="off" required>
</label> </label>
<div class="pc-product-actions"> <div class="pc-product-actions">
<button class="pc-btn primary" type="submit">Зарегистрироваться</button> <button class="pc-btn primary" type="submit">{{ __('Зарегистрироваться') }}</button>
<a class="pc-btn ghost" href="{{ route('login') }}">Уже есть аккаунт</a> <a class="pc-btn ghost" href="{{ route('login') }}">{{ __('Уже есть аккаунт') }}</a>
</div> </div>
</form> </form>
</section> </section>

View File

@@ -3,21 +3,21 @@
@section('content') @section('content')
@include('partials.breadcrumbs', [ @include('partials.breadcrumbs', [
'items' => [ 'items' => [
['label' => 'Главная', 'url' => route('home')], ['label' => __('Главная'), 'url' => route('home')],
['label' => 'Корзина', 'url' => null], ['label' => __('Корзина'), 'url' => null],
], ],
]) ])
<section class="pc-section"> <section class="pc-section">
<div class="pc-section-title"> <div class="pc-section-title">
<h2>Товары в корзине</h2> <h2>{{ __('Товары в корзине') }}</h2>
</div> </div>
@if ($items->isEmpty()) @if ($items->isEmpty())
<div class="pc-card"> <div class="pc-card">
<h3>Корзина пустая</h3> <h3>{{ __('Корзина пустая') }}</h3>
<p>Добавьте товары из каталога, чтобы оформить заказ.</p> <p>{{ __('Добавьте товары из каталога, чтобы оформить заказ.') }}</p>
<a class="pc-btn primary" href="{{ route('catalog.index') }}">Перейти в каталог</a> <a class="pc-btn primary" href="{{ route('catalog.index') }}">{{ __('Перейти в каталог') }}</a>
</div> </div>
@else @else
<div class="pc-cart-layout"> <div class="pc-cart-layout">
@@ -38,13 +38,13 @@
@csrf @csrf
@method('patch') @method('patch')
<input type="number" name="quantity" min="1" max="{{ max(1, $product->stock) }}" value="{{ $item['quantity'] }}"> <input type="number" name="quantity" min="1" max="{{ max(1, $product->stock) }}" value="{{ $item['quantity'] }}">
<button class="pc-btn ghost" type="submit">Обновить</button> <button class="pc-btn ghost" type="submit">{{ __('Обновить') }}</button>
</form> </form>
<strong class="pc-cart-subtotal">{{ number_format($item['subtotal'], 0, '.', ' ') }} {{ config('shop.currency_symbol', '₽') }}</strong> <strong class="pc-cart-subtotal">{{ number_format($item['subtotal'], 0, '.', ' ') }} {{ config('shop.currency_symbol', '₽') }}</strong>
<form method="post" action="{{ route('cart.remove', $product) }}" data-preserve-scroll="true"> <form method="post" action="{{ route('cart.remove', $product) }}" data-preserve-scroll="true">
@csrf @csrf
@method('delete') @method('delete')
<button class="pc-btn ghost" type="submit">Удалить</button> <button class="pc-btn ghost" type="submit">{{ __('Удалить') }}</button>
</form> </form>
</div> </div>
</article> </article>
@@ -52,16 +52,16 @@
</div> </div>
<aside class="pc-card pc-cart-summary"> <aside class="pc-card pc-cart-summary">
<h3>Итого</h3> <h3>{{ __('Итого') }}</h3>
<div class="pc-cart-summary-row"> <div class="pc-cart-summary-row">
<span>Товаров</span> <span>{{ __('Товаров') }}</span>
<strong>{{ $itemsCount }}</strong> <strong>{{ $itemsCount }}</strong>
</div> </div>
<div class="pc-cart-summary-row"> <div class="pc-cart-summary-row">
<span>Сумма</span> <span>{{ __('Сумма') }}</span>
<strong>{{ number_format($total, 0, '.', ' ') }} {{ config('shop.currency_symbol', '₽') }}</strong> <strong>{{ number_format($total, 0, '.', ' ') }} {{ config('shop.currency_symbol', '₽') }}</strong>
</div> </div>
<a class="pc-btn primary" href="{{ route('checkout.show') }}">Перейти к оформлению</a> <a class="pc-btn primary" href="{{ route('checkout.show') }}">{{ __('Перейти к оформлению') }}</a>
</aside> </aside>
</div> </div>
@endif @endif

View File

@@ -9,15 +9,15 @@
'@type' => 'ListItem', '@type' => 'ListItem',
'position' => $index + 1, 'position' => $index + 1,
'url' => route('catalog.category', $category), 'url' => route('catalog.category', $category),
'name' => $category->name, 'name' => __($category->name),
]) ])
->all(); ->all();
$catalogSchema = [ $catalogSchema = [
'@context' => 'https://schema.org', '@context' => 'https://schema.org',
'@type' => 'CollectionPage', '@type' => 'CollectionPage',
'name' => 'Каталог товаров', 'name' => __('Каталог товаров'),
'url' => route('catalog.index'), 'url' => route('catalog.index'),
'description' => 'Каталог компьютерных комплектующих и техники.', 'description' => __('Каталог компьютерных комплектующих и техники.'),
'mainEntity' => [ 'mainEntity' => [
'@type' => 'ItemList', '@type' => 'ItemList',
'numberOfItems' => count($catalogCategoryList), 'numberOfItems' => count($catalogCategoryList),
@@ -25,14 +25,14 @@
], ],
]; ];
@endphp @endphp
@section('meta_title', $searchQuery !== '' ? "Поиск: {$searchQuery}" : 'Каталог товаров') @section('meta_title', $searchQuery !== '' ? __('Поиск: :query', ['query' => $searchQuery]) : __('Каталог товаров'))
@section( @section(
'meta_description', 'meta_description',
$searchQuery !== '' $searchQuery !== ''
? "Результаты поиска по запросу «{$searchQuery}». Подберите нужные комплектующие по наименованию." ? __('Результаты поиска по запросу «:query». Подберите нужные комплектующие по наименованию.', ['query' => $searchQuery])
: 'Каталог компьютерных комплектующих: процессоры, материнские платы, видеокарты, память, накопители и ноутбуки.' : __('Каталог компьютерных комплектующих: процессоры, материнские платы, видеокарты, память, накопители и ноутбуки.')
) )
@section('meta_keywords', 'каталог комплектующих, поиск товаров, процессоры, материнские платы, видеокарты') @section('meta_keywords', __('каталог комплектующих, поиск товаров, процессоры, материнские платы, видеокарты'))
@section('meta_canonical', route('catalog.index')) @section('meta_canonical', route('catalog.index'))
@section('meta_robots', $hasCatalogQuery ? 'noindex,follow' : 'index,follow') @section('meta_robots', $hasCatalogQuery ? 'noindex,follow' : 'index,follow')
@@ -45,24 +45,24 @@
@section('content') @section('content')
@include('partials.breadcrumbs', [ @include('partials.breadcrumbs', [
'items' => [ 'items' => [
['label' => 'Главная', 'url' => route('home')], ['label' => __('Главная'), 'url' => route('home')],
['label' => 'Каталог', 'url' => null], ['label' => __('Каталог'), 'url' => null],
], ],
]) ])
<section class="pc-section"> <section class="pc-section">
<div class="pc-section-title"> <div class="pc-section-title">
<h2>Категории товаров</h2> <h2>{{ __('Категории товаров') }}</h2>
</div> </div>
<div class="pc-grid pc-grid-4 pc-category-grid"> <div class="pc-grid pc-grid-4 pc-category-grid">
@forelse ($categories as $category) @forelse ($categories as $category)
<a class="pc-card pc-category-card pc-category-link" href="{{ route('catalog.category', $category) }}"> <a class="pc-card pc-category-card pc-category-link" href="{{ route('catalog.category', $category) }}">
<div class="pc-category-image" role="img" aria-label="{{ $category->name }}"></div> <div class="pc-category-image" role="img" aria-label="{{ __($category->name) }}"></div>
<h3 class="pc-category-title">{{ $category->name }}</h3> <h3 class="pc-category-title">{{ __($category->name) }}</h3>
</a> </a>
@empty @empty
<div class="pc-card">Категории пока не добавлены.</div> <div class="pc-card">{{ __('Категории пока не добавлены.') }}</div>
@endforelse @endforelse
</div> </div>
</section> </section>
@@ -71,16 +71,16 @@
<section class="pc-section"> <section class="pc-section">
<div class="pc-category-toolbar"> <div class="pc-category-toolbar">
<div class="pc-section-title"> <div class="pc-section-title">
<h2>Результаты по запросу: "{{ request('q') }}"</h2> <h2>{{ __('Результаты по запросу: ":query"', ['query' => request('q')]) }}</h2>
</div> </div>
<p class="pc-muted">Найдено: <strong>{{ $products->total() }}</strong></p> <p class="pc-muted">{{ __('Найдено:') }} <strong>{{ $products->total() }}</strong></p>
</div> </div>
<div class="pc-products-grid"> <div class="pc-products-grid">
@forelse ($products as $product) @forelse ($products as $product)
@include('partials.product-card', ['product' => $product]) @include('partials.product-card', ['product' => $product])
@empty @empty
<div class="pc-card">По вашему запросу ничего не найдено.</div> <div class="pc-card">{{ __('По вашему запросу ничего не найдено.') }}</div>
@endforelse @endforelse
</div> </div>

View File

@@ -1,6 +1,8 @@
@extends('layouts.shop') @extends('layouts.shop')
@php @php
$translatedCategoryName = __($category->name);
$translatedCategoryDescription = $category->description ? __($category->description) : __('Категория товаров :category', ['category' => $translatedCategoryName]);
$hasSeoFilters = request()->filled('q') $hasSeoFilters = request()->filled('q')
|| request()->filled('sort') || request()->filled('sort')
|| request()->filled('page') || request()->filled('page')
@@ -24,9 +26,9 @@
$categorySchema = [ $categorySchema = [
'@context' => 'https://schema.org', '@context' => 'https://schema.org',
'@type' => 'CollectionPage', '@type' => 'CollectionPage',
'name' => $category->name, 'name' => $translatedCategoryName,
'url' => route('catalog.category', $category), 'url' => route('catalog.category', $category),
'description' => $category->description ?: 'Категория товаров ' . $category->name, 'description' => $translatedCategoryDescription,
'mainEntity' => [ 'mainEntity' => [
'@type' => 'ItemList', '@type' => 'ItemList',
'numberOfItems' => $products->total(), 'numberOfItems' => $products->total(),
@@ -35,9 +37,9 @@
]; ];
@endphp @endphp
@section('meta_title', $category->name) @section('meta_title', $translatedCategoryName)
@section('meta_description', ($category->description ?: 'Товары категории ' . $category->name . '.') . ' Фильтры и сортировка для быстрого подбора.') @section('meta_description', __('Товары категории :category. Фильтры и сортировка для быстрого подбора.', ['category' => $translatedCategoryName]))
@section('meta_keywords', $category->name . ', комплектующие, купить, фильтры товаров') @section('meta_keywords', __(':category, комплектующие, купить, фильтры товаров', ['category' => $translatedCategoryName]))
@section('meta_canonical', route('catalog.category', $category)) @section('meta_canonical', route('catalog.category', $category))
@section('meta_robots', $hasSeoFilters ? 'noindex,follow' : 'index,follow') @section('meta_robots', $hasSeoFilters ? 'noindex,follow' : 'index,follow')
@@ -50,15 +52,15 @@
@section('content') @section('content')
@include('partials.breadcrumbs', [ @include('partials.breadcrumbs', [
'items' => [ 'items' => [
['label' => 'Главная', 'url' => route('home')], ['label' => __('Главная'), 'url' => route('home')],
['label' => 'Каталог', 'url' => route('catalog.index')], ['label' => __('Каталог'), 'url' => route('catalog.index')],
['label' => $category->name, 'url' => null], ['label' => $translatedCategoryName, 'url' => null],
], ],
]) ])
<section class="pc-section pc-category-page"> <section class="pc-section pc-category-page">
<div class="pc-section-title"> <div class="pc-section-title">
<h2>{{ $category->name }}</h2> <h2>{{ $translatedCategoryName }}</h2>
</div> </div>
@php @php
@@ -69,7 +71,7 @@
if (request()->filled('price_from') || request()->filled('price_to')) { if (request()->filled('price_from') || request()->filled('price_to')) {
$priceFromLabel = trim((string) request('price_from', '')); $priceFromLabel = trim((string) request('price_from', ''));
$priceToLabel = trim((string) request('price_to', '')); $priceToLabel = trim((string) request('price_to', ''));
$activeFilters->push("Цена: {$priceFromLabel} - {$priceToLabel}"); $activeFilters->push(__('Цена: :from - :to', ['from' => $priceFromLabel, 'to' => $priceToLabel]));
} }
foreach ((array) ($filters ?? []) as $filter) { foreach ((array) ($filters ?? []) as $filter) {
@@ -90,12 +92,16 @@
$fromLabel = trim((string) request($fromParam, '')); $fromLabel = trim((string) request($fromParam, ''));
$toLabel = trim((string) request($toParam, '')); $toLabel = trim((string) request($toParam, ''));
$activeFilters->push(($filter['label'] ?? $rangeKey) . ": {$fromLabel} - {$toLabel}"); $activeFilters->push(__(':label: :from - :to', [
'label' => __($filter['label'] ?? $rangeKey),
'from' => $fromLabel,
'to' => $toLabel,
]));
} }
@endphp @endphp
<div class="pc-category-toolbar"> <div class="pc-category-toolbar">
<p class="pc-muted">Найдено товаров: <strong>{{ $products->total() }}</strong></p> <p class="pc-muted">{{ __('Найдено товаров:') }} <strong>{{ $products->total() }}</strong></p>
<div class="pc-category-toolbar-controls"> <div class="pc-category-toolbar-controls">
<form class="pc-sort-form" method="get"> <form class="pc-sort-form" method="get">
@foreach ((array) ($appliedFilters ?? []) as $key => $value) @foreach ((array) ($appliedFilters ?? []) as $key => $value)
@@ -124,12 +130,12 @@
@if (request()->filled('q')) @if (request()->filled('q'))
<input type="hidden" name="q" value="{{ request('q') }}"> <input type="hidden" name="q" value="{{ request('q') }}">
@endif @endif
<label for="sort">Сортировка:</label> <label for="sort">{{ __('Сортировка:') }}</label>
<select id="sort" name="sort" onchange="this.form.submit()"> <select id="sort" name="sort" onchange="this.form.submit()">
<option value="newest" @selected($sort === 'newest')>Сначала новые</option> <option value="newest" @selected($sort === 'newest')>{{ __('Сначала новые') }}</option>
<option value="price_asc" @selected($sort === 'price_asc')>Сначала дешевле</option> <option value="price_asc" @selected($sort === 'price_asc')>{{ __('Сначала дешевле') }}</option>
<option value="price_desc" @selected($sort === 'price_desc')>Сначала дороже</option> <option value="price_desc" @selected($sort === 'price_desc')>{{ __('Сначала дороже') }}</option>
<option value="name_asc" @selected($sort === 'name_asc')>По названию</option> <option value="name_asc" @selected($sort === 'name_asc')>{{ __('По названию') }}</option>
</select> </select>
</form> </form>
<button <button
@@ -142,7 +148,7 @@
<svg viewBox="0 0 24 24" aria-hidden="true"> <svg viewBox="0 0 24 24" aria-hidden="true">
<path d="M4 6h16v2H4V6zm3 5h10v2H7v-2zm3 5h4v2h-4v-2z"></path> <path d="M4 6h16v2H4V6zm3 5h10v2H7v-2zm3 5h4v2h-4v-2z"></path>
</svg> </svg>
<span>Фильтр</span> <span>{{ __('Фильтр') }}</span>
@if ($activeFilters->isNotEmpty()) @if ($activeFilters->isNotEmpty())
<span class="pc-filter-toggle-count">{{ $activeFilters->count() }}</span> <span class="pc-filter-toggle-count">{{ $activeFilters->count() }}</span>
@endif @endif
@@ -161,7 +167,7 @@
<aside class="pc-filters"> <aside class="pc-filters">
<div id="pc-category-filters" class="pc-filter-details {{ $activeFilters->isNotEmpty() ? 'is-open' : '' }}"> <div id="pc-category-filters" class="pc-filter-details {{ $activeFilters->isNotEmpty() ? 'is-open' : '' }}">
<form method="get"> <form method="get">
<div class="pc-filter-title">Фильтры</div> <div class="pc-filter-title">{{ __('Фильтры') }}</div>
@if ($sort !== 'newest') @if ($sort !== 'newest')
<input type="hidden" name="sort" value="{{ $sort }}"> <input type="hidden" name="sort" value="{{ $sort }}">
@endif @endif
@@ -169,7 +175,7 @@
<input type="hidden" name="q" value="{{ request('q') }}"> <input type="hidden" name="q" value="{{ request('q') }}">
@endif @endif
<label class="pc-filter-block"> <label class="pc-filter-block">
<span>Цена</span> <span>{{ __('Цена') }}</span>
<div class="pc-range-fields"> <div class="pc-range-fields">
<input <input
type="number" type="number"
@@ -178,7 +184,7 @@
value="{{ $priceFilter['from'] ?? '' }}" value="{{ $priceFilter['from'] ?? '' }}"
@if (!empty($priceFilter['min'])) min="{{ $priceFilter['min'] }}" @endif @if (!empty($priceFilter['min'])) min="{{ $priceFilter['min'] }}" @endif
@if (!empty($priceFilter['max'])) max="{{ $priceFilter['max'] }}" @endif @if (!empty($priceFilter['max'])) max="{{ $priceFilter['max'] }}" @endif
placeholder="От" placeholder="{{ __('От') }}"
> >
<input <input
type="number" type="number"
@@ -187,7 +193,7 @@
value="{{ $priceFilter['to'] ?? '' }}" value="{{ $priceFilter['to'] ?? '' }}"
@if (!empty($priceFilter['min'])) min="{{ $priceFilter['min'] }}" @endif @if (!empty($priceFilter['min'])) min="{{ $priceFilter['min'] }}" @endif
@if (!empty($priceFilter['max'])) max="{{ $priceFilter['max'] }}" @endif @if (!empty($priceFilter['max'])) max="{{ $priceFilter['max'] }}" @endif
placeholder="До" placeholder="{{ __('До') }}"
> >
</div> </div>
</label> </label>
@@ -200,7 +206,7 @@
@continue($filterKey === '') @continue($filterKey === '')
@if ($isRangeFilter) @if ($isRangeFilter)
<label class="pc-filter-block"> <label class="pc-filter-block">
<span>{{ $filter['label'] }}</span> <span>{{ __($filter['label']) }}</span>
<div class="pc-range-fields"> <div class="pc-range-fields">
<input <input
type="number" type="number"
@@ -209,7 +215,7 @@
value="{{ $rangeData['from'] ?? '' }}" value="{{ $rangeData['from'] ?? '' }}"
@if (!empty($rangeData['min'])) min="{{ $rangeData['min'] }}" @endif @if (!empty($rangeData['min'])) min="{{ $rangeData['min'] }}" @endif
@if (!empty($rangeData['max'])) max="{{ $rangeData['max'] }}" @endif @if (!empty($rangeData['max'])) max="{{ $rangeData['max'] }}" @endif
placeholder="От" placeholder="{{ __('От') }}"
> >
<input <input
type="number" type="number"
@@ -218,33 +224,33 @@
value="{{ $rangeData['to'] ?? '' }}" value="{{ $rangeData['to'] ?? '' }}"
@if (!empty($rangeData['min'])) min="{{ $rangeData['min'] }}" @endif @if (!empty($rangeData['min'])) min="{{ $rangeData['min'] }}" @endif
@if (!empty($rangeData['max'])) max="{{ $rangeData['max'] }}" @endif @if (!empty($rangeData['max'])) max="{{ $rangeData['max'] }}" @endif
placeholder="До" placeholder="{{ __('До') }}"
> >
</div> </div>
</label> </label>
@else @else
<label class="pc-filter-block"> <label class="pc-filter-block">
<span>{{ $filter['label'] }}</span> <span>{{ __($filter['label']) }}</span>
<select name="filters[{{ $filterKey }}]"> <select name="filters[{{ $filterKey }}]">
<option value="">Все</option> <option value="">{{ __('Все') }}</option>
@foreach ($filterOptions[$filterKey] ?? [] as $option) @foreach ($filterOptions[$filterKey] ?? [] as $option)
@php @php
$optionValue = trim((string) $option); $optionValue = trim((string) $option);
@endphp @endphp
@continue($optionValue === '') @continue($optionValue === '')
<option value="{{ $optionValue }}" @selected(($appliedFilters[$filterKey] ?? '') === $optionValue)> <option value="{{ $optionValue }}" @selected(($appliedFilters[$filterKey] ?? '') === $optionValue)>
{{ $optionValue }} {{ __($optionValue) }}
</option> </option>
@endforeach @endforeach
</select> </select>
</label> </label>
@endif @endif
@empty @empty
<p class="pc-muted">Для этой категории фильтры пока не заданы.</p> <p class="pc-muted">{{ __('Для этой категории фильтры пока не заданы.') }}</p>
@endforelse @endforelse
<div class="pc-filter-actions"> <div class="pc-filter-actions">
<button type="submit" class="pc-btn primary">Показать</button> <button type="submit" class="pc-btn primary">{{ __('Показать') }}</button>
<a class="pc-btn ghost" href="{{ route('catalog.category', $category) }}">Сбросить</a> <a class="pc-btn ghost" href="{{ route('catalog.category', $category) }}">{{ __('Сбросить') }}</a>
</div> </div>
</form> </form>
</div> </div>
@@ -254,7 +260,7 @@
@forelse ($products as $product) @forelse ($products as $product)
@include('partials.product-card', ['product' => $product]) @include('partials.product-card', ['product' => $product])
@empty @empty
<div class="pc-card">Пока нет товаров в этой категории.</div> <div class="pc-card">{{ __('Пока нет товаров в этой категории.') }}</div>
@endforelse @endforelse
</div> </div>
</div> </div>

View File

@@ -3,22 +3,22 @@
@section('content') @section('content')
@include('partials.breadcrumbs', [ @include('partials.breadcrumbs', [
'items' => [ 'items' => [
['label' => 'Главная', 'url' => route('home')], ['label' => __('Главная'), 'url' => route('home')],
['label' => 'Корзина', 'url' => route('cart.index')], ['label' => __('Корзина'), 'url' => route('cart.index')],
['label' => 'Данные получателя', 'url' => route('checkout.show')], ['label' => __('Данные получателя'), 'url' => route('checkout.show')],
['label' => 'Реквизиты для оплаты', 'url' => null], ['label' => __('Реквизиты для оплаты'), 'url' => null],
], ],
]) ])
<section class="pc-section"> <section class="pc-section">
<div class="pc-section-title"> <div class="pc-section-title">
<h2>Реквизиты для оплаты</h2> <h2>{{ __('Реквизиты для оплаты') }}</h2>
<p>Переведите сумму заказа по реквизитам ниже и подтвердите оформление.</p> <p>{{ __('Переведите сумму заказа по реквизитам ниже и подтвердите оформление.') }}</p>
</div> </div>
<div class="pc-cart-layout"> <div class="pc-cart-layout">
<div class="pc-card"> <div class="pc-card">
<h3>Данные получателя</h3> <h3>{{ __('Данные получателя') }}</h3>
<p><strong>{{ $customer['customer_name'] }}</strong></p> <p><strong>{{ $customer['customer_name'] }}</strong></p>
<p>{{ $customer['email'] }}</p> <p>{{ $customer['email'] }}</p>
@if (!empty($customer['phone'])) @if (!empty($customer['phone']))
@@ -26,16 +26,16 @@
@endif @endif
<p>{{ $customer['address'] }}</p> <p>{{ $customer['address'] }}</p>
@if (!empty($customer['comment'])) @if (!empty($customer['comment']))
<p>Комментарий: {{ $customer['comment'] }}</p> <p>{{ __('Комментарий:') }} {{ $customer['comment'] }}</p>
@endif @endif
<div class="pc-product-actions"> <div class="pc-product-actions">
<a class="pc-btn ghost" href="{{ route('checkout.show') }}">Изменить данные</a> <a class="pc-btn ghost" href="{{ route('checkout.show') }}">{{ __('Изменить данные') }}</a>
</div> </div>
</div> </div>
<aside class="pc-card pc-cart-summary"> <aside class="pc-card pc-cart-summary">
<h3>Ваш заказ</h3> <h3>{{ __('Ваш заказ') }}</h3>
<div class="pc-account-orders"> <div class="pc-account-orders">
@foreach ($items as $item) @foreach ($items as $item)
<div class="pc-account-order"> <div class="pc-account-order">
@@ -45,11 +45,11 @@
@endforeach @endforeach
</div> </div>
<div class="pc-cart-summary-row"> <div class="pc-cart-summary-row">
<span>Товаров</span> <span>{{ __('Товаров') }}</span>
<strong>{{ $itemsCount }}</strong> <strong>{{ $itemsCount }}</strong>
</div> </div>
<div class="pc-cart-summary-row"> <div class="pc-cart-summary-row">
<span>Итого</span> <span>{{ __('Итого') }}</span>
<strong>{{ number_format($total, 0, '.', ' ') }} {{ config('shop.currency_symbol', '₽') }}</strong> <strong>{{ number_format($total, 0, '.', ' ') }} {{ config('shop.currency_symbol', '₽') }}</strong>
</div> </div>
</aside> </aside>
@@ -57,13 +57,13 @@
@include('partials.payment-requisites', [ @include('partials.payment-requisites', [
'amount' => $total, 'amount' => $total,
'purpose' => 'Номер заказа будет присвоен после подтверждения', 'purpose' => __('Номер заказа будет присвоен после подтверждения'),
'showHelp' => true, 'showHelp' => true,
]) ])
<form method="post" action="{{ route('checkout.store') }}"> <form method="post" action="{{ route('checkout.store') }}">
@csrf @csrf
<button class="pc-btn primary" type="submit">Подтвердить оформление заказа</button> <button class="pc-btn primary" type="submit">{{ __('Подтвердить оформление заказа') }}</button>
</form> </form>
</section> </section>
@endsection @endsection

View File

@@ -3,28 +3,28 @@
@section('content') @section('content')
@include('partials.breadcrumbs', [ @include('partials.breadcrumbs', [
'items' => [ 'items' => [
['label' => 'Главная', 'url' => route('home')], ['label' => __('Главная'), 'url' => route('home')],
['label' => 'Заказ оформлен', 'url' => null], ['label' => __('Заказ оформлен'), 'url' => null],
], ],
]) ])
<section class="pc-section"> <section class="pc-section">
<div class="pc-card"> <div class="pc-card">
<h2>Заказ {{ $order->id }} успешно оформлен</h2> <h2>{{ __('Заказ №:number успешно оформлен', ['number' => $order->id]) }}</h2>
<p>Мы приняли заказ в обработку. Статус заказа: <strong>{{ $order->status }}</strong>.</p> <p>{{ __('Мы приняли заказ в обработку. Статус заказа:') }} <strong>{{ $order->status_label }}</strong>.</p>
<p>Способ оплаты: <strong>{{ $order->payment_method_label }}</strong>.</p> <p>{{ __('Способ оплаты:') }} <strong>{{ $order->payment_method_label }}</strong>.</p>
<p>Сумма заказа: <strong>{{ number_format($order->total, 0, '.', ' ') }} {{ config('shop.currency_symbol', '₽') }}</strong>.</p> <p>{{ __('Сумма заказа:') }} <strong>{{ number_format($order->total, 0, '.', ' ') }} {{ config('shop.currency_symbol', '₽') }}</strong>.</p>
@include('partials.payment-requisites', [ @include('partials.payment-requisites', [
'amount' => $order->total, 'amount' => $order->total,
'purpose' => 'Заказ #' . $order->id, 'purpose' => __('Заказ #:number', ['number' => $order->id]),
'showHelp' => true, 'showHelp' => true,
]) ])
<div class="pc-product-actions"> <div class="pc-product-actions">
<a class="pc-btn primary" href="{{ route('catalog.index') }}">Продолжить покупки</a> <a class="pc-btn primary" href="{{ route('catalog.index') }}">{{ __('Продолжить покупки') }}</a>
@auth @auth
<a class="pc-btn ghost" href="{{ route('account.orders.show', $order) }}">Открыть заказ</a> <a class="pc-btn ghost" href="{{ route('account.orders.show', $order) }}">{{ __('Открыть заказ') }}</a>
@endauth @endauth
</div> </div>
</div> </div>

View File

@@ -3,23 +3,23 @@
@section('content') @section('content')
@include('partials.breadcrumbs', [ @include('partials.breadcrumbs', [
'items' => [ 'items' => [
['label' => 'Главная', 'url' => route('home')], ['label' => __('Главная'), 'url' => route('home')],
['label' => 'Корзина', 'url' => route('cart.index')], ['label' => __('Корзина'), 'url' => route('cart.index')],
['label' => 'Данные получателя', 'url' => null], ['label' => __('Данные получателя'), 'url' => null],
], ],
]) ])
<section class="pc-section"> <section class="pc-section">
<div class="pc-section-title"> <div class="pc-section-title">
<h2>Данные получателя</h2> <h2>{{ __('Данные получателя') }}</h2>
<p>Заполните контакты и перейдите на страницу с реквизитами для оплаты.</p> <p>{{ __('Заполните контакты и перейдите на страницу с реквизитами для оплаты.') }}</p>
</div> </div>
<div class="pc-cart-layout"> <div class="pc-cart-layout">
<form class="pc-card pc-form" method="post" action="{{ route('checkout.prepare') }}"> <form class="pc-card pc-form" method="post" action="{{ route('checkout.prepare') }}">
@csrf @csrf
<label> <label>
Имя получателя {{ __('Имя получателя') }}
<input type="text" name="customer_name" value="{{ old('customer_name', session('checkout.customer.customer_name', auth()->user()->name ?? '')) }}" required> <input type="text" name="customer_name" value="{{ old('customer_name', session('checkout.customer.customer_name', auth()->user()->name ?? '')) }}" required>
</label> </label>
<label> <label>
@@ -27,22 +27,22 @@
<input type="email" name="email" value="{{ old('email', session('checkout.customer.email', auth()->user()->email ?? '')) }}" required> <input type="email" name="email" value="{{ old('email', session('checkout.customer.email', auth()->user()->email ?? '')) }}" required>
</label> </label>
<label> <label>
Телефон {{ __('Телефон') }}
<input type="text" name="phone" value="{{ old('phone', session('checkout.customer.phone')) }}"> <input type="text" name="phone" value="{{ old('phone', session('checkout.customer.phone')) }}">
</label> </label>
<label> <label>
Адрес доставки {{ __('Адрес доставки') }}
<textarea name="address" required>{{ old('address', session('checkout.customer.address')) }}</textarea> <textarea name="address" required>{{ old('address', session('checkout.customer.address')) }}</textarea>
</label> </label>
<label> <label>
Комментарий к заказу {{ __('Комментарий к заказу') }}
<textarea name="comment">{{ old('comment', session('checkout.customer.comment')) }}</textarea> <textarea name="comment">{{ old('comment', session('checkout.customer.comment')) }}</textarea>
</label> </label>
<button class="pc-btn primary" type="submit">Перейти к реквизитам</button> <button class="pc-btn primary" type="submit">{{ __('Перейти к реквизитам') }}</button>
</form> </form>
<aside class="pc-card pc-cart-summary"> <aside class="pc-card pc-cart-summary">
<h3>Ваш заказ</h3> <h3>{{ __('Ваш заказ') }}</h3>
<div class="pc-account-orders"> <div class="pc-account-orders">
@foreach ($items as $item) @foreach ($items as $item)
<div class="pc-account-order"> <div class="pc-account-order">
@@ -52,11 +52,11 @@
@endforeach @endforeach
</div> </div>
<div class="pc-cart-summary-row"> <div class="pc-cart-summary-row">
<span>Товаров</span> <span>{{ __('Товаров') }}</span>
<strong>{{ $itemsCount }}</strong> <strong>{{ $itemsCount }}</strong>
</div> </div>
<div class="pc-cart-summary-row"> <div class="pc-cart-summary-row">
<span>Итого</span> <span>{{ __('Итого') }}</span>
<strong>{{ number_format($total, 0, '.', ' ') }} {{ config('shop.currency_symbol', '₽') }}</strong> <strong>{{ number_format($total, 0, '.', ' ') }} {{ config('shop.currency_symbol', '₽') }}</strong>
</div> </div>
</aside> </aside>

View File

@@ -3,28 +3,28 @@
@section('content') @section('content')
@include('partials.breadcrumbs', [ @include('partials.breadcrumbs', [
'items' => [ 'items' => [
['label' => 'Главная', 'url' => route('home')], ['label' => __('Главная'), 'url' => route('home')],
['label' => 'Сравнение', 'url' => null], ['label' => __('Сравнение'), 'url' => null],
], ],
]) ])
<section class="pc-section"> <section class="pc-section">
<div class="pc-section-title"> <div class="pc-section-title">
<h2>Сравнение товаров</h2> <h2>{{ __('Сравнение товаров') }}</h2>
</div> </div>
@if ($products->isEmpty()) @if ($products->isEmpty())
<div class="pc-card"> <div class="pc-card">
<h3>Список сравнения пуст</h3> <h3>{{ __('Список сравнения пуст') }}</h3>
<p>Добавьте товары в сравнение из карточек каталога.</p> <p>{{ __('Добавьте товары в сравнение из карточек каталога.') }}</p>
<a class="pc-btn primary" href="{{ route('catalog.index') }}">Перейти в каталог</a> <a class="pc-btn primary" href="{{ route('catalog.index') }}">{{ __('Перейти в каталог') }}</a>
</div> </div>
@else @else
<div class="pc-compare-actions"> <div class="pc-compare-actions">
<form method="post" action="{{ route('compare.clear') }}" data-preserve-scroll="true"> <form method="post" action="{{ route('compare.clear') }}" data-preserve-scroll="true">
@csrf @csrf
@method('delete') @method('delete')
<button class="pc-btn ghost" type="submit">Очистить сравнение</button> <button class="pc-btn ghost" type="submit">{{ __('Очистить сравнение') }}</button>
</form> </form>
</div> </div>
@@ -40,7 +40,7 @@
<table class="pc-compare-table"> <table class="pc-compare-table">
<thead> <thead>
<tr> <tr>
<th>Характеристика</th> <th>{{ __('Характеристика') }}</th>
@foreach ($products as $product) @foreach ($products as $product)
<th>{{ $product->name }}</th> <th>{{ $product->name }}</th>
@endforeach @endforeach
@@ -49,9 +49,9 @@
<tbody> <tbody>
@foreach ($specKeys as $key) @foreach ($specKeys as $key)
<tr> <tr>
<th>{{ $specLabels[$key] ?? $key }}</th> <th>{{ __($specLabels[$key] ?? $key) }}</th>
@foreach ($products as $product) @foreach ($products as $product)
<td>{{ data_get($product->specs, $key, '—') }}</td> <td>{{ __(strval(data_get($product->specs, $key, '—'))) }}</td>
@endforeach @endforeach
</tr> </tr>
@endforeach @endforeach

View File

@@ -3,21 +3,21 @@
@section('content') @section('content')
@include('partials.breadcrumbs', [ @include('partials.breadcrumbs', [
'items' => [ 'items' => [
['label' => 'Главная', 'url' => route('home')], ['label' => __('Главная'), 'url' => route('home')],
['label' => 'Избранное', 'url' => null], ['label' => __('Избранное'), 'url' => null],
], ],
]) ])
<section class="pc-section"> <section class="pc-section">
<div class="pc-section-title"> <div class="pc-section-title">
<h2>Избранные товары</h2> <h2>{{ __('Избранные товары') }}</h2>
</div> </div>
@if ($products->isEmpty()) @if ($products->isEmpty())
<div class="pc-card"> <div class="pc-card">
<h3>Список пуст</h3> <h3>{{ __('Список пуст') }}</h3>
<p>Добавьте товары в избранное из каталога или со страницы товара.</p> <p>{{ __('Добавьте товары в избранное из каталога или со страницы товара.') }}</p>
<a class="pc-btn primary" href="{{ route('catalog.index') }}">Перейти в каталог</a> <a class="pc-btn primary" href="{{ route('catalog.index') }}">{{ __('Перейти в каталог') }}</a>
</div> </div>
@else @else
<div class="pc-products-grid"> <div class="pc-products-grid">

View File

@@ -1,8 +1,8 @@
@extends('layouts.shop') @extends('layouts.shop')
@section('meta_title', 'Главная') @section('meta_title', __('Главная'))
@section('meta_description', 'Интернет-магазин комплектующих для ПК: процессоры, материнские платы, видеокарты, ноутбуки и периферия.') @section('meta_description', __('Интернет-магазин комплектующих для ПК: процессоры, материнские платы, видеокарты, ноутбуки и периферия.'))
@section('meta_keywords', 'интернет-магазин пк, комплектующие, процессоры, видеокарты, ноутбуки') @section('meta_keywords', __('интернет-магазин пк, комплектующие, процессоры, видеокарты, ноутбуки'))
@section('meta_canonical', route('home')) @section('meta_canonical', route('home'))
@section('content') @section('content')
@@ -10,62 +10,62 @@
@include('partials.home-slider', [ @include('partials.home-slider', [
'slides' => $leftSlides, 'slides' => $leftSlides,
'sliderClass' => 'is-main', 'sliderClass' => 'is-main',
'fallbackTitle' => 'Собирайте ПК быстрее', 'fallbackTitle' => __('Собирайте ПК быстрее'),
'fallbackText' => 'Процессоры, материнские платы, видеокарты, ноутбуки и периферия в одном каталоге.', 'fallbackText' => __('Процессоры, материнские платы, видеокарты, ноутбуки и периферия в одном каталоге.'),
'fallbackUrl' => route('catalog.index'), 'fallbackUrl' => route('catalog.index'),
'fallbackButton' => 'Перейти в каталог', 'fallbackButton' => __('Перейти в каталог'),
]) ])
@include('partials.home-slider', [ @include('partials.home-slider', [
'slides' => $rightSlides, 'slides' => $rightSlides,
'sliderClass' => 'is-side', 'sliderClass' => 'is-side',
'fallbackTitle' => 'Доставка и оплата', 'fallbackTitle' => __('Доставка и оплата'),
'fallbackText' => 'Узнайте сроки доставки и способы оплаты заказа.', 'fallbackText' => __('Узнайте сроки доставки и способы оплаты заказа.'),
'fallbackUrl' => route('pages.shipping-payment'), 'fallbackUrl' => route('pages.shipping-payment'),
'fallbackButton' => 'Подробнее', 'fallbackButton' => __('Подробнее'),
]) ])
</section> </section>
<section class="pc-section"> <section class="pc-section">
<div class="pc-section-title"> <div class="pc-section-title">
<h2>Категории</h2> <h2>{{ __('Категории') }}</h2>
</div> </div>
<div class="pc-grid pc-grid-4 pc-category-grid"> <div class="pc-grid pc-grid-4 pc-category-grid">
@foreach ($categories as $category) @foreach ($categories as $category)
<a class="pc-card pc-category-card pc-category-link" href="{{ route('catalog.category', $category) }}"> <a class="pc-card pc-category-card pc-category-link" href="{{ route('catalog.category', $category) }}">
<div class="pc-category-image" role="img" aria-label="{{ $category->name }}"></div> <div class="pc-category-image" role="img" aria-label="{{ __($category->name) }}"></div>
<h3 class="pc-category-title">{{ $category->name }}</h3> <h3 class="pc-category-title">{{ __($category->name) }}</h3>
</a> </a>
@endforeach @endforeach
</div> </div>
</section> </section>
@include('partials.product-carousel', [ @include('partials.product-carousel', [
'title' => 'Популярные товары', 'title' => __('Популярные товары'),
'products' => $featured, 'products' => $featured,
'emptyText' => 'Пока нет популярных товаров.', 'emptyText' => __('Пока нет популярных товаров.'),
]) ])
@include('partials.product-carousel', [ @include('partials.product-carousel', [
'title' => 'Новые товары', 'title' => __('Новые товары'),
'products' => $newProducts, 'products' => $newProducts,
'emptyText' => 'Пока нет новых товаров.', 'emptyText' => __('Пока нет новых товаров.'),
]) ])
<section class="pc-grid pc-grid-3"> <section class="pc-grid pc-grid-3">
<a class="pc-card pc-category-link" href="{{ route('pages.shipping-payment') }}"> <a class="pc-card pc-category-link" href="{{ route('pages.shipping-payment') }}">
<div class="pc-card-meta">Сервис</div> <div class="pc-card-meta">{{ __('Сервис') }}</div>
<h3>Доставка и оплата</h3> <h3>{{ __('Доставка и оплата') }}</h3>
<p>Условия доставки, способы оплаты и сроки отправки.</p> <p>{{ __('Условия доставки, способы оплаты и сроки отправки.') }}</p>
</a> </a>
<a class="pc-card pc-category-link" href="{{ route('pages.about') }}"> <a class="pc-card pc-category-link" href="{{ route('pages.about') }}">
<div class="pc-card-meta">Компания</div> <div class="pc-card-meta">{{ __('Компания') }}</div>
<h3>О нас</h3> <h3>{{ __('О нас') }}</h3>
<p>Чем занимаемся и как помогаем выбрать комплектующие.</p> <p>{{ __('Чем занимаемся и как помогаем выбрать комплектующие.') }}</p>
</a> </a>
<a class="pc-card pc-category-link" href="{{ route('pages.contacts') }}"> <a class="pc-card pc-category-link" href="{{ route('pages.contacts') }}">
<div class="pc-card-meta">Поддержка</div> <div class="pc-card-meta">{{ __('Поддержка') }}</div>
<h3>Контакты</h3> <h3>{{ __('Контакты') }}</h3>
<p>Свяжитесь с нами для консультации по вашей сборке.</p> <p>{{ __('Свяжитесь с нами для консультации по вашей сборке.') }}</p>
</a> </a>
</section> </section>
@endsection @endsection

View File

@@ -3,22 +3,22 @@
@section('content') @section('content')
@include('partials.breadcrumbs', [ @include('partials.breadcrumbs', [
'items' => [ 'items' => [
['label' => 'Главная', 'url' => route('home')], ['label' => __('Главная'), 'url' => route('home')],
['label' => 'Личный кабинет', 'url' => route('account')], ['label' => __('Личный кабинет'), 'url' => route('account')],
['label' => 'Заказ #' . $order->id, 'url' => null], ['label' => __('Заказ #:number', ['number' => $order->id]), 'url' => null],
], ],
]) ])
<section class="pc-section"> <section class="pc-section">
<div class="pc-section-title"> <div class="pc-section-title">
<h2>Заказ #{{ $order->id }}</h2> <h2>{{ __('Заказ #:number', ['number' => $order->id]) }}</h2>
<p>Статус: <strong>{{ $order->status }}</strong></p> <p>{{ __('Статус:') }} <strong>{{ $order->status_label }}</strong></p>
<p>Способ оплаты: <strong>{{ $order->payment_method_label }}</strong></p> <p>{{ __('Способ оплаты:') }} <strong>{{ $order->payment_method_label }}</strong></p>
</div> </div>
<div class="pc-grid pc-grid-2"> <div class="pc-grid pc-grid-2">
<div class="pc-card"> <div class="pc-card">
<h3>Состав заказа</h3> <h3>{{ __('Состав заказа') }}</h3>
<div class="pc-account-orders"> <div class="pc-account-orders">
@foreach ($order->items as $item) @foreach ($order->items as $item)
<div class="pc-account-order"> <div class="pc-account-order">
@@ -28,13 +28,13 @@
@endforeach @endforeach
</div> </div>
<div class="pc-cart-summary-row"> <div class="pc-cart-summary-row">
<span>Итого</span> <span>{{ __('Итого') }}</span>
<strong>{{ number_format($order->total, 0, '.', ' ') }} {{ config('shop.currency_symbol', '₽') }}</strong> <strong>{{ number_format($order->total, 0, '.', ' ') }} {{ config('shop.currency_symbol', '₽') }}</strong>
</div> </div>
</div> </div>
<div class="pc-card"> <div class="pc-card">
<h3>Данные получателя</h3> <h3>{{ __('Данные получателя') }}</h3>
<p><strong>{{ $order->customer_name }}</strong></p> <p><strong>{{ $order->customer_name }}</strong></p>
<p>{{ $order->email }}</p> <p>{{ $order->email }}</p>
@if ($order->phone) @if ($order->phone)
@@ -44,7 +44,7 @@
<p>{{ $order->address }}</p> <p>{{ $order->address }}</p>
@endif @endif
@if ($order->comment) @if ($order->comment)
<p>Комментарий: {{ $order->comment }}</p> <p>{{ __('Комментарий:') }} {{ $order->comment }}</p>
@endif @endif
</div> </div>
</div> </div>
@@ -52,7 +52,7 @@
@if (!in_array($order->status, ['paid', 'shipped', 'completed'], true)) @if (!in_array($order->status, ['paid', 'shipped', 'completed'], true))
@include('partials.payment-requisites', [ @include('partials.payment-requisites', [
'amount' => $order->total, 'amount' => $order->total,
'purpose' => 'Заказ #' . $order->id, 'purpose' => __('Заказ #:number', ['number' => $order->id]),
'showHelp' => true, 'showHelp' => true,
]) ])
@endif @endif

View File

@@ -23,9 +23,9 @@
'@context' => 'https://schema.org', '@context' => 'https://schema.org',
'@type' => 'Product', '@type' => 'Product',
'name' => $product->name, 'name' => $product->name,
'description' => $product->short_description ?: ($product->description ?: "Купить {$product->name} по выгодной цене."), 'description' => __($product->short_description ?: ($product->description ?: __('Купить :product по выгодной цене.', ['product' => $product->name]))),
'sku' => $product->sku ?: null, 'sku' => $product->sku ?: null,
'category' => $product->category?->name, 'category' => $product->category?->name ? __($product->category->name) : null,
'image' => $productSchemaImages, 'image' => $productSchemaImages,
'url' => route('products.show', $product), 'url' => route('products.show', $product),
'offers' => [ 'offers' => [
@@ -47,8 +47,8 @@
@endphp @endphp
@section('meta_title', $product->name) @section('meta_title', $product->name)
@section('meta_description', \Illuminate\Support\Str::limit(strip_tags($product->short_description ?: ($product->description ?: "Купить {$product->name} по выгодной цене.")), 160)) @section('meta_description', \Illuminate\Support\Str::limit(strip_tags(__($product->short_description ?: ($product->description ?: __('Купить :product по выгодной цене.', ['product' => $product->name])))), 160))
@section('meta_keywords', $product->name . ', ' . ($product->category?->name ?? 'товар') . ', купить') @section('meta_keywords', __(':product, :category, купить', ['product' => $product->name, 'category' => $product->category?->name ? __($product->category->name) : __('товар')]))
@section('meta_canonical', route('products.show', $product)) @section('meta_canonical', route('products.show', $product))
@section('meta_image', $productImageUrl) @section('meta_image', $productImageUrl)
@section('meta_image_alt', $product->name) @section('meta_image_alt', $product->name)
@@ -72,9 +72,9 @@
@include('partials.breadcrumbs', [ @include('partials.breadcrumbs', [
'items' => [ 'items' => [
['label' => 'Главная', 'url' => route('home')], ['label' => __('Главная'), 'url' => route('home')],
['label' => 'Каталог', 'url' => route('catalog.index')], ['label' => __('Каталог'), 'url' => route('catalog.index')],
['label' => $product->category?->name ?? 'Категория', 'url' => $product->category ? route('catalog.category', $product->category) : null], ['label' => $product->category?->name ? __($product->category->name) : __('Категория'), 'url' => $product->category ? route('catalog.category', $product->category) : null],
['label' => $product->name, 'url' => null], ['label' => $product->name, 'url' => null],
], ],
]) ])
@@ -96,20 +96,20 @@
@endif @endif
@if (count($productGallery) > 1) @if (count($productGallery) > 1)
<div class="pc-product-thumbs" aria-label="Дополнительные изображения товара"> <div class="pc-product-thumbs" aria-label="{{ __('Дополнительные изображения товара') }}">
@foreach ($productGallery as $imageUrl) @foreach ($productGallery as $imageUrl)
<button <button
class="pc-product-thumb {{ $loop->first ? 'is-active' : '' }}" class="pc-product-thumb {{ $loop->first ? 'is-active' : '' }}"
type="button" type="button"
data-product-gallery-thumb data-product-gallery-thumb
data-image-src="{{ $imageUrl }}" data-image-src="{{ $imageUrl }}"
data-image-alt="{{ $product->name }} - фото {{ $loop->iteration }}" data-image-alt="{{ __(':product - фото :number', ['product' => $product->name, 'number' => $loop->iteration]) }}"
aria-label="Показать фото {{ $loop->iteration }}" aria-label="{{ __('Показать фото :number', ['number' => $loop->iteration]) }}"
aria-pressed="{{ $loop->first ? 'true' : 'false' }}" aria-pressed="{{ $loop->first ? 'true' : 'false' }}"
> >
<img <img
src="{{ $imageUrl }}" src="{{ $imageUrl }}"
alt="{{ $product->name }} - миниатюра {{ $loop->iteration }}" alt="{{ __(':product - миниатюра :number', ['product' => $product->name, 'number' => $loop->iteration]) }}"
loading="lazy" loading="lazy"
decoding="async" decoding="async"
> >
@@ -120,10 +120,10 @@
</div> </div>
<div class="pc-product-info"> <div class="pc-product-info">
<h1>{{ $product->name }}</h1> <h1>{{ $product->name }}</h1>
<p class="pc-muted">{{ $product->short_description }}</p> <p class="pc-muted">{{ __($product->short_description) }}</p>
<div class="pc-product-badges"> <div class="pc-product-badges">
@if ($product->sku) @if ($product->sku)
<span class="pc-sku">Артикул: {{ $product->sku }}</span> <span class="pc-sku">{{ __('Артикул:') }} {{ $product->sku }}</span>
@endif @endif
</div> </div>
<div class="pc-product-price"> <div class="pc-product-price">
@@ -137,22 +137,22 @@
<form method="post" action="{{ route('cart.add', $product) }}" data-preserve-scroll="true"> <form method="post" action="{{ route('cart.add', $product) }}" data-preserve-scroll="true">
@csrf @csrf
<button class="pc-btn primary {{ $isInCart ? 'is-active' : '' }}" type="submit"> <button class="pc-btn primary {{ $isInCart ? 'is-active' : '' }}" type="submit">
{{ $isInCart ? 'В корзине' : 'В корзину' }} {{ $isInCart ? __('В корзине') : __('В корзину') }}
</button> </button>
</form> </form>
@else @else
<button class="pc-btn primary" type="button" disabled>Нет в наличии</button> <button class="pc-btn primary" type="button" disabled>{{ __('Нет в наличии') }}</button>
@endif @endif
<form method="post" action="{{ route('favorites.toggle', $product) }}" data-preserve-scroll="true"> <form method="post" action="{{ route('favorites.toggle', $product) }}" data-preserve-scroll="true">
@csrf @csrf
<button class="pc-btn ghost {{ $isFavorite ? 'is-active' : '' }}" type="submit"> <button class="pc-btn ghost {{ $isFavorite ? 'is-active' : '' }}" type="submit">
{{ $isFavorite ? 'Убрать из избранного' : 'В избранное' }} {{ $isFavorite ? __('Убрать из избранного') : __('В избранное') }}
</button> </button>
</form> </form>
<form method="post" action="{{ route('compare.toggle', $product) }}" data-preserve-scroll="true"> <form method="post" action="{{ route('compare.toggle', $product) }}" data-preserve-scroll="true">
@csrf @csrf
<button class="pc-btn ghost {{ $isCompared ? 'is-active' : '' }}" type="submit"> <button class="pc-btn ghost {{ $isCompared ? 'is-active' : '' }}" type="submit">
{{ $isCompared ? 'Убрать из сравнения' : 'В сравнение' }} {{ $isCompared ? __('Убрать из сравнения') : __('В сравнение') }}
</button> </button>
</form> </form>
</div> </div>
@@ -166,10 +166,10 @@
<input type="radio" name="product-tabs" id="tab-payment"> <input type="radio" name="product-tabs" id="tab-payment">
<div class="pc-tab-labels"> <div class="pc-tab-labels">
<label for="tab-specs">Характеристики</label> <label for="tab-specs">{{ __('Характеристики') }}</label>
<label for="tab-desc">Описание</label> <label for="tab-desc">{{ __('Описание') }}</label>
<label for="tab-shipping">Доставка</label> <label for="tab-shipping">{{ __('Доставка') }}</label>
<label for="tab-payment">Оплата</label> <label for="tab-payment">{{ __('Оплата') }}</label>
</div> </div>
<div class="pc-tab-content"> <div class="pc-tab-content">
@@ -177,29 +177,29 @@
<div class="pc-specs-grid"> <div class="pc-specs-grid">
@forelse (($product->specs ?? []) as $key => $value) @forelse (($product->specs ?? []) as $key => $value)
<div class="pc-spec-row"> <div class="pc-spec-row">
<span>{{ $specLabels[$key] ?? str_replace('_', ' ', $key) }}</span> <span>{{ __($specLabels[$key] ?? str_replace('_', ' ', $key)) }}</span>
<strong>{{ $value }}</strong> <strong>{{ __((string) $value) }}</strong>
</div> </div>
@empty @empty
<p class="pc-muted">Характеристики еще не добавлены.</p> <p class="pc-muted">{{ __('Характеристики еще не добавлены.') }}</p>
@endforelse @endforelse
</div> </div>
</section> </section>
<section class="pc-tab-panel pc-tab-desc"> <section class="pc-tab-panel pc-tab-desc">
<p class="pc-muted">{{ $product->description ?? 'Описание товара будет добавлено позже.' }}</p> <p class="pc-muted">{{ __($product->description ?? __('Описание товара будет добавлено позже.')) }}</p>
</section> </section>
<section class="pc-tab-panel pc-tab-shipping"> <section class="pc-tab-panel pc-tab-shipping">
<ul class="pc-list"> <ul class="pc-list">
<li>Доставка курьером по городу</li> <li>{{ __('Доставка курьером по городу') }}</li>
<li>Самовывоз из пункта выдачи</li> <li>{{ __('Самовывоз из пункта выдачи') }}</li>
<li>Отправка по стране 1-3 дня</li> <li>{{ __('Отправка по стране 1-3 дня') }}</li>
</ul> </ul>
</section> </section>
<section class="pc-tab-panel pc-tab-payment"> <section class="pc-tab-panel pc-tab-payment">
<ul class="pc-list"> <ul class="pc-list">
<li>Оплата картой онлайн</li> <li>{{ __('Оплата картой онлайн') }}</li>
<li>Банковский перевод</li> <li>{{ __('Банковский перевод') }}</li>
<li>Рассрочка на крупные заказы</li> <li>{{ __('Рассрочка на крупные заказы') }}</li>
</ul> </ul>
</section> </section>
</div> </div>
@@ -209,7 +209,7 @@
@if ($related->isNotEmpty()) @if ($related->isNotEmpty())
<section class="pc-section"> <section class="pc-section">
<div class="pc-section-title"> <div class="pc-section-title">
<h2>Что еще посмотреть в этой категории</h2> <h2>{{ __('Что еще посмотреть в этой категории') }}</h2>
</div> </div>
<div class="pc-products-grid"> <div class="pc-products-grid">
@foreach ($related as $item) @foreach ($related as $item)

View File

@@ -14,7 +14,7 @@
? [ ? [
'@context' => 'https://schema.org', '@context' => 'https://schema.org',
'@type' => 'SearchResultsPage', '@type' => 'SearchResultsPage',
'name' => "Результаты поиска: {$searchQuery}", 'name' => __('Результаты поиска: :query', ['query' => $searchQuery]),
'url' => route('search.index', ['q' => $searchQuery]), 'url' => route('search.index', ['q' => $searchQuery]),
'mainEntity' => [ 'mainEntity' => [
'@type' => 'ItemList', '@type' => 'ItemList',
@@ -25,14 +25,14 @@
: null; : null;
@endphp @endphp
@section('meta_title', $searchQuery !== '' ? "Поиск: {$searchQuery}" : 'Поиск товаров') @section('meta_title', $searchQuery !== '' ? __('Поиск: :query', ['query' => $searchQuery]) : __('Поиск товаров'))
@section( @section(
'meta_description', 'meta_description',
$searchQuery !== '' $searchQuery !== ''
? "Найденные товары по запросу «{$searchQuery}». Выберите подходящий товар и откройте подробную карточку." ? __('Найденные товары по запросу «:query». Выберите подходящий товар и откройте подробную карточку.', ['query' => $searchQuery])
: 'Поиск товаров по наименованию: процессоры, видеокарты, материнские платы, ноутбуки и периферия.' : __('Поиск товаров по наименованию: процессоры, видеокарты, материнские платы, ноутбуки и периферия.')
) )
@section('meta_keywords', 'поиск товаров, результаты поиска, комплектующие пк, ноутбуки') @section('meta_keywords', __('поиск товаров, результаты поиска, комплектующие пк, ноутбуки'))
@section('meta_canonical', route('search.index')) @section('meta_canonical', route('search.index'))
@section('meta_robots', 'noindex,follow') @section('meta_robots', 'noindex,follow')
@@ -47,20 +47,20 @@
@section('content') @section('content')
@include('partials.breadcrumbs', [ @include('partials.breadcrumbs', [
'items' => [ 'items' => [
['label' => 'Главная', 'url' => route('home')], ['label' => __('Главная'), 'url' => route('home')],
['label' => 'Поиск', 'url' => null], ['label' => __('Поиск'), 'url' => null],
], ],
]) ])
<section class="pc-section"> <section class="pc-section">
<div class="pc-category-toolbar"> <div class="pc-category-toolbar">
<div class="pc-section-title"> <div class="pc-section-title">
<h2>{{ $searchQuery !== '' ? 'Результаты поиска' : 'Поиск товаров' }}</h2> <h2>{{ $searchQuery !== '' ? __('Результаты поиска') : __('Поиск товаров') }}</h2>
<p> <p>
@if ($searchQuery !== '') @if ($searchQuery !== '')
Запрос: "{{ $searchQuery }}" {{ __('Запрос: ":query"', ['query' => $searchQuery]) }}
@else @else
Введите название товара, чтобы увидеть найденные позиции. {{ __('Введите название товара, чтобы увидеть найденные позиции.') }}
@endif @endif
</p> </p>
</div> </div>
@@ -68,12 +68,12 @@
@if ($searchQuery !== '') @if ($searchQuery !== '')
<form class="pc-sort-form" method="get" action="{{ route('search.index') }}"> <form class="pc-sort-form" method="get" action="{{ route('search.index') }}">
<input type="hidden" name="q" value="{{ $searchQuery }}"> <input type="hidden" name="q" value="{{ $searchQuery }}">
<label for="sort">Сортировка:</label> <label for="sort">{{ __('Сортировка:') }}</label>
<select id="sort" name="sort" onchange="this.form.submit()"> <select id="sort" name="sort" onchange="this.form.submit()">
<option value="newest" @selected($sort === 'newest')>Сначала новые</option> <option value="newest" @selected($sort === 'newest')>{{ __('Сначала новые') }}</option>
<option value="price_asc" @selected($sort === 'price_asc')>Сначала дешевле</option> <option value="price_asc" @selected($sort === 'price_asc')>{{ __('Сначала дешевле') }}</option>
<option value="price_desc" @selected($sort === 'price_desc')>Сначала дороже</option> <option value="price_desc" @selected($sort === 'price_desc')>{{ __('Сначала дороже') }}</option>
<option value="name_asc" @selected($sort === 'name_asc')>По названию</option> <option value="name_asc" @selected($sort === 'name_asc')>{{ __('По названию') }}</option>
</select> </select>
</form> </form>
@endif @endif
@@ -81,26 +81,26 @@
<form class="pc-search-page-form" method="get" action="{{ route('search.index') }}"> <form class="pc-search-page-form" method="get" action="{{ route('search.index') }}">
<div class="pc-search"> <div class="pc-search">
<input type="text" name="q" placeholder="Например, Ryzen 7 или RTX 4060" value="{{ $searchQuery }}"> <input type="text" name="q" placeholder="{{ __('Например, Ryzen 7 или RTX 4060') }}" value="{{ $searchQuery }}">
</div> </div>
<button class="pc-btn primary" type="submit">Найти</button> <button class="pc-btn primary" type="submit">{{ __('Найти') }}</button>
@if ($searchQuery !== '') @if ($searchQuery !== '')
<a class="pc-btn ghost" href="{{ route('search.index') }}">Очистить</a> <a class="pc-btn ghost" href="{{ route('search.index') }}">{{ __('Очистить') }}</a>
@endif @endif
</form> </form>
@if ($searchQuery === '') @if ($searchQuery === '')
<div class="pc-card"> <div class="pc-card">
Введите запрос в строку поиска, чтобы открыть список найденных товаров. {{ __('Введите запрос в строку поиска, чтобы открыть список найденных товаров.') }}
</div> </div>
@else @else
<p class="pc-muted">Найдено товаров: <strong>{{ $products->total() }}</strong></p> <p class="pc-muted">{{ __('Найдено товаров:') }} <strong>{{ $products->total() }}</strong></p>
<div class="pc-products-grid"> <div class="pc-products-grid">
@forelse ($products as $product) @forelse ($products as $product)
@include('partials.product-card', ['product' => $product]) @include('partials.product-card', ['product' => $product])
@empty @empty
<div class="pc-card">По вашему запросу ничего не найдено.</div> <div class="pc-card">{{ __('По вашему запросу ничего не найдено.') }}</div>
@endforelse @endforelse
</div> </div>

View File

@@ -7,6 +7,7 @@ use App\Http\Controllers\Admin\ChatController as AdminChatController;
use App\Http\Controllers\Admin\HomeSlideController as AdminHomeSlideController; use App\Http\Controllers\Admin\HomeSlideController as AdminHomeSlideController;
use App\Http\Controllers\Admin\OrderController as AdminOrderController; use App\Http\Controllers\Admin\OrderController as AdminOrderController;
use App\Http\Controllers\Admin\ProductController as AdminProductController; use App\Http\Controllers\Admin\ProductController as AdminProductController;
use App\Http\Controllers\LocaleController;
use App\Http\Controllers\SitemapController; use App\Http\Controllers\SitemapController;
use App\Http\Controllers\Shop\AccountController; use App\Http\Controllers\Shop\AccountController;
use App\Http\Controllers\Shop\AuthController; use App\Http\Controllers\Shop\AuthController;
@@ -23,6 +24,7 @@ use App\Http\Controllers\Shop\ShopController;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
Route::get('/sitemap.xml', [SitemapController::class, 'index'])->name('sitemap'); Route::get('/sitemap.xml', [SitemapController::class, 'index'])->name('sitemap');
Route::post('/locale/{locale}', LocaleController::class)->name('locale.switch');
Route::get('/robots.txt', function () { Route::get('/robots.txt', function () {
$content = implode(PHP_EOL, [ $content = implode(PHP_EOL, [
'User-agent: *', 'User-agent: *',

View File

@@ -0,0 +1,37 @@
<?php
namespace Tests\Feature;
use Tests\TestCase;
class LocaleSwitchingTest extends TestCase
{
public function test_site_uses_russian_by_default(): void
{
$response = $this->get('/about');
$response->assertOk();
$response->assertSee('lang="ru"', false);
$response->assertSee('pc-lang-switcher-label">Рус<', false);
}
public function test_user_can_switch_site_locale_to_kazakh(): void
{
$response = $this->from('/about')->post('/locale/kk');
$response->assertRedirect('/about');
$response->assertSessionHas('locale', 'kk');
$this->withSession(['locale' => 'kk'])
->get('/about')
->assertOk()
->assertSee('lang="kk"', false)
->assertSee('pc-lang-switcher-label">Қаз<', false)
->assertSee('Басты бет');
}
public function test_unsupported_locale_returns_not_found(): void
{
$this->post('/locale/en')->assertNotFound();
}
}