diff --git a/app/Http/Controllers/LocaleController.php b/app/Http/Controllers/LocaleController.php
new file mode 100644
index 0000000..28dccb3
--- /dev/null
+++ b/app/Http/Controllers/LocaleController.php
@@ -0,0 +1,20 @@
+session()->put('locale', $locale);
+
+ return back();
+ }
+}
diff --git a/app/Http/Controllers/Shop/AccountController.php b/app/Http/Controllers/Shop/AccountController.php
index ba04c8d..17f91f2 100644
--- a/app/Http/Controllers/Shop/AccountController.php
+++ b/app/Http/Controllers/Shop/AccountController.php
@@ -28,6 +28,6 @@ class AccountController extends Controller
$request->user()->update($validated);
- return back()->with('status', 'Данные профиля обновлены.');
+ return back()->with('status', __('Данные профиля обновлены.'));
}
}
diff --git a/app/Http/Controllers/Shop/AuthController.php b/app/Http/Controllers/Shop/AuthController.php
index bacba8c..99d6bc2 100644
--- a/app/Http/Controllers/Shop/AuthController.php
+++ b/app/Http/Controllers/Shop/AuthController.php
@@ -34,7 +34,7 @@ class AuthController extends Controller
if (!$this->captchaIsValid($request, self::LOGIN_CAPTCHA_CONTEXT)) {
return back()
->withInput($request->only('email', 'remember'))
- ->withErrors(['captcha' => 'Неверный ответ на капчу.']);
+ ->withErrors(['captcha' => __('Неверный ответ на капчу.')]);
}
$credentials = [
@@ -47,7 +47,7 @@ class AuthController extends Controller
if (!Auth::attempt($credentials, $remember)) {
return back()
->withInput($request->only('email', 'remember'))
- ->withErrors(['email' => 'Неверный email или пароль.']);
+ ->withErrors(['email' => __('Неверный email или пароль.')]);
}
$request->session()->regenerate();
@@ -75,7 +75,7 @@ class AuthController extends Controller
if (!$this->captchaIsValid($request, self::REGISTER_CAPTCHA_CONTEXT)) {
return back()
->withInput($request->only('name', 'email'))
- ->withErrors(['captcha' => 'Неверный ответ на капчу.']);
+ ->withErrors(['captcha' => __('Неверный ответ на капчу.')]);
}
$user = User::create([
diff --git a/app/Http/Controllers/Shop/CartController.php b/app/Http/Controllers/Shop/CartController.php
index 75f2de8..88eaecf 100644
--- a/app/Http/Controllers/Shop/CartController.php
+++ b/app/Http/Controllers/Shop/CartController.php
@@ -46,20 +46,20 @@ class CartController extends Controller
public function add(Product $product)
{
if (!$product->is_active || $product->stock < 1) {
- return back()->with('status', 'Товар сейчас недоступен для заказа.');
+ return back()->with('status', __('Товар сейчас недоступен для заказа.'));
}
$cart = (array) session()->get('cart', []);
$current = (int) ($cart[$product->id] ?? 0);
if ($current >= $product->stock) {
- return back()->with('status', 'В корзине уже максимальное доступное количество.');
+ return back()->with('status', __('В корзине уже максимальное доступное количество.'));
}
$cart[$product->id] = $current + 1;
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)
@@ -80,15 +80,15 @@ class CartController extends Controller
unset($cart[$product->id]);
session()->put('cart', $cart);
- return back()->with('status', "Товар \"{$product->name}\" удален из корзины.");
+ return back()->with('status', __('Товар ":name" удален из корзины.', ['name' => $product->name]));
}
$cart[$product->id] = $quantity;
session()->put('cart', $cart);
$message = $quantity < (int) $validated['quantity']
- ? 'Количество ограничено текущим остатком.'
- : 'Количество товара обновлено.';
+ ? __('Количество ограничено текущим остатком.')
+ : __('Количество товара обновлено.');
return back()->with('status', $message);
}
@@ -101,6 +101,6 @@ class CartController extends Controller
session()->put('cart', $cart);
}
- return back()->with('status', "Товар \"{$product->name}\" удален из корзины.");
+ return back()->with('status', __('Товар ":name" удален из корзины.', ['name' => $product->name]));
}
}
diff --git a/app/Http/Controllers/Shop/ChatController.php b/app/Http/Controllers/Shop/ChatController.php
index 706a5a6..b478719 100644
--- a/app/Http/Controllers/Shop/ChatController.php
+++ b/app/Http/Controllers/Shop/ChatController.php
@@ -40,7 +40,7 @@ class ChatController extends Controller
$messageText = $this->sanitizeMessage((string) $validated['message']);
if ($messageText === '') {
throw ValidationException::withMessages([
- 'message' => 'Сообщение содержит недопустимые символы.',
+ 'message' => __('Сообщение содержит недопустимые символы.'),
]);
}
@@ -156,7 +156,7 @@ class ChatController extends Controller
'status' => $conversation->status,
'is_closed' => $conversation->isClosed(),
'notice' => $conversation->isClosed()
- ? 'Чат закрыт администратором. Отправьте новое сообщение, чтобы начать новый диалог.'
+ ? __('Чат закрыт администратором. Отправьте новое сообщение, чтобы начать новый диалог.')
: null,
];
}
diff --git a/app/Http/Controllers/Shop/CheckoutController.php b/app/Http/Controllers/Shop/CheckoutController.php
index eb4e730..9402902 100644
--- a/app/Http/Controllers/Shop/CheckoutController.php
+++ b/app/Http/Controllers/Shop/CheckoutController.php
@@ -19,7 +19,7 @@ class CheckoutController extends Controller
$items = $this->cartItems($request);
if ($items->isEmpty()) {
- return redirect()->route('cart.index')->with('status', 'Корзина пустая. Добавьте товары перед оформлением.');
+ return redirect()->route('cart.index')->with('status', __('Корзина пустая. Добавьте товары перед оформлением.'));
}
return view('shop.checkout', [
@@ -34,7 +34,7 @@ class CheckoutController extends Controller
$items = $this->cartItems($request);
if ($items->isEmpty()) {
- return redirect()->route('cart.index')->with('status', 'Корзина пустая. Добавьте товары перед оформлением.');
+ return redirect()->route('cart.index')->with('status', __('Корзина пустая. Добавьте товары перед оформлением.'));
}
$validated = $request->validate([
@@ -56,12 +56,12 @@ class CheckoutController extends Controller
$items = $this->cartItems($request);
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);
if (!is_array($customer)) {
- return redirect()->route('checkout.show')->with('status', 'Сначала заполните данные получателя.');
+ return redirect()->route('checkout.show')->with('status', __('Сначала заполните данные получателя.'));
}
return view('shop.checkout-payment', [
@@ -77,12 +77,12 @@ class CheckoutController extends Controller
$items = $this->cartItems($request);
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);
if (!is_array($validated)) {
- return redirect()->route('checkout.show')->with('status', 'Сначала заполните данные получателя.');
+ return redirect()->route('checkout.show')->with('status', __('Сначала заполните данные получателя.'));
}
$validator = validator($validated, [
diff --git a/app/Http/Controllers/Shop/CompareController.php b/app/Http/Controllers/Shop/CompareController.php
index 206ce33..d506bbf 100644
--- a/app/Http/Controllers/Shop/CompareController.php
+++ b/app/Http/Controllers/Shop/CompareController.php
@@ -44,24 +44,24 @@ class CompareController extends Controller
$compare = array_values(array_filter($compare, fn (int $id) => $id !== $product->id));
session()->put('compare', $compare);
- return back()->with('status', "Товар \"{$product->name}\" удален из сравнения.");
+ return back()->with('status', __('Товар ":name" удален из сравнения.', ['name' => $product->name]));
}
if (count($compare) >= 4) {
- return back()->with('status', 'Можно сравнить не более 4 товаров одновременно.');
+ return back()->with('status', __('Можно сравнить не более 4 товаров одновременно.'));
}
$compare[] = $product->id;
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()
{
session()->forget('compare');
- return back()->with('status', 'Список сравнения очищен.');
+ return back()->with('status', __('Список сравнения очищен.'));
}
private function compareIds(): array
diff --git a/app/Http/Controllers/Shop/ContactController.php b/app/Http/Controllers/Shop/ContactController.php
index 36a6a63..c1f9490 100644
--- a/app/Http/Controllers/Shop/ContactController.php
+++ b/app/Http/Controllers/Shop/ContactController.php
@@ -24,7 +24,7 @@ class ContactController extends Controller
if ($botToken === '' || $chatId === '') {
return back()
->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);
@@ -41,16 +41,16 @@ class ContactController extends Controller
} catch (Throwable) {
return back()
->withInput()
- ->withErrors(['contact' => 'Не удалось отправить заявку в Telegram. Попробуйте еще раз.']);
+ ->withErrors(['contact' => __('Не удалось отправить заявку в Telegram. Попробуйте еще раз.')]);
}
if (!$response->successful() || $response->json('ok') !== true) {
return back()
->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
diff --git a/app/Http/Controllers/Shop/FavoriteController.php b/app/Http/Controllers/Shop/FavoriteController.php
index 34f432c..45573e7 100644
--- a/app/Http/Controllers/Shop/FavoriteController.php
+++ b/app/Http/Controllers/Shop/FavoriteController.php
@@ -34,13 +34,13 @@ class FavoriteController extends Controller
$favorites = array_values(array_filter($favorites, fn (int $id) => $id !== $product->id));
session()->put('favorites', $favorites);
- return back()->with('status', "Товар \"{$product->name}\" удален из избранного.");
+ return back()->with('status', __('Товар ":name" удален из избранного.', ['name' => $product->name]));
}
$favorites[] = $product->id;
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
diff --git a/app/Http/Middleware/SetLocale.php b/app/Http/Middleware/SetLocale.php
new file mode 100644
index 0000000..724def1
--- /dev/null
+++ b/app/Http/Middleware/SetLocale.php
@@ -0,0 +1,25 @@
+session()->get('locale', $defaultLocale);
+ if (!in_array($locale, $supportedLocales, true)) {
+ $locale = $defaultLocale;
+ }
+
+ app()->setLocale($locale);
+
+ return $next($request);
+ }
+}
diff --git a/app/Models/ChatConversation.php b/app/Models/ChatConversation.php
index 5595076..406bba6 100644
--- a/app/Models/ChatConversation.php
+++ b/app/Models/ChatConversation.php
@@ -47,7 +47,7 @@ class ChatConversation extends Model
return $this->user->name;
}
- return 'Гость #' . $this->id;
+ return __('Гость #:number', ['number' => $this->id]);
}
public function isClosed(): bool
diff --git a/app/Models/Order.php b/app/Models/Order.php
index 5032dca..7386890 100644
--- a/app/Models/Order.php
+++ b/app/Models/Order.php
@@ -43,8 +43,21 @@ class Order extends Model
public function getPaymentMethodLabelAttribute(): string
{
return match ($this->payment_method) {
- 'card_transfer' => 'Перевод по реквизитам (на карту)',
- default => 'Не указан',
+ 'card_transfer' => __('Перевод по реквизитам (на карту)'),
+ default => __('Не указан'),
+ };
+ }
+
+ public function getStatusLabelAttribute(): string
+ {
+ return match ($this->status) {
+ 'new' => __('Новый'),
+ 'processing' => __('В обработке'),
+ 'paid' => __('Оплачен'),
+ 'shipped' => __('Отправлен'),
+ 'completed' => __('Завершен'),
+ 'cancelled' => __('Отменен'),
+ default => (string) $this->status,
};
}
}
diff --git a/bootstrap/app.php b/bootstrap/app.php
index c183276..673c147 100644
--- a/bootstrap/app.php
+++ b/bootstrap/app.php
@@ -1,5 +1,6 @@
withMiddleware(function (Middleware $middleware): void {
- //
+ $middleware->web(append: [
+ SetLocale::class,
+ ]);
})
->withExceptions(function (Exceptions $exceptions): void {
//
diff --git a/config/app.php b/config/app.php
index 423eed5..587fb71 100644
--- a/config/app.php
+++ b/config/app.php
@@ -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',
+ ],
+ ],
/*
|--------------------------------------------------------------------------
diff --git a/deploy/nginx/pc-shop.conf b/deploy/nginx/pc-shop.conf
index e2abad2..c5cc046 100644
--- a/deploy/nginx/pc-shop.conf
+++ b/deploy/nginx/pc-shop.conf
@@ -1,7 +1,7 @@
server {
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;
location ^~ /.well-known/acme-challenge/ {
@@ -17,12 +17,12 @@ server {
server {
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;
index index.php;
- ssl_certificate /etc/letsencrypt/live/shop.example.com/fullchain.pem;
- ssl_certificate_key /etc/letsencrypt/live/shop.example.com/privkey.pem;
+ ssl_certificate /etc/letsencrypt/live/tehnobox.shop/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/tehnobox.shop/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
diff --git a/lang/kk.json b/lang/kk.json
new file mode 100644
index 0000000..68474d8
--- /dev/null
+++ b/lang/kk.json
@@ -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",
+ "Wi‑Fi": "Wi‑Fi",
+ "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, Техноград",
+ "Материнские платы.": "Аналық платалар.",
+ "Производитель": "Өндіруші",
+ "Производитель видеокарты": "Бейнекарта өндірушісі",
+ "Производитель процессора": "Процессор өндірушісі",
+ "Память": "Жад",
+ "Оперативная память": "Жедел жад",
+ "Системы охлаждения.": "Салқындату жүйелері.",
+ "Төлем": "Төлем"
+}
diff --git a/resources/css/app.css b/resources/css/app.css
index 7fa1583..51b583d 100644
--- a/resources/css/app.css
+++ b/resources/css/app.css
@@ -138,12 +138,150 @@ body.pc-body {
justify-content: center;
}
+.pc-header-tools {
+ display: flex;
+ align-items: center;
+}
+
.pc-header-icons {
display: flex;
gap: 14px;
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 {
display: none;
}
@@ -2560,14 +2698,18 @@ body.pc-body {
letter-spacing: 0.08em;
}
+ .pc-header-tools {
+ display: none;
+ }
+
.pc-catalog-btn {
display: none;
}
.pc-hamburger {
display: inline-flex;
- order: 2;
- margin-left: auto;
+ order: 3;
+ margin-left: 0;
}
.pc-mobile-menu-head {
@@ -2610,11 +2752,33 @@ body.pc-body {
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 {
display: flex;
flex-direction: column;
gap: 10px;
- order: 3;
+ order: 4;
width: 100%;
padding-top: 0;
border-top: 0;
@@ -2625,7 +2789,7 @@ body.pc-body {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 8px;
- order: 4;
+ order: 5;
width: 100%;
}
@@ -2634,6 +2798,7 @@ body.pc-body {
grid-template-columns: 1fr;
gap: 6px;
width: 100%;
+ order: 6;
max-height: none;
opacity: 1;
overflow: visible;
diff --git a/resources/js/app.js b/resources/js/app.js
index 9964029..615ef7e 100644
--- a/resources/js/app.js
+++ b/resources/js/app.js
@@ -54,6 +54,8 @@ const initChatWidget = () => {
const fetchUrl = widget.dataset.fetchUrl;
const sendUrl = widget.dataset.sendUrl;
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 submitButton = form.querySelector('button[type="submit"]');
@@ -83,7 +85,7 @@ const initChatWidget = () => {
note.textContent = conversationClosed && closedNotice !== '' ? closedNotice : defaultNoteText;
}
- submitButton.textContent = conversationClosed ? 'Начать новый чат' : 'Отправить';
+ submitButton.textContent = conversationClosed ? restartLabel : sendLabel;
if (conversationClosed) {
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) => {
const form = event.target;
if (!(form instanceof HTMLFormElement)) {
@@ -620,3 +662,4 @@ initHomeSliders();
initProductCarousels();
initProductGallery();
initCategoryFilterToggle();
+initLanguageSwitchers();
diff --git a/resources/views/components/chat-widget.blade.php b/resources/views/components/chat-widget.blade.php
index 0e2ed9d..07364b8 100644
--- a/resources/views/components/chat-widget.blade.php
+++ b/resources/views/components/chat-widget.blade.php
@@ -4,32 +4,34 @@
data-fetch-url="{{ route('chat.messages') }}"
data-send-url="{{ route('chat.send') }}"
data-csrf="{{ csrf_token() }}"
+ data-send-label="{{ __('Отправить') }}"
+ data-restart-label="{{ __('Начать новый чат') }}"
>
Задайте вопрос — администратор ответит в этом окне. {{ __('Задайте вопрос — администратор ответит в этом окне.') }}Онлайн-чат
-
+ {{ __('Онлайн-чат') }}
+