---
title: Usage
---

# Usage

Internationalization (i18n) is an essential part of developing Smart MiniApp or Panel MiniApp. It helps applications adapt to users from different languages and cultures, improving user experience and market reach. Therefore, we have built an I18N module into the `Panel SDK`. This module extends the functionalities of the [built-in I18n object](/en/miniapp/develop/miniapp/guide/i18n/config) to meet the multilingual needs of Panel MiniApp.

## Getting Started

First, ensure that you have installed `@ray-js/panel-sdk`. You can install it using the following command:

```bash
$ yarn add @ray-js/panel-sdk
```

Then ensure the project's multilingual file structure is as shown below. You can refer to the [public-sdm template](https://github.com/Tuya-Community/tuya-ray-materials/tree/main/template/PublicSdmTemplate):

```bash
├── src
│   ├── i18n
│   │   ├── index.ts # Multilingual instance export
│   │   └── strings.ts # Multilingual definitions
│   └── ...
```

### Define Multilingual Strings

<Callout type="info" emoji="ℹ️">
  Local code's multilingual strings are generally only used for quickly viewing the multilingual entries involved in the project and for fallback in case of exceptions, such as when online multilingual strings are empty. Additionally, local code cannot fully support multiple regions for other languages like zh_CN, en_GB, etc. Therefore, it is recommended not to define multilingual strings other than Chinese and English in local code.
</Callout>

Edit the `src/i18n/strings.{js,ts}` file.

```javascript
// Both en and zh must be defined
export default {
  en: {
    hello: 'Hello',
    // More language entries
  },
  zh: {
    hello: '您好',
    // More language entries
  },
};
```

### Instantiate Multilingual Strings

Instantiate and export in the `src/i18n/index.{js,ts}` file.

```javascript
import { kit } from '@ray-js/panel-sdk';
import strings from './strings';

const { I18N } = kit;

const Strings = new I18N(strings);

export default Strings;
```

### Use Multilingual Strings

You can call it in any scenario where multilingual strings are needed. For example, in a component:

```javascript
import React from 'react';
import Strings from '../i18n';

const MyComponent = () => (
  <div>
    {Strings.getLang('hello')}
  </div>
);

export default MyComponent;
```

### Platform Configuration for Multilingual Strings

#### Configure MiniApp Multilingual Strings

MiniApp multilingual strings need to be added on the [MiniApp Developer Platform](https://platform.tuya.com/miniapp/). Select the corresponding MiniApp and click on the **Multilingual Management** sidebar.

<Image
  src="/images/panel/panel-i18n-platform.en-US.png"
  style={{
    borderRadius: '10px',
    width: '618px',
    boxShadow: '0 0 5px rgba(0,0,0,0.3)',
  }}
/>

#### Configure Product Multilingual Strings

<Callout type="info" emoji="ℹ️">
  Product multilingual strings only apply to Panel MiniApp, and the configuration priority of product multilingual strings is higher than that of Panel MiniApp. See [Q: What is the multilingual logic of Panel MiniApp?](#q-what-is-the-multilingual-logic-of-panel-MiniApp)
</Callout>

Product multilingual strings need to be added on the [Tuya Developer Platform - Product Multilingual](https://platform.tuya.com/exp/i18n/multilingual). Select the corresponding product and click on the corresponding tab to configure the multilingual strings.

<Image
  src="/images/panel/panel-i18n-product.en-US.png"
  style={{
    borderRadius: '10px',
    width: '618px',
    boxShadow: '0 0 5px rgba(0,0,0,0.3)',
  }}
/>

## Advanced Development

### Multilingual Specifications

```javascript
export default {
  en: {
    dsc_edit: 'Edit', // Basic multilingual strings with dsc_ start and name it semantically
    dsc_hour: 'Hour',
    dsc_minute: 'Minute',
    dsc_countdown_on: 'Turn on after {0}{1}',
    dp_switch: 'Switch', // Datapoint (DP) related multilingual strings should be in accordance with `dp_${dpCode}`
    dp_switch_on: 'Switch is On', // Boolean type datapoint related multilingual strings should be in accordance with `dp_${dpCode}_${'on' || 'off'}`
    dp_mode_smart: 'Smart Mode', // Enum type datapoint related multilingual strings should be in accordance with `dp_${dpCode}_${enumValue}`
    dp_fault_0: 'Binary first bit is faulty', // Bitmap type datapoint related multilingual strings should be in accordance with `dp_${dpCode}_${bit}`
    dp_fault_1: 'Binary second bit is faulty', // How to use of bitmap, see https://support.tuya.com/en/help/_detail/K9mc4euc6tq9i
  },
  zh: {
    dsc_edit: '编辑', // Basic multilingual strings with dsc_ start and name it semantically
    dsc_hour: '时',
    dsc_minute: '分',
    dsc_countdown_on: '设备将在{0}{1}后开启',
    dp_switch: '开关', // Datapoint (DP) related multilingual strings should be in accordance with `dp_${dpCode}`
    dp_switch_on: '开关开', // Boolean type datapoint related multilingual strings should be in accordance with `dp_${dpCode}_${'on' || 'off'}`
    dp_mode_smart: '智能模式', // Enum type datapoint related multilingual strings should be in accordance with `dp_${dpCode}_${enumValue}`
    dp_fault_0: '第一位故障', // Bitmap type datapoint related multilingual strings should be in accordance with `dp_${dpCode}_${bit}`
    dp_fault_1: '第二位故障', // How to use of bitmap, see https://support.tuya.com/zh/help/_detail/K9mc4euc6tq9i
  },
};
```

### Multilingual API

#### Get Multilingual String

**Name**

getLang

**Description**

Gets the multilingual string corresponding to the key value. If it does not exist in the current language, it will look up in `en`. If it does not exist either, it returns `defaultValue` or `${key}`.

**Request Parameters**

| Parameter    | Data Type | Description                            | Required |
| :----------- | :-------  | :------------------------------------- | :------- |
| key          | `string`  | Multilingual key value                 | Yes      |
| defaultValue | `string`  | Default value, returned if not found   | No       |

**Return Parameters**

| Parameter | Data Type | Description                                         |
| :-------- | :-------  | :-------------------------------------------------- |
| result    | `string`  | Returns the multilingual string corresponding to the key value, or defaultValue |

**Request Example**

```javascript
// Request example corresponding to multilingual data source
// export default {
//   en: {
//     dsc_edit: 'Edit',
//     dsc_edit_en: 'Edit',
//   },
//   zh: {
//     dsc_edit: '编辑',
//   },
// };
import Strings from '../i18n';

Strings.getLang('dsc_edit'); // Assume the current language environment is zh, get the configured multilingual string
Strings.getLang('dsc_edit_en'); // Assume the current language environment is zh, but zh does not have this entry, it will look up in en
Strings.getLang('dsc_edit_not_exist'); // Assume the current language environment is zh, get the unconfigured multilingual string
```

**Return Example**

```javascript
'编辑' // Assume the current language environment is zh, get the configured multilingual string
'Edit' // Assume the current language environment is zh, but zh does not have this entry, it will look up in en
'dsc_edit_not_exist'; // Assume the current language environment is zh, get the unconfigured multilingual string
```

#### Get Datapoint Multilingual String

**Name**

getDpLang

**Description**

Gets the multilingual string corresponding to the DP code. If it does not exist in the current language, it will look up in `en`. If it does not exist either, it returns `dp_${code}_${value}`.

<Callout type="info" emoji="ℹ️">
  Compared with getLang, getDpLang is mainly used to standardize the acquisition of multilingual strings related to datapoints, generally only used in Panel MiniApp.<br/>
  For example: getLang('dp_switch_on') is equivalent to getDpLang('switch'.toLowerCase(), true);
</Callout>

**Request Parameters**

| Parameter | Data Type                  | Description           | Required |
| :-------- | :------------------------- | :-------------------- | :------- |
| code      | `string`                   | DP code               | Yes      |
| value     | `string\|boolean\|number`  | Corresponding DP value | No       |

**Return Parameters**

| Parameter | Data Type | Description                           |
| :-------- | :-------  | :------------------------------------- |
| result    | `string`  | Returns the multilingual string corresponding to the key value, or code |

**Request Example**

```javascript
// Request example corresponding to multilingual data source
// export default {
//   en: {
//     dp_switch: 'Switch', // Datapoint (DP) related multilingual strings should be in accordance with `dp_${dpCode}`
//     dp_switch_on: 'Switch is On', // Boolean type datapoint related multilingual strings should be in accordance with `dp_${dpCode}_${'on' || 'off'}`
//   },
//   zh: {
//     dp_switch: '开关', // Datapoint (DP) related multilingual strings should be in accordance with `dp_${dpCode}`
//     dp_switch_on: '开关开', // Boolean type datapoint related multilingual strings should be in accordance with `dp_${dpCode}_${'on' || 'off'}`
//   },
// };
import Strings from '../i18n';

Strings.getDpLang('switch'); // Assume the current language environment is zh, get the configured datapoint multilingual string
Strings.getDpLang('switch', true); // Assume the current language environment is zh, get the configured datapoint state multilingual string
Strings.getDpLang('switch', false); // Assume the current language environment is zh, get the unconfigured datapoint state multilingual string
```

**Return Example**

```javascript
'开关' // Assume the current language environment is zh, get the configured datapoint multilingual string
'开关开' // Assume the current language environment is zh, get the configured datapoint state multilingual string
'dp_switch_off'; // Assume the current language environment is zh, get the unconfigured datapoint state multilingual string
```

#### Get Datapoint Name

**Name**

getDpName

**Description**

Gets the name corresponding to the DP point.

<Callout type="info" emoji="ℹ️">
  For the sake of DP naming conventions, the passed DP code will be converted to lowercase letters, such as `Switch` will be converted to `switch`, generally only used in Panel MiniApp.
</Callout>

**Request Parameters**

| Parameter    | Data Type | Description | Required |
| :----------- | :-------  | :---------- | :------- |
| code         | `string`  | DP code     | Yes      |
| defaultName  | `string`  | Default name | Yes     |

**Return Parameters**

| Parameter | Data Type | Description                                |
| :-------- | :-------  | :------------------------------------------ |
| result    | `string`  | Returns the multilingual string corresponding to the key value, or defaultName |

**Request Example**

```javascript
// export default {
//   en: {
//     dp_switch: 'Switch', // Datapoint (DP) related multilingual strings should be in accordance with `dp_${dpCode}`
//   },
//   zh: {
//     dp_switch: '开关', // Datapoint (DP) related multilingual strings should be in accordance with `dp_${dpCode}`
//   },
// };
import Strings from '../i18n';

Strings.getDpName('switch', '插座开关'); // Assume the current language environment is zh, get the configured datapoint multilingual string
Strings.getDpName('switch_led', '彩光开关'); // Assume the current language environment is zh, get the unconfigured datapoint multilingual string
```

**Return Example**

```javascript
'开关'
'彩光开关'
```

#### Get Fault Datapoint Multilingual String

**Name**

getFaultLang

**Description**

Gets the multilingual strings corresponding to fault-type datapoints (Bitmap type). This method is used to handle multilingual display of device fault information, supporting bit-wise parsing of fault codes and returning corresponding multilingual descriptions. Compared with the deprecated `getFaultStrings`, `getFaultLang` provides a more modern parameter structure and more flexible configuration options.

<Callout type="info" emoji="ℹ️">
  getFaultLang is specifically designed for processing Bitmap type fault datapoints, obtaining corresponding fault descriptions by parsing each bit of the fault value. The multilingual key follows the `dp_${faultCode}_${label}` naming convention. This API is supported starting from `@ray-js/panel-sdk` version 1.14.0.
</Callout>

**Request Parameters**

| Parameter          | Data Type           | Description                                                                    | Required             |
| :----------------- | :------------------ | :----------------------------------------------------------------------------- | :------------------- |
| faultCode          | `string`            | DP code, must be a fault-type datapoint code                                  | Yes                  |
| faultValue         | `number`            | Fault value, used for bit-wise parsing of fault status                        | Yes                  |
| options            | `object`            | Configuration options                                                          | Yes                  |
| options.schema     | `object`            | Fault-type datapoint schema information, must contain `property.label` array  | Yes                  |
| options.mode       | `'first'\|'all'`    | Return mode: 'first' returns the first fault, 'all' returns all faults       | No, default 'first'  |
| options.targetBits | `number[]`          | Array of specified fault bit positions to process, processes all bits if not specified | No                   |

**Return Parameters**

| Parameter | Data Type | Description                                                    |
| :-------- | :-------- | :------------------------------------------------------------- |
| result    | `string`  | Returns fault multilingual strings, separated by commas for multiple faults |

**Request Example**

```javascript
// Request example corresponding to multilingual data source
// export default {
//   en: {
//     dp_fault_motor_fault: 'Motor Fault',       // Corresponds to schema.property.label[0]
//     dp_fault_sensor_error: 'Sensor Error',     // Corresponds to schema.property.label[1]  
//     dp_fault_overheat: 'Overheat Protection',  // Corresponds to schema.property.label[2]
//   },
//   zh: {
//     dp_fault_motor_fault: '电机故障',            // Corresponds to schema.property.label[0]
//     dp_fault_sensor_error: '传感器错误',         // Corresponds to schema.property.label[1]
//     dp_fault_overheat: '过热保护',               // Corresponds to schema.property.label[2]
//   },
// };

import Strings from '../i18n';

// Schema definition
const faultSchema = {
  property: {
    label: ['motor_fault', 'sensor_error', 'overheat']
  }
};

// Example 1: Get first fault (default mode)
Strings.getFaultLang('fault', 5, { 
  schema: faultSchema 
}); 
// faultValue = 5 (binary 101), bits 0 and 2 are 1

// Example 2: Get all faults
Strings.getFaultLang('fault', 7, { 
  schema: faultSchema, 
  mode: 'all' 
}); 
// faultValue = 7 (binary 111), all bits are 1

// Example 3: Process only specified fault bits
Strings.getFaultLang('fault', 7, { 
  schema: faultSchema, 
  mode: 'all',
  targetBits: [0, 2] 
});
// Only check bits 0 and 2 for faults
```

**Return Example**

```javascript
'Motor Fault'                                    // Example 1: mode='first', returns first matching fault
'Motor Fault, Sensor Error, Overheat Protection' // Example 2: mode='all', returns all faults
'Motor Fault, Overheat Protection'               // Example 3: specified targetBits, returns only specified bit faults
```

#### Replace Multilingual Template Variables

**Name**

formatValue

**Description**

The `formatValue` method is used to get the template string of the specified key from the language package and replace the passed values in the placeholder positions of the template string.

**Request Parameters**

| Parameter | Data Type | Description                                                  | Required |
| :-------- | :-------- | :----------------------------------------------------------- | :------- |
| key       | `string`  | Key in the language package to get the corresponding template string | Yes      |
| ...values | `string[]` | Variable parameters, representing the values to replace in the template string. Each value will replace the placeholders {0}, {1}, {2} in order. | Yes      |

**Return Parameters**

| Parameter | Data Type | Description                     |
| :-------- | :-------- | :------------------------------ |
| result    | `string`  | Returns the replaced string     |

**Request Example**

```javascript
// export default {
//   en: {
//     dsc_countdown_on: 'Turn on after {0}{1}',
//   },
//   zh: {
//     dsc_countdown_on: '设备将在{0}{1}后开启',
//   },
// };
import Strings from '../i18n';

// Correct usage: Replace parameters into template string placeholders
Strings.formatValue('dsc_countdown_on', '1 hour', '5 minutes');

// ❌ Incorrect example: Do not use pure numbers as multilingual keys
// If multilingual configuration contains { "0": "hour", "1": "minute" }
// Calling Strings.formatValue('dsc_countdown_on', '1', '5') may cause unexpected replacement results
```

**Return Example**

```javascript
'Turn on after 1 hour5 minutes'
```

**Notes**

<Callout type="warning" emoji="⚠️">
  Please ensure that numbers like `0-9` are not used as keys for multilingual configuration, as the underlying implementation is based on `I18n.t`. For details, refer to [Multilingual Placeholders](/en/miniapp/develop/miniapp/guide/i18n/config#multi-language-placeholders).
</Callout>

### Multilingual Language Switching Test

The language environment of the MiniApp depends on the current running environment, i.e., `Tuya MiniApp IDE` or `App Real Machine`. Currently, dynamic language switching is not supported. If you need to perform language switching tests, you can do so by the following methods:

- Switch the language on the `App Real Machine`.
  - iOS: [Change the language on your iPhone or iPad](https://support.apple.com/en-us/109358)
  - Android: [Change the language of apps on your Android phone](https://support.google.com/android/answer/12395118?hl=en)
- Switch the language in the `Tuya MiniApp IDE`, as shown below.
<Image src='/images/panel/panel-i18n-ide.png' />

## FAQs

<Callout type="info" emoji="ℹ️">
  For more multilingual FAQs, see [Help Center - Multilingual](https://support.tuya.com/en/help/_list?category=Cbutcmllzdtzl)
</Callout>

### Q: Why does the multilingual string defined in my local code not take effect?

A: The multilingual string defined locally has a lower priority than the multilingual string uploaded on the platform. If the multilingual string is uploaded on the platform, the locally defined multilingual string will not take effect.

### Q: Why does the multilingual string I modified on the MiniApp platform not take effect?

A1: If it is a `Smart MiniApp`, if you confirm that the multilingual key used in the business code is consistent with the multilingual key modified on the platform, and you have cleared the app cache and re-entered the MiniApp, if it still does not take effect, please contact Tuya technical support.

A2: If it is a `Panel MiniApp`, follow the steps below to troubleshoot:

1. Check whether the Panel MiniApp associated with the device's corresponding product is currently running in the `Tuya MiniApp IDE` or on the App real machine.

<Callout type="warning" emoji="⚠️">
  Note 1: The multilingual strings of the Panel MiniApp during runtime are based on the product associated with the current device, which means the multilingual strings of the current product associated with the Panel MiniApp are fetched. Therefore, if the multilingual strings of other MiniApp are modified, they will not take effect. For more details, see [Q: What is the multilingual logic of Panel MiniApp?](#q-what-is-the-multilingual-logic-of-panel-MiniApp)
</Callout>

2. Check whether the product associated with the device currently running in the `Tuya MiniApp IDE` or on the App real machine has the same multilingual key configured and has written different multilingual values.

<Callout type="warning" emoji="⚠️">
  Note 2: The configuration priority of product multilingual strings is higher than that of Panel MiniApp multilingual strings. For more details, see [Q: What is the multilingual logic of Panel MiniApp?](#q-what-is-the-multilingual-logic-of-panel-MiniApp)
</Callout>

3. If you confirm that the above two steps are correct, and you have cleared the app cache and re-entered the MiniApp, if it still does not take effect, please contact Tuya technical support.

### Q: What is the multilingual logic of Panel MiniApp?

A: Since Panel MiniApp can be associated with multiple products at the same time, and different products may require different multilingual configurations, the multilingual design logic of Panel MiniApp is as follows:

| Multilingual Type | Priority | Configuration Scenario | Source Screenshot |
| --- | --- | --- | --- |
| Local Multilingual Strings <div style={{ minWidth: '120px' }} /> | `3` <div style={{ minWidth: '30px' }} /> | 1. Quickly view the multilingual entries involved in the project. <br/> 2. Used for fallback when online multilingual cannot be retrieved.<div style={{ minWidth: '200px' }} /> | <Image style={{ boxShadow: '0 0 5px rgba(0,0,0,0.3)' }} src='/images/panel/panel-i18n-local.png'/> |
| Panel MiniApp Multilingual Strings <div style={{ minWidth: '120px' }} /> | `2` <div style={{ minWidth: '30px' }} /> | Used to apply multilingual strings to all associated products of the current Panel MiniApp in bulk.<br/>* (Provided that the Panel MiniApp has been published and associated with the corresponding product, and the corresponding product has not yet configured multilingual strings, otherwise the product's existing multilingual configuration will be used first) *<div style={{ minWidth: '200px' }} /> | <Image style={{ boxShadow: '0 0 5px rgba(0,0,0,0.3)' }} src='/images/panel/panel-i18n-platform.en-US.png'/><br/><Image style={{ boxShadow: '0 0 5px rgba(0,0,0,0.3)' }} src='/images/panel/panel-i18n-related.en-US.png'/> |
| Product Multilingual Strings <div style={{ minWidth: '120px' }} /> | `1` <div style={{ minWidth: '30px' }} /> | Used to configure multilingual strings only for the current product.<div style={{ minWidth: '200px' }} /> | <Image style={{ boxShadow: '0 0 5px rgba(0,0,0,0.3)' }} src='/images/panel/panel-i18n-product.en-US.png'/> |

**In other words, the priority of product multilingual configuration is the highest, followed by Panel MiniApp multilingual configuration, and finally local multilingual configuration.**

### Q: Why does multilingual upload fail?

A: You can troubleshoot according to the following steps:

1. Check whether the uploaded multilingual file meets the platform's requirements for EXCEL or JSON format and is smaller than 1M.
2. Check whether the uploaded multilingual file content contains scenarios where Chinese is written under English, as shown below:

```javascript
export default {
  en: {
    hello: '你好', // Chinese written under en (English)
  },
  zh: {
    hello: '你好',
  },
};
```

3. Check whether the uploaded multilingual file content has mismatched keys between Chinese and English, as shown below:

```javascript
export default {
  en: {
    hello: 'Hello',
    world: 'World', // "world" configured only under en (English) but not under zh (Chinese)
  },
  zh: {
    hello: '你好',
  },
};
```

4. Check whether the uploaded multilingual file content contains duplicate multilingual keys, as shown below (commonly occurring in EXCEL):

```javascript
export default {
  en: {
    hello: 'Hello',
    world: 'World',
    hello: 'Helloo', // Duplicate key
  },
  zh: {
    hello: '你好',
    world: '世界',
    hello: '你好啊',
  },
};
```
