Настройка мультиязычности и мультивалютности OpenCart
OpenCart изначально спроектирован с поддержкой нескольких языков и валют — это не дополнение, а часть ядра. Но «работает из коробки» и «настроено правильно» — разные вещи. Здесь разберём полный цикл настройки, включая SEO-URL для каждого языка, автообновление курсов и корректное отображение цен для разных рынков.
Установка языков
OpenCart поставляется с английским языком (en-gb). Для добавления русского, белорусского и других языков нужно:
1. Скачать языковой пакет.
Официальные языки доступны на opencart.com или github.com/opencart/opencart. Для OpenCart 4.x структура языкового пакета:
ru-ru.zip
├── admin/language/ru-ru/
│ ├── common/
│ ├── catalog/
│ ├── customer/
│ └── ...
└── catalog/language/ru-ru/
├── common/
├── product/
├── checkout/
└── ...
2. Установить через Extension Installer:
Extensions → Extension Installer → Upload → ru-ru.zip
3. Активировать язык:
System → Localization → Languages → Add Language
→ Language Name: Русский
→ Code: ru-ru
→ Locale: ru_RU.UTF-8
→ Image: flag/ru.png
→ Directory: ru-ru
→ Sort Order: 1
→ Status: Enabled
Флаги стран для переключателя — PNG-файлы в catalog/view/image/flags/. Размер: 16×11 px или 24×16 px.
4. Установить по умолчанию:
System → Settings → Local
→ Language: Русский
→ Administration Language: Русский (для панели управления)
Языковые файлы и переводы
Кастомные строки в модулях или темах добавляются через языковые файлы:
// catalog/language/ru-ru/module/mymodule.php
$_['heading_title'] = 'Моё расширение';
$_['text_add_cart'] = 'В корзину';
$_['text_in_stock'] = 'В наличии';
$_['text_out_stock'] = 'Нет в наличии';
$_['text_preorder'] = 'Предзаказ';
$_['error_required'] = 'Поле обязательно для заполнения!';
Использование в контроллере:
$this->load->language('module/mymodule');
$data['text_add_cart'] = $this->language->get('text_add_cart');
В Twig-шаблоне:
<button>{{ text_add_cart }}</button>
Мультиязычный контент товаров
Каждый товар имеет описание на каждом языке. В базе данных это хранится в таблице oc_product_description с полем language_id:
SELECT pd.name, pd.description, pd.meta_title, pd.meta_description, l.name as language
FROM oc_product_description pd
JOIN oc_language l ON pd.language_id = l.language_id
WHERE pd.product_id = 123;
В форме редактирования товара — вкладки по языкам:
Product Edit → Вкладка "Данные":
[Русский] → название, описание, метатеги на русском
[English] → name, description, meta tags in English
[Беларуская] → назва, апісанне
Если перевод отсутствует для языка — OpenCart отображает описание языка по умолчанию.
SEO-URL для мультиязычности
Для каждого языка — отдельный SEO-slug:
-- Русский URL
INSERT INTO oc_seo_url (store_id, language_id, key, value, keyword)
VALUES (0, 1, 'product_id', '123', 'kreslo-ofisnoe-chernoe');
-- Английский URL
INSERT INTO oc_seo_url (store_id, language_id, key, value, keyword)
VALUES (0, 2, 'product_id', '123', 'black-office-chair');
Или через UI: Product Edit → SEO Tab → Per-language URL keywords.
Для корректной мультиязычной SEO-структуры — задать hreflang-теги. OpenCart не делает это автоматически, нужен кастомный код или расширение:
{# В header.twig добавляем hreflang #}
{% for lang in languages %}
<link rel="alternate"
hreflang="{{ lang.code }}"
href="{{ lang.href }}">
{% endfor %}
<link rel="alternate" hreflang="x-default" href="{{ canonical }}">
Данные для languages передаются из контроллера через модификацию header-контроллера.
Переключатель языка
В шаблоне — через сниппет common/language:
{# В header.twig #}
<div class="language-switcher">
{% for language in languages %}
<a href="{{ language.href }}" class="{% if language.code == language_code %}active{% endif %}">
<img src="{{ language.image }}" alt="{{ language.name }}">
{{ language.name }}
</a>
{% endfor %}
</div>
languages — переменная, передаваемая из контроллера common/header. Она уже содержит список доступных языков с href для текущей страницы.
Настройка валют
Добавление валюты:
System → Localization → Currencies → Add Currency
→ Currency Title: Белорусский рубль
→ Code: BYN
→ Symbol Left: (пусто)
→ Symbol Right: Br
→ Decimal Places: 2
→ Decimal Point: ,
→ Thousand Point: (пробел)
→ Value: 0.315 (курс к базовой валюте)
→ Status: Enabled
→ Default: (если BYN — основная валюта магазина)
Пример для трёх валют магазина, ориентированного на СНГ:
| Валюта | Код | Символ | Decimals | Default |
|---|---|---|---|---|
| Белорусский рубль | BYN | Br | 2 | Да |
| Российский рубль | RUB | ₽ | 2 | Нет |
| Доллар США | USD | $ | 2 | Нет |
Автообновление курсов:
OpenCart поддерживает автообновление через несколько источников. По умолчанию используется ECB (Европейский центральный банк), что неудобно для BYN.
Конфигурация источника курсов:
System → Settings → Local
→ Currency Auto Update: ECB (выбрать источник)
Ручное обновление:
System → Localization → Currencies → Update Currency Rates
Для автоматического обновления по расписанию — cron:
# Каждый день в 9:00
0 9 * * * /usr/bin/php /var/www/myshop/index.php \
route=cron/currency \
cron_token=YOUR_CRON_TOKEN
Или кастомный скрипт с парсингом НБРБ API:
// shell/update_currencies.php
$nbrb = json_decode(file_get_contents('https://api.nbrb.by/exrates/rates?periodicity=0'), true);
$rates = array_column($nbrb, 'Cur_OfficialRate', 'Cur_Abbreviation');
$pdo = new PDO("mysql:host=localhost;dbname=opencart", 'user', 'pass');
foreach (['USD', 'EUR', 'RUB'] as $currency) {
if (isset($rates[$currency])) {
$stmt = $pdo->prepare(
"UPDATE oc_currency SET value = ?, date_modified = NOW() WHERE code = ?"
);
$stmt->execute([1 / $rates[$currency], $currency]); // BYN как базовая
}
}
Запуск через cron, результат — актуальные курсы в базе.
Переключатель валюты
Переключатель работает через форму POST к common/currency:
{# В header.twig #}
<div class="currency-switcher">
{% for currency in currencies %}
<form action="{{ action_currency }}" method="post">
<input type="hidden" name="code" value="{{ currency.code }}">
<input type="hidden" name="redirect" value="{{ redirect }}">
<button type="submit" class="{% if currency.code == currency_code %}active{% endif %}">
{{ currency.symbol_left }}{{ currency.symbol_right }} {{ currency.code }}
</button>
</form>
{% endfor %}
</div>
Или через AJAX для смены без перезагрузки страницы:
document.querySelectorAll('[data-currency]').forEach(btn => {
btn.addEventListener('click', async function() {
const code = this.dataset.currency
await fetch(actionCurrencyUrl, {
method: 'POST',
body: new URLSearchParams({ code, redirect: window.location.href })
})
window.location.reload()
})
})
Мультивалютные цены в каталоге
OpenCart хранит все цены в базовой валюте и пересчитывает на лету через $this->currency->format(). Это значит, что при изменении курса все отображаемые цены обновляются автоматически.
Если нужны зафиксированные «красивые» цены в каждой валюте (например, 999 BYN, а не 998.73) — это реализуется через кастомный total модуль или через поля на уровне товара с переопределением метода расчёта цены.
Мультимагазин: разные настройки на разных доменах
OpenCart поддерживает несколько магазинов с общей базой данных:
System → Settings → Add Store
→ Store Name: Магазин для России
→ URL: https://myshop.ru/
→ Default Language: Русский (ru-ru)
→ Default Currency: RUB
Каждый магазин (store_id) имеет свои настройки языка, валюты, шаблона и ассортимента. Товары привязываются к конкретному магазину через вкладку «Links» в редакторе товара.
В nginx — один сервер-конфиг, PHP-файл один, а контент определяется по HTTP_HOST:
server {
server_name myshop.by myshop.ru;
root /var/www/myshop/public_html;
# OpenCart сам определяет store_id по домену
}
Типичные проблемы
Цены в каталоге не обновились после смены курса. Причина — кеш страниц. Решение: очистить кеш:
System → Tools → Cache → Clear
Или программно:
php index.php route=cron/cache cron_token=TOKEN
SEO-URL дублируются для разных языков. Каждая запись в oc_seo_url должна иметь уникальное сочетание (store_id, language_id, keyword). Проверить:
SELECT keyword, COUNT(*) FROM oc_seo_url
GROUP BY keyword HAVING COUNT(*) > 1;
Переключение языка ведёт на главную. Нужно передавать redirect с текущим URL при переключении. В стандартном контроллере языка это реализовано, но некоторые темы убирают скрытое поле из формы.
Сроки настройки
- Установка языков (2–3 языка) + перевод товаров: 1–2 дня
- SEO-URL для каждого языка + hreflang: 1 день
- Настройка валют + автообновление курсов (НБРБ/ЦБ РФ): 0,5–1 день
- Переключатели языка и валюты в шаблоне: 0,5 дня
- Мультимагазин (разные домены): +1–2 дня
Итого при готовой теме: 2–4 дня.







