OpenCart Multilingual and Multi-Currency Setup

Our company is engaged in the development, support and maintenance of sites of any complexity. From simple one-page sites to large-scale cluster systems built on micro services. Experience of developers is confirmed by certificates from vendors.
Development and maintenance of all types of websites:
Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Showing 1 of 1 servicesAll 2065 services
OpenCart Multilingual and Multi-Currency Setup
Medium
~2-3 business days
FAQ
Our competencies:
Development stages
Latest works
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    822
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    847
  • image_website-sbh_0.png
    Website development for SBH Partners
    999
  • image_website-_0.png
    Website development for Red Pear
    451

OpenCart Multilingual and Multicurrency Setup

OpenCart is designed from the ground up with multi-language and multi-currency support — this is not an add-on but part of the core. However, "works out of the box" and "configured correctly" are different things. Here we'll cover full setup cycle including SEO-URLs for each language, auto-updated exchange rates, and correct price display for different markets.

Installing Languages

OpenCart ships with English (en-gb). To add Russian, Belarusian, and other languages:

1. Download language pack.

Official languages available at opencart.com or github.com/opencart/opencart. OpenCart 4.x language pack structure:

ru-ru.zip
├── admin/language/ru-ru/
│   ├── common/
│   ├── catalog/
│   ├── customer/
│   └── ...
└── catalog/language/ru-ru/
    ├── common/
    ├── product/
    ├── checkout/
    └── ...

2. Install via Extension Installer:

Extensions → Extension Installer → Upload → ru-ru.zip

3. Activate language:

System → Localization → Languages → Add Language
→ Language Name: Russian
→ Code: ru-ru
→ Locale: ru_RU.UTF-8
→ Image: flag/ru.png
→ Directory: ru-ru
→ Sort Order: 1
→ Status: Enabled

Country flags for switcher — PNG files in catalog/view/image/flags/. Size: 16×11 px or 24×16 px.

4. Set default:

System → Settings → Local
→ Language: Russian
→ Administration Language: Russian (for admin panel)

Language Files and Translations

Custom strings in modules or themes added via language files:

// catalog/language/ru-ru/module/mymodule.php
$_['heading_title']   = 'My extension';
$_['text_add_cart']   = 'Add to Cart';
$_['text_in_stock']   = 'In Stock';
$_['text_out_stock']  = 'Out of Stock';
$_['text_preorder']   = 'Pre-order';
$_['error_required']  = 'This field is required!';

Usage in controller:

$this->load->language('module/mymodule');
$data['text_add_cart'] = $this->language->get('text_add_cart');

In Twig template:

<button>{{ text_add_cart }}</button>

Multilingual Product Content

Each product has description in each language. In database stored in oc_product_description table with language_id field:

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;

In product edit form — language tabs:

Product Edit → "Data" Tab:
  [Russian]     → name, description, meta tags in Russian
  [English]     → name, description, meta tags in English
  [Belarusian]  → name, description, meta tags in Belarusian

If translation missing for language — OpenCart displays default language description.

SEO-URLs for Multilingual

Each language has separate SEO-slug:

-- Russian URL
INSERT INTO oc_seo_url (store_id, language_id, key, value, keyword)
VALUES (0, 1, 'product_id', '123', 'black-office-chair');

-- English URL
INSERT INTO oc_seo_url (store_id, language_id, key, value, keyword)
VALUES (0, 2, 'product_id', '123', 'chernoe-ofisnoye-kreslo');

Or via UI: Product Edit → SEO Tab → Per-language URL keywords.

For correct multilingual SEO structure — set hreflang tags. OpenCart doesn't do this automatically, need custom code or extension:

{# In header.twig add hreflang #}
{% for lang in languages %}
<link rel="alternate"
      hreflang="{{ lang.code }}"
      href="{{ lang.href }}">
{% endfor %}
<link rel="alternate" hreflang="x-default" href="{{ canonical }}">

Data for languages passed from controller via header controller modification.

Language Switcher

In template — via common/language snippet:

{# In 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 — variable passed from common/header controller. Already contains list of available languages with href for current page.

Currency Configuration

Add currency:

System → Localization → Currencies → Add Currency
→ Currency Title: Belarusian Ruble
→ Code: BYN
→ Symbol Left: (empty)
→ Symbol Right: Br
→ Decimal Places: 2
→ Decimal Point: ,
→ Thousand Point: (space)
→ Value: 0.315  (rate to base currency)
→ Status: Enabled
→ Default: (if BYN — main store currency)

Example for three currencies store oriented to CIS:

Currency Code Symbol Decimals Default
Belarusian Ruble BYN Br 2 Yes
Russian Ruble RUB 2 No
US Dollar USD $ 2 No

Auto-update rates:

OpenCart supports auto-update via several sources. Default uses ECB (European Central Bank), inconvenient for BYN.

Configuration:

System → Settings → Local
→ Currency Auto Update: ECB (select source)

Manual update:

System → Localization → Currencies → Update Currency Rates

For automatic scheduled update — cron:

# Every day at 9:00
0 9 * * * /usr/bin/php /var/www/myshop/index.php \
    route=cron/currency \
    cron_token=YOUR_CRON_TOKEN

Or custom script parsing NBRB 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 as base
    }
}

Run via cron, result — current rates in database.

Currency Switcher

Switcher works via POST form to common/currency:

{# In 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>

Or via AJAX for change without page reload:

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()
    })
})

Multicurrency Pricing in Catalog

OpenCart stores all prices in base currency and recalculates on-the-fly via $this->currency->format(). This means when exchange rate changes, all displayed prices update automatically.

If you need fixed "nice" prices in each currency (e.g., 999 BYN instead of 998.73) — implement via custom total module or product-level fields with price calculation method override.

Multistore: Different Settings on Different Domains

OpenCart supports multiple stores with shared database:

System → Settings → Add Store
→ Store Name: Russia Store
→ URL: https://myshop.ru/
→ Default Language: Russian (ru-ru)
→ Default Currency: RUB

Each store (store_id) has own language, currency, theme, and product assortment settings. Products linked to specific store via "Links" tab in product editor.

In nginx — one server config, one PHP file, content determined by HTTP_HOST:

server {
    server_name myshop.by myshop.ru;
    root /var/www/myshop/public_html;
    # OpenCart itself determines store_id by domain
}

Common Issues

Catalog prices not updated after rate change. Cause — page caching. Solution: clear cache:

System → Tools → Cache → Clear

Or programmatically:

php index.php route=cron/cache cron_token=TOKEN

SEO-URLs duplicated for different languages. Each oc_seo_url record should have unique combination (store_id, language_id, keyword). Check:

SELECT keyword, COUNT(*) FROM oc_seo_url
GROUP BY keyword HAVING COUNT(*) > 1;

Language switching goes to homepage. Need to pass redirect with current URL when switching. Standard language controller implements this, but some themes remove hidden field from form.

Setup Timeline

  • Install languages (2–3) + translate products: 1–2 days
  • SEO-URLs for each language + hreflang: 1 day
  • Currency setup + auto-update rates (NBRB/CB RF): 0.5–1 day
  • Language and currency switchers in theme: 0.5 day
  • Multistore (different domains): +1–2 days

Total with ready theme: 2–4 days.