Files
crosspoint-reader-mod/docs/i18n.md
Baris Albayrak 4ef433e373 feat: add turkish translation (#1192)
Description
  This Pull Request introduces Turkish language support to CrossPoint
  Reader firmware.


  Key Changes:
- Translation File: Added lib/I18n/translations/turkish.yaml with 315
translated
     string keys, covering all system UI elements.
- I18N Script Update: Modified scripts/gen_i18n.py to include the "TR"
     abbreviation mapping for Turkish.
- System Integration: Regenerated I18N C++ files to include the new
Language::TR
     enum and STRINGS_TR array.
- UI Availability: The language is now selectable in the Settings menu
and
     correctly handles Turkish-specific characters (ç, ğ, ı, ö, ş, ü).
- Documentation: Updated docs/i18n.md to include Turkish in the list of
     supported languages.

  Testing:
   - Verified the build locally with PlatformIO.
- Flashed the firmware to an Xteink X4 device and confirmed the Turkish
UI
     renders correctly.
---

### AI Usage

Did you use AI tools to help write this code?  Yes Gemini

---------

Co-authored-by: Baris Albayrak <baris@Bariss-MacBook-Pro.local>
Co-authored-by: Barış Albayrak <barisa@pop-os.lan>
2026-03-05 18:24:44 -06:00

5.7 KiB

Internationalization (I18N)

This guide explains the multi-language support system in CrossPoint Reader.

Supported Languages

  • English
  • French
  • German
  • Portuguese
  • Spanish
  • Swedish
  • Czech
  • Russian
  • Ukrainian
  • Polish
  • Danish
  • Turkish

For Developers

Translation System Architecture

The I18N system uses per-language YAML files to maintain translations and a Python script to generate C++ code:

lib/I18n/
├── translations/                # One YAML file per language
│   ├── english.yaml
│   ├── spanish.yaml
│   ├── french.yaml
│   └── ...
├── I18n.h
├── I18n.cpp
├── I18nKeys.h                   # Enums (auto-generated)
├── I18nStrings.h                # String array declarations (auto-generated)
└── I18nStrings.cpp              # String array definitions (auto-generated)

scripts/
└── gen_i18n.py                  # Code generator script

Key principle: All translations are managed in the YAML files under lib/I18n/translations/. The Python script generates the necessary C++ code automatically.


YAML File Format

Each language has its own file in lib/I18n/translations/ (e.g. spanish.yaml).

A file looks like this:

_language_name: "Español"
_language_code: "ES"
_order: "1"

STR_CROSSPOINT: "CrossPoint"
STR_BOOTING: "BOOTING"
STR_BROWSE_FILES: "Buscar archivos"

Metadata keys (prefixed with _):

  • _language_name — Native display name shown to the user (e.g. "Français")
  • _language_code — C++ enum name (e.g. "FR"). Please use the ISO Code of the language. Must be a valid C++ identifier.
  • _order — Controls the position in the Language enum (English is always 0)

Rules:

  • Use UTF-8 encoding
  • Every line must follow the format: KEY: "value"
  • Keys must be valid C++ identifiers (uppercase, starts with STR_)
  • Keys must be unique within a file
  • String values must be quoted
  • Use \n for newlines, \\ for literal backslashes, \" for literal quotes inside values

Adding New Strings

To add a new translatable string:

1. Edit the English YAML file

Add the key to lib/I18n/translations/english.yaml:

STR_MY_NEW_STRING: "My New String"

Then add translations in each language file. If a key is missing from a language file, the generator will automatically use the English text as a fallback (and print a warning).

2. Run the generator script

python3 scripts/gen_i18n.py lib/I18n/translations lib/I18n/

This automatically:

  • Fills missing translations from English
  • Updates the StrId enum in I18nKeys.h
  • Regenerates all language arrays in I18nStrings.cpp

3. Use in code

#include <I18n.h>

// Using the tr() macro (recommended)
renderer.drawText(font, x, y, tr(STR_MY_NEW_STRING));

// Using I18N.get() directly
const char* text = I18N.get(StrId::STR_MY_NEW_STRING);

That's it! No manual array synchronization needed.


Adding a New Language

To add support for a new language (e.g., Italian):

1. Create a new YAML file

Create lib/I18n/translations/italian.yaml:

_language_name: "Italiano"
_language_code: "IT"
_order: "7"

STR_CROSSPOINT: "CrossPoint"
STR_BOOTING: "AVVIO"

You only need to include the strings you have translations for. Missing keys will fall back to English automatically.

2. Run the generator

python3 scripts/gen_i18n.py lib/I18n/translations lib/I18n/

This automatically updates all necessary code.


Modifying Existing Translations

Simply edit the relevant YAML file and regenerate:

python3 scripts/gen_i18n.py lib/I18n/translations lib/I18n/

UTF-8 Encoding

The YAML files use UTF-8 encoding. Special characters are automatically converted to C++ UTF-8 hex sequences by the generator.


I18N API Reference

// === Convenience Macros (Recommended) ===

// tr(id) - Get translated string without StrId:: prefix
const char* text = tr(STR_SETTINGS_TITLE);
renderer.drawText(font, x, y, tr(STR_BROWSE_FILES));
Serial.printf("Status: %s\n", tr(STR_CONNECTED));

// I18N - Shorthand for I18n::getInstance()
I18N.setLanguage(Language::ES);
Language lang = I18N.getLanguage();

// === Full API ===

// Get the singleton instance
I18n& instance = I18n::getInstance();

// Get translated string (three equivalent ways)
const char* text = tr(STR_SETTINGS_TITLE);              // Macro (recommended)
const char* text = I18N.get(StrId::STR_SETTINGS_TITLE);   // Direct call
const char* text = I18N[StrId::STR_SETTINGS_TITLE];       // Operator overload

// Set language
I18N.setLanguage(Language::ES);

// Get current language
Language lang = I18N.getLanguage();

// Save language setting to file
I18N.saveSettings();

// Load language setting from file
I18N.loadSettings();

// Get character set for font subsetting (static method)
const char* chars = I18n::getCharacterSet(Language::FR);

File Storage

Language settings are stored in:

/.crosspoint/language.bin

This file contains:

  • Version byte
  • Current language selection (1 byte)

Translation Workflow

For Developers (Adding Features)

  1. Add new strings to lib/I18n/translations/english.yaml
  2. Run python3 scripts/gen_i18n.py lib/I18n/translations lib/I18n/
  3. Use the new StrId in your code
  4. Request translations from translators

For Translators

  1. Open the YAML file for your language in lib/I18n/translations/
  2. Add or update translations using the format STR_KEY: "translated text"
  3. Keep translations concise (E-ink space constraints)
  4. Make sure the file is in UTF-8 encoding
  5. Run python3 scripts/gen_i18n.py lib/I18n/translations lib/I18n/ to verify
  6. Test on device or submit for review