Skip to content

Commit

Permalink
add i18n doc
Browse files Browse the repository at this point in the history
  • Loading branch information
Neutree committed Jul 15, 2024
1 parent af86f6a commit 04ecf0d
Show file tree
Hide file tree
Showing 6 changed files with 338 additions and 0 deletions.
139 changes: 139 additions & 0 deletions docs/doc/en/gui/i18n.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
---
title: Title: 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](https://www.science.co.il/language/Locale-codes.php) or check [Wikipedia](https://en.wikipedia.org/wiki/Language_localisation).

## 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:

```python
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:

```python
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:

```python
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:

```python
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)
```
2 changes: 2 additions & 0 deletions docs/doc/en/sidebar.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ items:
label: AprilTag identity
- file: vision/opencv.md
label: Use OpenCV
- file: gui/i18n.md
label: I18N (Multi language)

- label: AI Vision
items:
Expand Down
151 changes: 151 additions & 0 deletions docs/doc/zh/gui/i18n.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
---
title: MaixPy MaixCAM i18n(国际化) 多语言实现
---



## i18n (国际化)简介

i18n 是国际化单词(internationalization)的简称,目的在与根据用户的地域或者喜好切换语言。

我们常用的 中文 和 英文 这个就是语言,语言有对应的地域编码( LCID),比如中文的地域编码为`zh`,英文为`en`,日文为`ja`,另外还有二级地域编码,比如简体中文对应`zh-cn`,一般我们实现`zh`即可。

地域编号可以参考[Windows的地域编码表](https://www.science.co.il/language/Locale-codes.php) 或者看 [wikipedia](https://en.wikipedia.org/wiki/Language_localisation)


## MaixPy MaixCAM 中使用 i18n

用户使用大致流程如下:
* 首先用户使用时,在系统设置中可以选择系统语言,比如出厂默认是`en`即英文。
* 然后程序通过`maix.i18n.get_locale()`可以获得当前系统设置的地域。
* 程序根据系统设置的地域显示对应语言的字符串。

对于应用程序来说,比较麻烦的地方就在这里的第三步,即根据地域设置查表获取对应的字符串,下面提供两种方法,根据自己的需求选择:

### 不使用翻译文件,直接使用字典

如果你的程序只有几个字符串,可以直接手动指定翻译字典:

```python
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"))
```

这里用`trans.set_locale("zh")`临时设置语言为中文了, 运行就会打印`你好``my friend` 了, 因为没给`my friend`填加翻译,所以原封不动地返回了。


### 自动扫描生成字典,并且从翻译文件加载

这种方法比较适合有大量需要翻译的字符串的场景。

前面的方法我们手动指定了字符串翻译,在简单场景很方便,但是如果字符串太多了,手动改字典很容易漏掉,所以我们需要程序自动帮我们找到需要翻译的字符串并生成翻译文件,我们只需要翻译一下文件就好了。


在 MaixPy 中,提供了`maix.i18n.Trans` 这个类,可以用来加载多种语言的翻译文件,调用其成员函数`tr()`,传入想要翻译的文字即可获得翻译,举例:
```python
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"))
```

这里从当前目录下的`locales`文件夹加载了翻译文件,然后根据系统的语言设置打印`hello`,比如中文就会打印`你好`

**翻译文件**: 既然这里加载用到了翻译文件,这些翻译文件怎么制作呢?
首先我们需要知道我们需要翻译那些文字,显而易见,就是上面我们用函数`tr`调用的字符串,所以我们只需要搜索源码中所有用到了`tr`函数的字符串即可认为是我们需要翻译的所有字符串了。
所以使用流程如下:
* 建立一个项目文件夹,里面存放代码入口`main.py`,可以使用 `MaixVision`` 打开这个项目文件夹方便运行。
* 编写`main.py`,让需要翻译的字符串都用上述的`tr`函数调用。
* MaixPy 提供了一个扫描工具,首先确保安装了`maixtool`(电脑通过系统终端 `pip install maixtool -U` 命令来安装升级)。
* 然后在目录下仍然使用电脑终端执行`maixtool i18n -d . r`来扫描需要翻译的字符串,并且生成一个`locales`目录,里面包含了中英文两种语言的翻译文件,如果要更多语言,执行`maixtool i18n -h`查看帮助。
* 生成的文件是键值对组成的,比如`zh.yaml`中的`hello: hello` 的意思就是字符串`hello`中文翻译是`hello`,这显然不对,需要我们手动翻译一下,改成`hello: 你好`即可。注意编辑文件一定要用支持 `UTF-8` 编码的编辑器,特别是在`Windows`下不要将文件改为`GBK`编码了,不然会出错,可以用 MaixVision 或者 VsCode 编辑。
* 然后运行项目,或者打包项目为安装包都可以,记得把 `locales` 目录也一起打包进去。
* 如果后面又更新了源码,需要再次执行`maixtool`命令更新文件,更新会对之前已经翻译了的文件更新,如果你担心程序不小心将之前的错误覆盖,可以先自行备份一份,确认无误后再删除备份。

这样你的程序就会根据系统语言设置更改语言了,如果你调试程序也可以手动调用`trans.set_locale("zh")`来手动临时切换语言。



## 显示翻译到界面

前面的例子都是在调用`print`函数打印,如果想显示到界面上,还有一步要做,就是需要字库支持,对于英文来说默认都支持了,可是对于中文这种字库庞大的语言,默认是不支持的。
比如:
```python
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)
```

运行会发现显示了一堆`?`,因为没有中文字库,对于`image`模块,可以加载字库,系统内置了一个中文字库,你也可以用你自己的字库:

```python
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)
```






2 changes: 2 additions & 0 deletions docs/doc/zh/sidebar.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ items:
label: AprilTag 识别
- file: vision/opencv.md
label: 使用 OpenCV
- file: gui/i18n.md
label: I18N 国际化(多语言)

- label: AI 视觉
items:
Expand Down
27 changes: 27 additions & 0 deletions examples/gui/i18n_display.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
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)

17 changes: 17 additions & 0 deletions examples/gui/i18n_simple.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
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"))

0 comments on commit 04ecf0d

Please sign in to comment.