Prices, currencies and languages
A store can sell in several currencies and answer in several languages. Both are options on the client or on a
single call, and config() says which ones the store offers.
Price lists, one per currency
Every variant has a base price in its own currency. To sell in another currency, the merchant enables it in Storefront › Prices, which creates a price list, and enters prices in it (by hand, by import or through the API). A variant's price in a currency is:
- its entry in that currency's price list, when there is one;
- else its base price, when its base currency is that currency;
- else none: the variant has no price in that currency.
config() answers currencies (every base
currency in use plus every enabled price list) and defaultCurrency (the
catalog's default, used when a cart is created without a currency).
The currency option
Without currency, each variant is priced in its own base currency and a list
answer's currency is null. With it:
- Every price in the answer is in that currency: price ranges, variants, sorts and price filters.
- Product lists, search, suggestions and facet counts leave out products with no public variant priced in that currency.
-
A product page still answers such a product, with
availableInCurrency: false,priceRange: null, and every variant unpriced andpurchasable: false. It cannot be added to a cart in that currency: the cart refuses the line (NO_PRICE_IN_CURRENCY). -
A currency the store has not enabled answers
400 CURRENCY_NOT_ENABLED.
A cart has one currency. Switching currency makes a new cart with the same lines; see Cart and checkout.
import { createCatalogClient, isCatalogError } from '@usethrottle/catalog';
const catalog = createCatalogClient({
publishableKey: 'pc_pk_your_browser_key',
});
try {
const answer = await catalog.products.get('ceramic-brake-pads', {
currency: 'EUR',
});
if (!('redirectTo' in answer) && answer.product.availableInCurrency === false) {
// No EUR price: priceRange is null, every variant is unpriced and not
// purchasable, and a cart in EUR refuses it.
console.log('Not sold in EUR. Switch currency to buy it.');
}
} catch (error) {
if (isCatalogError(error) && error.code === 'CURRENCY_NOT_ENABLED') {
// The store has no EUR price list (see config().currencies).
console.log('EUR is not one of this store’s currencies.');
} else {
throw error;
}
}
Languages
The merchant sets a default language and up to 19 more in Storefront › Languages, and
translates products, categories, collections, options, attribute labels, filter labels and filter value labels.
Ask for a language with the locale option, a BCP 47 tag such as fr or fr-CA.
- The locale used. The catalog tries the tag, then its language (
fr-CA→fr), and takes the first one the store has enabled. A locale the store does not have is not an error: the answer comes in the default language. The answer'slocalenames the one used. - Field by field. A field without a translation in that locale falls back the same way, to the language and then to the default text, so a half-translated product still shows every field.
- What is not translated: variant fields, and reviews, which are shown as written.
- Search with a
localealso matches the locale's translated titles and descriptions.
In the SDK
Set currency and locale on createCatalogClient as defaults, and override them on any call. Each call sends
only what its route takes:
| Calls | Sends |
|---|---|
| products.list, products.get, products.related, filters.values, suggest, carts.create | currency and locale |
| carts.check | currency |
| categories.tree, categories.get, collections.list, collections.get, reviews.list | locale |
| tags.list, config, reviews.eligibility, reviews.submit | neither |
import { createCatalogClient } from '@usethrottle/catalog';
// What the store offers: build the currency and language pickers from it.
const setup = createCatalogClient({ publishableKey: 'pc_pk_your_browser_key' });
const config = await setup.config();
console.log(config.currencies, config.defaultCurrency);
console.log(config.locales, config.defaultLocale);
// Defaults for every call of this client...
const catalog = createCatalogClient({
publishableKey: 'pc_pk_your_browser_key',
currency: 'EUR',
locale: 'fr-CA',
});
const list = await catalog.products.list({ category: 'brakes' });
// Every price is in EUR; products with no EUR price are left out.
// `locale` names the language the catalog answered in (here `fr` if the
// store has French but not Canadian French).
console.log(list.currency, list.locale, list.products[0]?.priceRange);
// ...and per-call options win over them.
const pounds = await catalog.products.list(
{ category: 'brakes' },
{ currency: 'GBP', locale: 'en' },
);
console.log(pounds.currency);
Prices for a signed-in shopper (customer groups) are on Customer prices.