Skip to main content
Version: 2.11

Internationalization and Translation


Address forms#

Google’s address format database is used to provide location-specific address formats and forms. It also handles the address validation so you do not need to know how to address a package to China or whether they use postal codes in the United Arab Emirates (they don’t).

Currency conversion#

Saleor can use currency exchange rate data to show price estimations in the customer’s local currency.

How to configure Open Exchange Rates#

This integration will allow your customers to see product prices in their local currency. Local prices are only provided as an estimate; customers are still charged in your store’s default currency.

Before you begin, you will need an Open Exchange Rates account.


While the free subscription plan should be enough to update exchange rates once a day, consider paying for the excellent service that Open Exchange Rates provides.

Export the following environment variable:

  • OPENEXCHANGERATES_API_KEY: Your store’s Open Exchange Rates “App ID”.

To update exchange rates, run the following command at least once a day:

python update_exchange_rates --all

Heroku users can use the Scheduler add-on to automatically call the command at a pre-defined time each day.

Phone number format#

Saleor uses Google’s libphonenumber library to ensure that the phone numbers provided by your customers are correct. You need to choose the prefix and type the number separately. Regardless of which country has been selected, you may enter the phone number for any country format.


Saleor's storefront and dashboard are both prepared for translation.


Saleor uses Transifex to coordinate translations. If you wish to help, head to the translation dashboard.

All translations are handled by the community. Translation teams are open and everyone is welcome to request a new language.

Model Translation#

Saleor enables you to translate database content (for example, product descriptions).


Model translations are currently only accessible from the Python code. The backend and the storefront are prepared to handle the translated properties. GraphQL API and UI views will be added in future releases.

Model translations are available via TranslationProxy, defined on the to-be-translated Model.

TranslationProxy gets a user’s language and checks if there is an existing ModelTranslation available. If not, it will return the original (untranslated) property. Otherwise, the translated property is returned.

How to add a ModelTranslation#

Consider a product:

from django.db import models
from saleor.core.utils.translations import TranslationProxy

class Product(models.Model):    name = models.CharField(max_length=128)    description = models.CharField(max_length=256)    ...
    translated = TranslationProxy()

The product has several properties, but let's assume you want to translate just the name and description.

  1. Set a translated property to an instance of TranslationProxy.

  2. Use ProductTranslation to store your translated properties. It requires two base fields:

  • language_code: A language code to which this translation correlates.

  • product: ForeignKey relation to the translated object (in this case, it will be named product).

… and any other field you would like to translate. For the purpose of this example, a name and description were used.


TranslationProxy expects that the related_name, on the ForeignKey relation is set to translations.

from django.db import models

class ProductTranslation(models.Model):    language_code = models.CharField(max_length=10)    product = models.ForeignKey(        Product,        related_name="translations",        on_delete=models.CASCADE,    )    name = models.CharField(max_length=128)    description = models.CharField(max_length=256)
    class Meta:        unique_together = ("product", "language_code")

Remember to set unique_together on the product and language_code, there should be only one translation per product and per language.


ModelTranslation fields must always take the same arguments as the existing translatable model. For example, an inconsistency in the max_length attribute could lead to UI bugs when translation settings are switched on.

Using Model Translation#

Based on the above example, you can access translated properties via the TranslationProxy.

translated_name =

The translated property is returned if there is an existing ModelTranslation with the same language_code as the user’s currently active language. Otherwise, the original property (untranslated) is returned.