# Localization

Source: https://developers.swell.is/backend-api/localization

Content localization is supported by providing alternative values for each configured locale. Any string or array of strings can be set in multiple locales with the `$locale` parameter when creating or updating objects.

Locales can be specified with or without a country code (e.g., `en` and `en-US`).

## Set locale values

Use the format `$locale: { <code>: { <field>: value } }` with any `PUT` or `POST` request. For nested values, the `$locale` parameter must be defined on the nearest parent object.

All locale content is optional using this API, even if the setting **Require content for this locale** is enabled in the Swell dashboard.

### Example request

**Example setting localized content**

**cURL**

```bash
$ curl https://api.swell.store/products/5cad15bc9b14d1990724663a \
  -u store-id:secret-key \
  -d name="Test product" \
  -d $locale[fr][name]="Test produit" \
  -d $locale[fr][tags]="étiqueter1, étiqueter2" \
  -d $locale[es][name]="Producto de prueba" \
  -d $locale[es][tags]="etiqueta1, etiqueta2" \
  -X PUT
```

**Node**

```javascript
const { swell } = require('swell-node');
swell.init('store-id', 'secret-key');

await swell.put('/products/5cad15bc9b14d1990724663a', {
  name: 'Test product',
  tags: ['tag1', 'tag2'],
  $locale: {
    fr: {
      name: 'Test produit',
      tags: ['étiqueter1', 'étiqueter2']
    },
    es: {
      name: 'Producto de prueba',
      tags: ['etiqueta1', 'etiqueta2']
    },
  },
});
```

**PHP**

```php
<?php $swell = new \\Swell\\Client('store-id', 'secret-key');

$swell->put('/products/5cad15bc9b14d1990724663a', [
  'name' => 'Test product',
  'tags' => ['tag1', 'tag2'],
  '$locale' => [
    'fr' => [
      'name' => 'Test produit',
      'tags' => ['étiqueter1', 'étiqueter2']
    ],
    'es' => [
      'name' => 'Producto de prueba',
      'tags' => ['etiqueta1', 'etiqueta2']
    ],
  ],
]);
```

### Example response

```json
{
  "id": "5cad15bc9b14d1990724663a",
  "name": "Test product",
  "tags": ["tag1", "tag2"],
  "$locale": {
    "en": {
      "name": "Test product",
      "tags": ["tag1", "tag2"]
    },
    "fr": {
      "name": "Test produit",
      "tags": ["étiqueter1", "étiqueter2"]
    },
    "es": {
      "name": "Producto de prueba",
      "tags": ["etiqueta1", "etiqueta2"]
    }
  }
  ...
}
```


## Retrieve localized content

Use the query parameter `$locale: <code>`, or alternatively an HTTP header `X-Locale: <code>` with any `GET` request. All fields with localized values will be returned according to the locale code and fallback settings.

### Example request

**Example retrieving localized content**

**cURL**

```bash
$ curl 'https://api.swell.store/products?$locale=fr' \
  -u store-id:secret-key
```

**Node**

```javascript
const { swell } = require('swell-node');
swell.init('store-id', 'secret-key');

await swell.get('/products', {
  $locale: 'fr'
});
```

**PHP**

```php
<?php $swell = new \Swell\Client('store-id', 'secret-key');

$swell->get('/products', [
  '$locale' => 'fr'
]);
```

### Example response

```json
{
  "count": 36,
  "results": [
    {
      "id": "5cad15bc9b14d1990724663a",
      "name": "Test produit",
      "tags": ["étiqueter1", "étiqueter2"],
      ...
    }
  ],
  "page": 1,
  "page_count": 3,
  "limit": 15,
  ...
}
```


## Retrieve locale values

To retrieve records with `$locale` values in order to review localized content or build custom localization interfaces, pass an array of locale codes using the parameter `$locale: [<code>, ...]` with any `GET` request. All objects with `$locale` values will be returned matching the specific locale codes requested.

### Example request

**Example retrieving locale values**

**cURL**

```bash
$ curl https://api.swell.store/products?$locale=en,fr,es \
  -u store-id:secret-key
```

**Node**

```javascript
const { swell } = require('swell-node');
swell.init('store-id', 'secret-key');

await swell.get('/products', {
  $locale: ['en', 'fr', 'es']
});
```

**PHP**

```php
<?php $swell = new \\Swell\\Client('store-id', 'secret-key');

$swell->get('/products', [
  '$locale' => ['en', 'fr', 'es']
]);
```

### Example response

```json
{
  "count": 36,
  "results": [
    {
      "id": "5cad15bc9b14d1990724663a",
      "name": "Test product",
      "$locale": {
        "en": {
          "name": "Test product",
          "tags": ["tag1", "tag2"]
        },
        "fr": {
          "name": "Test produit",
          "tags": ["étiqueter1", "étiqueter2"]
        },
        "es": {
          "name": "Producto de prueba",
          "tags": ["etiqueta1", "etiqueta2"]
        }
      },
      ...
    }
  ],
  "page": 1,
  "page_count": 3,
  "limit": 15,
  ...
}
```


## Multi-currency

Every store has a base currency, and can enable additional currencies in settings. Each additional currency works in one of two modes: `priced`—you set explicit prices in that currency—or display, where prices are converted automatically from the base currency at the current exchange rate. Exchange rates come from a platform-level table that refreshes hourly.

#### Listing enabled currencies

Retrieve the store's currency configuration and current rates from `/:currencies`. Each entry's `type` is `base`, `priced`, or `display`:

```javascript
await swell.get('/:currencies');
```

```json
{
  "base": "USD",
  "rates": {
    "USD": 1,
    "EUR": 0.92,
    "AUD": 1.53
  },
  "config": [
    {
      "code": "USD",
      "rate": 1,
      "name": "US Dollar",
      "symbol": "$",
      "decimals": 2,
      "priced": true,
      "type": "base"
    },
    {
      "code": "EUR",
      "rate": 0.92,
      "name": "Euro",
      "symbol": "€",
      "decimals": 2,
      "priced": true,
      "type": "priced"
    },
    {
      "code": "AUD",
      "rate": 1.53,
      "name": "Australian Dollar",
      "symbol": "A$",
      "decimals": 2,
      "priced": false,
      "type": "display"
    }
  ]
}
```

#### Setting per-currency prices

For priced currencies, set explicit values by including a `$currency` object beside the regular fields, keyed by currency code (codes are uppercased automatically):

```javascript
await swell.put('/products/{id}', {
  id: '5ca24abb9c077817e5fe2b36',
  price: 15,
  $currency: {
    EUR: { price: 14 },
    GBP: { price: 12.5 }
  }
});
```

This works at any level where price fields live—the product root, `purchase_options` and their subscription plans, `prices` entries, options, and variants. Fields that support per-currency values are the currency-typed fields on each object, such as `price` and `sale_price`. Write responses always include the full `$currency` map, so you can confirm what is stored.

#### Reading prices in another currency

Pass `$currency` on a GET request to have price fields returned in that currency:

```javascript
// Prices flattened to EUR
await swell.get('/products/{id}', {
  id: '5ca24abb9c077817e5fe2b36',
  $currency: 'EUR'
});

// Keep the per-currency map for several currencies
await swell.get('/products/{id}', {
  id: '5ca24abb9c077817e5fe2b36',
  $currency: ['USD', 'EUR']
});
```

The value returned for each price field depends on the currency's configuration:

- Priced currency with an explicit stored value: the stored value is returned.
- Priced currency with no stored value: converted from the base price at the current rate when the currency has fallback conversion enabled; otherwise `null`.
- Display currency: always converted from the base price at the current rate, even if a stored value exists.
- Unconfigured currency code: no error is returned, and prices are left unchanged (or use stored values if any exist for that code).

Converted values are rounded using the currency's settings—`decimals`, and optional rounding to whole units or fraction endings (for example, prices ending in .95). With a single code, the response's `currency` field is set to the requested code and the `$currency` map is omitted; with an array of codes, the map is kept and filtered to the requested codes. `$currency` also applies to records brought in with `expand` and `include`.

#### Carts and orders in another currency

To transact in another currency, set the `currency` field on the cart or order—not the `$currency` parameter, which only affects how records are read:

```javascript
await swell.put('/carts/{id}', {
  id: '5cad15bc9b14d1990724663a',
  currency: 'EUR'
});
```

- A priced currency re-prices the cart in that currency—items need a price in it, either stored on the product or passed explicitly on the item.
- A display currency is recorded as `display_currency` while the transaction currency and totals are unchanged—the base currency for a new cart, or whatever currency the cart already transacts in.
- An inactive currency is rejected with an error, and the currency can't be changed after a payment has been made.

When a record's currency differs from the base currency, `currency_rate` is snapshotted at write time and not refreshed by later writes—pass `currency_rate: null` to recompute it at the current rate, or supply your own value.

