MaixPy MaixCAM i18n (Internationalization) Multi-Language Implementation

Introduction to i18n (Internationalization)

i18n is an abbreviation for internationalization, which aims to switch languages according to the user's region or preference.

Commonly used languages, such as Chinese and English, have corresponding region codes (LCID). For example, the region code for Chinese is zh, English is en, and Japanese is ja. There are also secondary region codes, like Simplified Chinese corresponding to zh-cn. Generally, implementing zh is sufficient.

For region codes, you can refer to Windows Locale Codes or check Wikipedia.

Using i18n in MaixPy MaixCAM

The general user process is as follows:

  • Initially, users can select the system language in the system settings, with the factory default being en (English).
  • Then, the program can get the current system locale using maix.i18n.get_locale().
  • The program displays the corresponding language strings based on the system locale.

For applications, the tricky part is the third step, which involves looking up the corresponding strings based on the locale settings. Here are two methods to achieve this, depending on your needs:

Using a Dictionary Directly Without Translation Files

If your program only has a few strings, you can manually specify the translation dictionary:

from maix import i18n

trans_dict = {
    "zh": {
        "hello": "你好"
    },
    "en": {
    }
}

trans = i18n.Trans(trans_dict)
tr = trans.tr

trans.set_locale("zh")
print(tr("hello"))
print(tr("my friend"))

Here, trans.set_locale("zh") temporarily sets the language to Chinese. Running this will print 你好 and my friend, since there is no translation for my friend, it returns as is.

Automatically Scanning and Generating a Dictionary, and Loading from Translation Files

This method is more suitable for scenarios with many strings to translate.

In the previous method, we manually specified string translations, which is convenient for simple scenarios. However, if there are too many strings, manually editing the dictionary can easily result in omissions. Therefore, we need the program to automatically find the strings that need translation and generate translation files, which we only need to translate.

In MaixPy, the maix.i18n.Trans class is provided to load translation files in multiple languages. By calling its tr() function and passing in the text to be translated, you can get the translation. For example:

from maix import i18n, err
trans = i18n.Trans()
tr = trans.tr

e = trans.load("locales")
err.check_raise(e, "load translation yamls failed")

print(tr("hello"))

Here, the translation files are loaded from the locales folder in the current directory, and the system prints hello according to the language settings, such as 你好 for Chinese.

Translation Files: Since translation files are used here, how are these files created?
First, we need to know which text needs translation, which are the strings called by the tr function. So we just need to search for all strings that use the tr function in the source code to find all the strings that need translation.
The usage process is as follows:

  • Create a project folder to store the code entry main.py, and open this project folder with MaixVision for easy operation.
  • Write main.py, using the tr function to call the strings that need translation.
  • MaixPy provides a scanning tool. First, make sure maixtool is installed (pip install maixtool -U on the computer terminal to install or upgrade).
  • Then, in the directory, use the computer terminal to execute maixtool i18n -d . r to scan for strings that need translation and generate a locales directory containing translation files for Chinese and English. For more languages, execute maixtool i18n -h for help.
  • The generated files are key-value pairs, for example, in zh.yaml, hello: hello means the Chinese translation of hello is hello. This is incorrect and needs manual translation, changing hello: hello to hello: 你好. Make sure to use a text editor that supports UTF-8 encoding, especially on Windows, avoid changing the file to GBK encoding to prevent errors. You can use MaixVision or VsCode for editing.
  • Then run the project, or package the project into an installation package, remember to include the locales directory.
  • If the source code is updated later, execute the maixtool command again to update the files. It will update the previously translated files. If you are worried about accidental overwriting, you can back up the files first and then delete the backup after confirming everything is correct.

This way, your program will change the language according to the system settings. You can also manually call trans.set_locale("zh") to temporarily switch the language for debugging.

Displaying Translations on the Interface

The previous examples used the print function to display translations. If you want to display them on the interface, you need font support. For English, it is supported by default, but for languages with large font libraries like Chinese, it is not supported by default.
For example:

from maix import i18n, image, display, app, time

trans_dict = {
    "zh": {
        "hello": "你好"
    },
    "en": {
    }
}

trans = i18n.Trans(trans_dict)
tr = trans.tr
trans.set_locale("zh")

disp = display.Display()
img = image.Image(disp.width(), disp.height())

img.draw_string(10, 10, tr("hello"), image.COLOR_WHITE, scale=2)
disp.show(img)

while not app.need_exit():
    time.sleep_ms(100)

Running this will show a bunch of ? because there is no Chinese font library. For the image module, you can load a font library. The system has a built-in Chinese font library, or you can use your own font library:

from maix import i18n, image, display, app, time

trans_dict = {
    "zh": {
        "hello": "你好"
    },
    "en": {
    }
}

trans = i18n.Trans(trans_dict)
tr = trans.tr
trans.set_locale("zh")

disp = display.Display()

image.load_font("sourcehansans", "/maixapp/share/font/SourceHanSansCN-Regular.otf", size = 24)
image.set_default_font("sourcehansans")

img = image.Image(disp.width(), disp.height())
img.draw_string(10, 10, tr("hello"), image.COLOR_WHITE, scale=2)
disp.show(img)

while not app.need_exit():
    time.sleep_ms(100)