Skip to content

Commit

Permalink
Merge pull request #238 from Schokobecher/i18n
Browse files Browse the repository at this point in the history
German Translation Update / Cross-platform Language File Generation script / Updated Translation Docs
  • Loading branch information
solosky authored Apr 6, 2024
2 parents f4f9468 + e8fc510 commit a5234d4
Show file tree
Hide file tree
Showing 16 changed files with 569 additions and 248 deletions.
96 changes: 81 additions & 15 deletions docs/en/05+5-translation.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,92 @@
# Transalation
# Translation

## How to update exists translation
## Firmware

1. Edit fw/data/i18n.csv with your favorite text editor. For vscode, extension "Edit csv" is recommended.
2. Run `fw/scripts/i18n_gen.py` to generate new language files.
3. Optional: Run `fw/scripts/font_data_gen.sh` to generate new font data if you add new charaters in i18n.csv
4. Run `make full` rebuild firmware
## How to update existing translation

When editing CSV files with VSCode, the extension [Edit CSV](https://marketplace.visualstudio.com/items?itemName=janisdd.vscode-edit-csv) is recommended.

**Windows** requires you to have [Python](https://www.python.org/downloads/) and [Git](https://git-scm.com/download/windows) installed and within your `$PATH`
For **Linux**, most distributions come with `python` and `git` by default and **macOS** comes bundled with `python`, but to use `git` you either need to install the Command Line tools via `xcode-select –-install`, or download [Git](https://git-scm.com/download/mac) separately.

### Windows

note: <br />
The script `font_data_gen.sh` only can be run in Git Bash windows in Windows.
1. Clone this repository
`git clone https://github.com/solosky/pixl.js.git; cd pixl.js`
2. Edit `fw/data/i18n.csv`
3. Run `py.exe fw/scripts/i18n_gen.py` to generate new language files.
4. _Optional:_ Run `py.exe fw/scripts/font_data_gen.py` to generate new font data if you add new characters in `i18n.csv`
5. [Build the Firmware](03-Build-Firmware.md)

### Linux and macOS

1. Clone this repository
`git clone https://github.com/solosky/pixl.js.git; cd pixl.js`
2. Edit `fw/data/i18n.csv`
3. Run `python3 fw/scripts/i18n_gen.py` to generate new language files.
4. Optional: Run `python fw/scripts/font_data_gen.py` to generate new font data if you add new characters in `i18n.csv`
5. [Build the Firmware](03-Build-Firmware.md)

## How to add new language translation

1. Add new column in fw/data/i18n.csv, for example "ja_JP"
The process is similar to updating an existing translation, and has the same requirements depending on your Operating System.

1. Add new column in `fw/data/i18n.csv`, for example "ja_JP"
2. Run `fw/scripts/i18n_gen.py` to generate new language files.
3. Optional: Run `fw/scripts/font_data_gen.sh` to generate new font data if you add new charaters in i18n.csv
3. Optional: Run `fw/scripts/font_data_gen.py` to generate new font data if you add new characters in `i18n.csv`
4. Edit `fw/application/src/i18n/language.h` and `fw/application/src/i18n/language.c` to adopt new language
5. Edit Makefile to include `$(PROJ_DIR)/i18n/ja_JP.c` as C source files
6. Run `make full` rebuild firmware
6. [Build the Firmware](03-Build-Firmware.md)

## Font notes

For release builds (RELEASE=1), the firmware uses wenquanyi_9pt_u8g2.bdf to display unicode characters.
Please check if the new language character codepoint is included in wenquanyi_9pt_u8g2.bdf or not.
If not, it's not recommended supporting the new language due to the MCU internal flash restrictions.

## Web App

### How to update existing translation

The language file can be found under `web/src/i18n'

## How to add new language translation

In this example, we will add a Japanese (ja_JP) translation:

1. Copy the `en_US.js` file and name it `ja_JP.js`
2. Translate the string within `ja_JP.js` including the `changeok` message.

Don't translate the other language names.

Add your language at the bottom of the `lang {` section:

`ja: '日本語',`

3. Edit `index.js` while keeping its current structure, adding:

```js
import elementJaLocale from 'element-ui/lib/locale/lang/ja' // element-ui
lang import jaLocale from './ja_JP' elementJpLocale
```

And extending `messages`:

```js
ja_JP: {
...jaLocale,
...elementJaLocale,
},
```

4. Add your language to the other `.js` files (within the `lang: {` section):

`vueja: '日本語',`

## Font notes
5. Add your language to the `web/src/App.vue` file:

For release build (RELEASE=1), the firmware use wenquanyi_9pt_u8g2.bdf to display unicode characters. <br />
Please check new language charater codepoint is included in wenquanyi_9pt_u8g2.bdf or not.<br />
If not, I am not recommended to support the new language due to the MCU internal flash restrction.
```js
<el-dropdown-item Enabled="language==='ja'" command="ja" divided>
{{ $t('lang.ja') }}
</el-dropdown-item>
```
128 changes: 64 additions & 64 deletions fw/application/src/i18n/de_DE.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,30 @@ const char * const lang_de_DE[_L_COUNT] = {
[_L_OFF] = "AUS",
[_L_ON_F] = "[AN]",
[_L_OFF_F] = "[AUS]",
[_L_BACK] = "[Zurück]",
[_L_BACK] = "Zurück",
[_L_ERR] = "Fehler",
[_L_ERR_CODE] = "Fehlercode",
[_L_APP_AMIIBO] = "Amiibo-Emulator",
[_L_APP_AMIIBO] = "Amiibo Emulator",
[_L_APP_AMIIBOLINK] = "AmiiboLink",
[_L_APP_BLE] = "BLE-Dateitransfer",
[_L_APP_BLE_TITLE] = "BLE-Dateitransfer",
[_L_APP_PLAYER] = "Videospieler",
[_L_APP_BLE] = "BLE Dateitransfer",
[_L_APP_BLE_TITLE] = "BLE Dateitransfer",
[_L_APP_PLAYER] = "Videoplayer",
[_L_APP_SET] = "Einstellungen",
[_L_APP_SET_VERSION] = "Version",
[_L_APP_SET_STORAGE_USED] = "Belegt",
[_L_APP_SET_STORAGE] = "Speicher",
[_L_APP_SET_OLED_CONTRAST] = "OLED-Kontrast",
[_L_APP_SET_OLED_CONTRAST_TITLE] = "OLED-Kontrast",
[_L_APP_SET_STORAGE] = "Externer Speicher",
[_L_APP_SET_OLED_CONTRAST] = "OLED Kontrast",
[_L_APP_SET_OLED_CONTRAST_TITLE] = "OLED Kontrast",
[_L_APP_SET_LCD_BACKLIGHT] = "Beleuchtung",
[_L_APP_SET_LCD_BACKLIGHT_TITLE] = "Helligkeit",
[_L_APP_SET_ANIM] = "Menü-Animation",
[_L_APP_SET_LIPO_BAT] = "LiPO-Batterie",
[_L_APP_SET_ANIM] = "Menü Animation",
[_L_APP_SET_LIPO_BAT] = "LiPO Batterie",
[_L_APP_SET_SHOW_MEM_USAGE] = "Speicheranzeige",
[_L_APP_SET_HIBERNATE] = "Schnell-Wecken",
[_L_APP_SET_SLEEP_TIMEOUT] = "Schlaf-Timeout",
[_L_APP_SET_HIBERNATE] = "Schnelles Aufwachen",
[_L_APP_SET_SLEEP_TIMEOUT] = "Standby nach",
[_L_APP_SET_LANGUAGE] = "Sprache",
[_L_APP_SET_DFU] = "Firmw.-Aktualisierung",
[_L_APP_SET_REBOOT] = "System-Neustart",
[_L_APP_SET_DFU] = "Firmw. Aktualisierung",
[_L_APP_SET_REBOOT] = "System Neustart",
[_L_APP_SET_RESET_DEFAULT] = "Standardeinstellungen",
[_L_APP_SET_RESET_DEFAULT_SUCCESS] = "Einstellungen zurückgesetzt!",
[_L_APP_SET_RESET_DEFAULT_CONFIRM] = "Auf Standardeinstellungen zurücksetzen?",
Expand All @@ -36,68 +36,68 @@ const char * const lang_de_DE[_L_COUNT] = {
[_L_45S] = "45 Sekunden",
[_L_1MIN] = "1 Minute",
[_L_2MIN] = "2 Minuten",
[_L_3MIN] = "3 Min",
[_L_AMIIBO_KEY_UNLOADED] = "Schlüssel nicht gefunden",
[_L_UPLOAD_KEY_RETAIL_BIN] = "Laden Sie die Datei key_retail.bin in das Stammverzeichnis des Speichers.",
[_L_3MIN] = "3 Minuten",
[_L_AMIIBO_KEY_UNLOADED] = "Amiibo Schlüssel fehlt",
[_L_UPLOAD_KEY_RETAIL_BIN] = "Platzieren Sie die Datei key_retail.bin im Hauptverzeichnis des Speichers.",
[_L_KNOW] = "Verstanden",
[_L_RANDOM_GENERATION] = "Zufällige Tag-Nummer",
[_L_AUTO_RANDOM_GENERATION] = "Autom. random.",
[_L_SHOW_QRCODE] = "QR-Code",
[_L_RANDOM_GENERATION] = "Zufällige UUID",
[_L_AUTO_RANDOM_GENERATION] = "Zufällige UUID (Automatisch)",
[_L_SHOW_QRCODE] = "QR Code",
[_L_DELETE_TAG] = "Tag löschen",
[_L_DELETE_TAG_CONFIRM] = "Bestätigen Sie das\nLöschen %s?",
[_L_BACK_TO_DETAILS] = "Zurück zu Tag-Details",
[_L_BACK_TO_FILE_LIST] = "[Zurück zur Liste]",
[_L_BACK_TO_MAIN_MENU] = "[Hauptmenü]",
[_L_DELETE_TAG_CONFIRM] = "Löschen von %s bestätigen?",
[_L_BACK_TO_DETAILS] = "Zurück zu Tag Details",
[_L_BACK_TO_FILE_LIST] = "Zurück zur Liste",
[_L_BACK_TO_MAIN_MENU] = "Hauptmenü",
[_L_FORMAT] = "Formatieren",
[_L_FORMAT_STORAGE] = "Speicher formatieren",
[_L_DELETE_ALL_DATA] = "Alle Daten löschen?",
[_L_DELETING_MESSAGE] = "Formatierung..",
[_L_MESSAGE] = "Nachricht",
[_L_DELETING_MESSAGE] = "Formatiere..",
[_L_MESSAGE] = "Meldung",
[_L_CONFIRM] = "Bestätigen",
[_L_CANCEL] = "Abbrechen",
[_L_BACK_TO_LIST] = "[Zurück zur Liste]",
[_L_NOT_MOUNTED] = "Speicher nicht ausgerüstet",
[_L_BACK_TO_LIST] = "Zurück zur Liste",
[_L_NOT_MOUNTED] = "Speicher nicht eingebunden",
[_L_MOUNTED_LFS] = "===Speicher [LFS]===",
[_L_MOUNTED_FFS] = "===Speicher [FFS]===",
[_L_TOTAL_SPACE] = "Gesamt",
[_L_AVAILABLE_SPACE] = "Frei",
[_L_NOT_AMIIBO_FILE] = "Dies ist keine Amiibo-Datei",
[_L_NOT_AMIIBO_FILE] = "Keine Amiibo Datei",
[_L_READ_FILE_FAILED] = "Lesen fehlgeschlagen",
[_L_INPUT_FOLDER_NAME] = "Ordnername eingeben:",
[_L_INPUT_AMIIBO_NAME] = "Amiibo-Name eingeben:",
[_L_INPUT_AMIIBO_NAME] = "Amiibo Namen eingeben:",
[_L_DELETE] = "Löschen",
[_L_INPUT_NEW_NAME] = "Neuen Namen eingeben:",
[_L_INVALID_INPUT] = "Ungültige Eingabe",
[_L_CREATE_NEW_FOLDER] = "Neuer Ordner..",
[_L_CREATE_NEW_TAG] = "Neuer Tag..",
[_L_CREATE_NEW_TAG_BATCH] = "Mehrere Tags..",
[_L_INPUT_TAG_NUM] = "Tag-Anzahl eingeben:",
[_L_CREATE_TOO_MANY_NUM] = "Nur maximal %d Tags in einem Stapel erstellt.",
[_L_CREATE_NEW_TAG_BATCH] = "Mehrere Tags erstellen..",
[_L_INPUT_TAG_NUM] = "Tag Anzahl eingeben:",
[_L_CREATE_TOO_MANY_NUM] = "Sie können nur maximal %d Tags auf einmal erstellen.",
[_L_CREATING_TAG_BATCH] = "Tag erstellen",
[_L_CREATING_TAG_FAILED] = "Erstellen von Tag %s fehlgeschlagen!",
[_L_RENAME] = "Umbenennen",
[_L_OPEN_FOLDER_FAILED] = "Ordner konnte nicht geöffnet werden",
[_L_RENAME_FAILED] = "Umbenennen fehlgeschlagen\nFehlercode",
[_L_MAIN_RETURN] = "[Zurück]",
[_L_RANDOM_MODE_MANUAL] = "Zufällig (Manuell)",
[_L_RANDOM_MODE_AUTO] = "Zufällig (Automatisch)",
[_L_RANDOM_MODE_MANUAL] = "Zufällige UUID (Manuell)",
[_L_RANDOM_MODE_AUTO] = "Zufällige UUID (Automatisch)",
[_L_SEQUENCE_MODE] = "Sequentieller Modus",
[_L_READ_WRITE_MODE] = "Lese-Schreib-Modus",
[_L_READ_WRITE_MODE] = "Lese-Schreibmodus",
[_L_AMIIBOLINK_V1] = "V1",
[_L_AMIIBOLINK_V2] = "V2",
[_L_AMILOOP] = "AmiLoop",
[_L_MODE] = "Modus",
[_L_AUTO_RANDOM] = "Autom. randomisieren",
[_L_COMPATIBLE_MODE] = "Kompat. Modus",
[_L_AUTO_RANDOM] = "Zufällige UUID (Automatisch)",
[_L_COMPATIBLE_MODE] = "Kompabilitäts Modus",
[_L_TAG_DETAILS] = "[Zurück zu Details]",
[_L_MAIN_MENU] = "[Hauptmenü]",
[_L_MODE_RANDOM] = "Manuell",
[_L_MODE_RANDOM] = "Zufällige UUID (Manuell)",
[_L_MODE_CYCLE] = "Sequentiell",
[_L_MODE_NTAG] = "Lese/Schreib",
[_L_MODE_RANDOM_AUTO_GEN] = "Automatisch",
[_L_BLANK_TAG] = "Leerer NFC-Tag",
[_L_APP_AMIIDB] = "Amiibo-Datenbank",
[_L_APP_AMMIDB_BROWSER] = "Browser..",
[_L_MODE_NTAG] = "Lesen/Schreiben",
[_L_MODE_RANDOM_AUTO_GEN] = "Zufällig (Auto.)",
[_L_BLANK_TAG] = "Leerer NFC Tag",
[_L_APP_AMIIDB] = "Amiibo Datenbank",
[_L_APP_AMMIDB_BROWSER] = "Navigieren..",
[_L_APP_AMIIDB_SEARCH] = "Suche..",
[_L_APP_AMIIDB_MY_FAVORITES] = "Meine Favoriten..",
[_L_APP_AMIIDB_MY_TAGS] = "Meine Amiibo..",
Expand All @@ -106,8 +106,8 @@ const char * const lang_de_DE[_L_COUNT] = {
[_L_APP_AMIIDB_BACK] = "[Zurück]",
[_L_APP_AMIIDB_SETTINGS_AMIIBO_KEY] = "Schlüssel",
[_L_APP_AMIIDB_SETTINGS_AMIIBO_KEY_LOADED] = "geladen",
[_L_APP_AMIIDB_SETTINGS_AMIIBO_KEY_NOT_LOADED] = "fehlend",
[_L_APP_AMIIDB_SETTINGS_SLOT_NUM] = "Steckplatznummer",
[_L_APP_AMIIDB_SETTINGS_AMIIBO_KEY_NOT_LOADED] = "NICHT geladen",
[_L_APP_AMIIDB_SETTINGS_SLOT_NUM] = "Steckplatzanzahl",
[_L_APP_AMIIDB_DETAIL_FAVORITE] = "Favorit..",
[_L_APP_AMIIDB_DETAIL_SAVE_AS] = "Speichern unter..",
[_L_APP_AMIIDB_DETAIL_BACK_DETAIL] = "[Zurück zu Details]",
Expand All @@ -122,15 +122,15 @@ const char * const lang_de_DE[_L_COUNT] = {
[_L_APP_AMIIDB_NEW] = "Neu..",
[_L_APP_AMIIDB_EMPTY] = "Leeren..",
[_L_APP_AMIIDB_DELETE] = "Löschen..",
[_L_APP_AMIIDB_FAV_NEW_HEAD] = "Neuer Favoriten-Ordner:",
[_L_APP_AMIIDB_FAV_EMPTY_MSG] = "Favoritenordner leeren?",
[_L_APP_AMIIDB_FAV_DELETE_MSG] = "Favoritenordner löschen?",
[_L_APP_AMIIDB_FAV_NEW_HEAD] = "Neuer Fav.-Ordner:",
[_L_APP_AMIIDB_FAV_EMPTY_MSG] = "Fav.-Ordner leeren?",
[_L_APP_AMIIDB_FAV_DELETE_MSG] = "Löschen Bestätigen?",
[_L_APP_AMIIDB_FAV_SELECT_FOLDER] = "Fav.-Ordner auswählen..",
[_L_APP_AMIIDB_FAV_SUCCESS] = "Favorit erstellt ",
[_L_APP_AMIIDB_FAV_FAILED] = "Favorit fehlgeschlagen!",
[_L_APP_AMIIDB_FAV_FAILED] = "Favorisieren fehlgeschlagen!",
[_L_APP_AMIIDB_SLOT_SAVE_SUCCESS] = "Speichern erfolgreich",
[_L_APP_AMIIDB_SLOT_SAVE_FAILED] = "Speichern fehlgeschlagen!",
[_L_APP_CHAMELEON] = "Karten-Emulator",
[_L_APP_CHAMELEON] = "Karten Emulator",
[_L_APP_CHAMELEON_TAG_MF1_WRITE_NORMAL] = "Normal",
[_L_APP_CHAMELEON_TAG_MF1_WRITE_DENIED] = "Verweigern",
[_L_APP_CHAMELEON_TAG_MF1_WRITE_DECEIVE] = "Ignorieren",
Expand All @@ -142,25 +142,25 @@ const char * const lang_de_DE[_L_COUNT] = {
[_L_APP_CHAMELEON_CARD_TYPE] = "Typ",
[_L_APP_CHAMELEON_CARD_DATA] = "Daten..",
[_L_APP_CHAMELEON_CARD_ADVANCED] = "Erweitert..",
[_L_APP_CHAMELEON_CARD_SLOT_SETTINGS] = "Steckplätze..",
[_L_APP_CHAMELEON_CARD_SLOT_NUM] = "Steckplätze",
[_L_APP_CHAMELEON_CARD_SET_NICK_SUCCESS] = "Spitzname erfolgreich",
[_L_APP_CHAMELEON_CARD_SET_NICK_FAILED] = "Spitzname fehlgeschlagen!",
[_L_APP_CHAMELEON_CARD_INPUT_NICK] = "Spitzname eingeben:",
[_L_APP_CHAMELEON_CARD_SLOT_SETTINGS] = "Steckplatz Einstellungen..",
[_L_APP_CHAMELEON_CARD_SLOT_NUM] = "Steckplatz Nummer",
[_L_APP_CHAMELEON_CARD_SET_NICK_SUCCESS] = "Spitzname erfolgreich gesetzt",
[_L_APP_CHAMELEON_CARD_SET_NICK_FAILED] = "Spitzname setzen fehlgeschlagen!",
[_L_APP_CHAMELEON_CARD_INPUT_NICK] = "Spitznamen eingeben:",
[_L_APP_CHAMELEON_CARD_DATA_LOAD] = "Laden..",
[_L_APP_CHAMELEON_CARD_DATA_SAVE] = "Speichern..",
[_L_APP_CHAMELEON_CARD_DATA_FACTORY] = "Zurücksetzen..",
[_L_APP_CHAMELEON_CARD_DATA_FACTORY_SUCCESS] = "Daten zurückgesetzt",
[_L_APP_CHAMELEON_CARD_DATA_LOAD_NOT_FOUND] = "Datei nicht gefunden",
[_L_APP_CHAMELEON_CARD_DATA_LOAD_SIZE_NOT_MATCH] = "Dateigröße inkorrekt",
[_L_APP_CHAMELEON_CARD_DATA_LOAD_FAILED] = "Laden fehlgeschlagen",
[_L_APP_CHAMELEON_CARD_DATA_LOAD_SUCCESS] = "Laden erfolgreich",
[_L_APP_CHAMELEON_CARD_DATA_SAVE_INPUT_FILE_NAME] = "Dateinamen eingeben:",
[_L_APP_CHAMELEON_CARD_DATA_SAVE_FAILED] = "Speichern fehlgeschlagen!",
[_L_APP_CHAMELEON_CARD_DATA_SAVE_SUCCESS] = "Speichern erfolgreich",
[_L_APP_CHAMELEON_CARD_ADV_CUSTOM_MODE] = "Benutzermodus",
[_L_APP_CHAMELEON_CARD_DATA_LOAD_SIZE_NOT_MATCH] = "Dateigröße stimmt nicht überein",
[_L_APP_CHAMELEON_CARD_DATA_LOAD_FAILED] = "Laden der Datei fehlgeschlagen",
[_L_APP_CHAMELEON_CARD_DATA_LOAD_SUCCESS] = "Datei erfolgreich geladen",
[_L_APP_CHAMELEON_CARD_DATA_SAVE_INPUT_FILE_NAME] = "Datei Namen eingeben:",
[_L_APP_CHAMELEON_CARD_DATA_SAVE_FAILED] = "Datei speichern fehlgeschlagen!",
[_L_APP_CHAMELEON_CARD_DATA_SAVE_SUCCESS] = "Datei erfolgreich gespeichert",
[_L_APP_CHAMELEON_CARD_ADV_CUSTOM_MODE] = "Benutzerdefinierter Modus",
[_L_APP_CHAMELEON_CARD_GEN1A_MODE] = "Gen1A aktiv",
[_L_APP_CHAMELEON_CARD_GENERATE_UID] = "Randomisierte UID",
[_L_APP_CHAMELEON_CARD_GENERATE_UID] = "Zufällige UID",
[_L_APP_CHAMELEON_CARD_GENERATE_UID_SUCCESS] = "UID generiert",
[_L_APP_CHAMELEON_CARD_GEN2_MODE] = "Gen2 aktiv",
[_L_APP_CHAMELEON_CARD_WRITE_MODE] = "Schreibmodus",
Expand Down
2 changes: 1 addition & 1 deletion fw/application/src/i18n/fr_FR.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ const char * const lang_fr_FR[_L_COUNT] = {
[_L_APP_CHAMELEON_TAG_MF1_WRITE_NORMAL] = "Normal",
[_L_APP_CHAMELEON_TAG_MF1_WRITE_DENIED] = "Refuser",
[_L_APP_CHAMELEON_TAG_MF1_WRITE_DECEIVE] = "Ignorer",
[_L_APP_CHAMELEON_TAG_MF1_WRITE_SHADOW] = "Zwischenspeicher",
[_L_APP_CHAMELEON_TAG_MF1_WRITE_SHADOW] = "Cache",
[_L_APP_CHAMELEON_INITIALIZING] = "Initialisation des données ..",
[_L_APP_CHAMELEON_CARD_SLOT] = "Fente",
[_L_APP_CHAMELEON_CARD_NICK] = "Pseudo",
Expand Down
2 changes: 1 addition & 1 deletion fw/application/src/mui/u8g2_font_wqy12_t_gb2312a.c
Original file line number Diff line number Diff line change
Expand Up @@ -1250,4 +1250,4 @@ const uint8_t u8g2_font_wqy12_t_gb2312a[39601] U8G2_FONT_SECTION("u8g2_font_wqy1
"<\311\360\22U\243\4\377\10\15\303\177\134I\224D\275EY\0\377\11\15\303{\34Y\224E\275DI"
"\4\377\21\12\244{\134Y\262\365i\377\32\11r\236\34C<\4\377\37\20\266|<C\42\15\221\250\31"
"\355\230(\1\377=\13\304z\34C\326\277\15\2\0";
#endif /* U8G2_USE_LARGE_GB2312_FONT */
#endif /* U8G2_USE_LARGE_GB2312_FONT */
Loading

0 comments on commit a5234d4

Please sign in to comment.