## Major Features ### 1. CJK UI Font System - Implemented external font loading system for CJK characters - Added Source Han Sans (思源黑体) as base font for UI rendering - Support for multiple font sizes (20pt, 22pt, 24pt) - Font selection UI for both reader and UI fonts - Automatic fallback to built-in fonts when external fonts unavailable - External UI font now renders ALL characters (including ASCII) for consistent style - Proportional spacing for external fonts (variable width per character) ### 2. Complete I18N Implementation - Added comprehensive internationalization system - Support for English, Chinese Simplified, and Japanese - Translated all UI strings across the entire application - Language selection UI in settings with native language names - English displayed as "English" - Chinese displayed as "简体中文" - Japanese displayed as "日本語" - Dynamic language switching without restart ### 3. Bug Fixes #### Rendering Race Conditions - Fixed race condition where parent and child Activity rendering tasks run simultaneously - Added 500ms delay in child Activity displayTaskLoop() to wait for parent rendering completion - Unified displayTaskLoop() logic: `if (updateRequired && !subActivity)` - Prevents duplicate RED RAM writes and incomplete screen refreshes **Affected Activities:** - CategorySettingsActivity: Unified displayTaskLoop check logic - KOReaderSettingsActivity: Added 500ms delay before first render - CalibreSettingsActivity: Added 500ms delay before first render - FontSelectActivity: Added 500ms delay before first render - ClearCacheActivity: Added 500ms delay and subActivity check - LanguageSelectActivity: Added 500ms delay in displayTaskLoop (not onEnter) #### Button Response Issues - Fixed CrossPointWebServer exit button requiring long press - Added MappedInputManager::update() method - Call update() before wasPressed() in tight HTTP processing loop - Button presses during loop are now properly detected #### ClearCache Crash - Fixed FreeRTOS mutex deadlock when exiting ClearCache activity - Added isExiting flag to prevent operations during exit - Added clearCacheTaskHandle tracking - Wait for clearCache task completion before deleting mutex #### External UI Font Rendering - Fixed ASCII characters not using external UI font (was using built-in EPD font) - Fixed character spacing too wide (now uses proportional spacing via getGlyphMetrics) ## Technical Details **Files Added:** - lib/ExternalFont/: External font loading system - lib/I18n/: Internationalization system - lib/GfxRenderer/cjk_ui_font*.h: Pre-rendered CJK font data - scripts/generate_cjk_ui_font.py: Font generation script - src/activities/settings/FontSelectActivity.*: Font selection UI - src/activities/settings/LanguageSelectActivity.*: Language selection UI - docs/cjk-fonts.md: CJK font documentation - docs/i18n.md: I18N documentation **Files Modified:** - lib/GfxRenderer/: Added CJK font rendering support with proportional spacing - src/activities/: I18N integration across all activities - src/MappedInputManager.*: Added update() method - src/CrossPointSettings.cpp: Added language and font settings **Memory Usage:** - Flash: 94.7% (6204434 bytes / 6553600 bytes) - RAM: 66.4% (217556 bytes / 327680 bytes) ## Testing Notes All rendering race conditions and button response issues have been fixed and tested. ClearCache no longer crashes when exiting. File transfer page now responds to short press on exit button. External UI font now renders all characters with proper proportional spacing. Language selection page displays language names in their native scripts. Co-authored-by: Claude (Anthropic AI Assistant)
6.9 KiB
Internationalization (I18N)
This guide explains the multi-language support system in CrossPoint Reader.
Overview
CrossPoint Reader supports multiple languages for the user interface:
- English (Default)
- Chinese Simplified (简体中文)
- Japanese (日本語)
All UI text, menus, settings, and system messages are translated.
Changing Language
- Go to Settings → System
- Select Language
- Choose your preferred language from the list:
- English - Displayed as "English"
- 简体中文 - Displayed as "简体中文" (Chinese Simplified)
- 日本語 - Displayed as "日本語" (Japanese)
- The interface will update immediately
Note: Language changes take effect immediately without requiring a restart.
Supported Languages
English (Default)
The default language. All text is displayed in English.
Chinese Simplified (简体中文)
Full Chinese translation including:
- All menu items and settings
- System messages and prompts
- Button labels and hints
- Error messages
Requirements: CJK UI font must be enabled for proper character display.
Japanese (日本語)
Full Japanese translation including:
- All menu items and settings
- System messages and prompts
- Button labels and hints
- Error messages
Requirements: CJK UI font must be enabled for proper character display.
Language and Font Relationship
When using Chinese or Japanese:
- Enable CJK UI Font - Go to Settings → Display → UI Font
- Select a font that supports your language's characters
- Change language - The UI will now display correctly
If CJK font is not enabled, Chinese/Japanese characters may display as boxes or question marks.
For Developers
Adding New Translations
1. Add String ID
In lib/I18n/I18n.h, add a new entry to the StrId enum:
enum class StrId : uint16_t {
// ... existing entries ...
MY_NEW_STRING,
// ... more entries ...
_COUNT // Must be last
};
2. Add Translations
In lib/I18n/I18n.cpp, add translations to each language array:
// English
static const char* const STRINGS_EN[] = {
// ... existing strings ...
"My New String",
// ... more strings ...
};
// Chinese Simplified
static const char* const STRINGS_ZH[] = {
// ... existing strings ...
"\xE6\x88\x91\xE7\x9A\x84\xE6\x96\xB0\xE5\xAD\x97\xE7\xAC\xA6\xE4\xB8\xB2", // 我的新字符串
// ... more strings ...
};
// Japanese
static const char* const STRINGS_JA[] = {
// ... existing strings ...
"\xE6\x96\xB0\xE3\x81\x97\xE3\x81\x84\xE6\x96\x87\xE5\xAD\x97\xE5\x88\x97", // 新しい文字列
// ... more strings ...
};
Important:
- Arrays must have the same number of entries
- Use UTF-8 hex encoding for non-ASCII characters
- Keep entries in the same order as the enum
3. Use in Code
#include <I18n.h>
// Using the TR() macro (recommended)
renderer.drawText(font, x, y, TR(MY_NEW_STRING));
// Using I18N.get() directly
const char* text = I18N.get(StrId::MY_NEW_STRING);
UTF-8 Hex Encoding
For non-ASCII characters, use UTF-8 hex encoding:
| Character | UTF-8 Hex |
|---|---|
| 中 | \xE4\xB8\xAD |
| 文 | \xE6\x96\x87 |
| 日 | \xE6\x97\xA5 |
| 本 | \xE6\x9C\xAC |
Python helper:
def to_utf8_hex(text):
return ''.join(f'\\x{b:02X}' for b in text.encode('utf-8'))
print(to_utf8_hex("设置")) # \xE8\xAE\xBE\xE7\xBD\xAE
I18N API Reference
// Get the singleton instance
I18n& i18n = I18n::getInstance();
// Or use the global macro
I18N.get(StrId::SETTINGS);
// Get translated string
const char* text = I18N.get(StrId::SETTINGS);
// Set language
I18N.setLanguage(Language::ZH);
// Get current language
Language lang = I18N.getLanguage();
// Save language setting to file
I18N.saveSettings();
// Load language setting from file
I18N.loadSettings();
Language Enum
enum class Language : uint8_t {
EN = 0, // English
ZH = 1, // Chinese Simplified
JA = 2, // Japanese
_COUNT // Number of languages
};
String Categories
The I18N system organizes strings into categories:
Navigation & Actions
BACK,CONFIRM,CANCEL,SELECT,EXIT,DONE
Settings Categories
CAT_DISPLAY,CAT_READER,CAT_CONTROLS,CAT_SYSTEM
Display Settings
SLEEP_SCREEN,STATUS_BAR,REFRESH_FREQ, etc.
Reader Settings
FONT_SIZE,LINE_SPACING,ORIENTATION, etc.
System Settings
LANGUAGE,KOREADER_SYNC,CALIBRE_SETTINGS, etc.
Status Messages
CONNECTING,CONNECTED,FAILED,SUCCESS, etc.
File Transfer
FILE_TRANSFER,HOTSPOT_MODE,NETWORK_PREFIX, etc.
File Storage
Language settings are stored in:
/.crosspoint/i18n.bin
This file contains:
- Current language selection (1 byte)
Adding a New Language
To add support for a new language:
-
Add language to enum in
lib/I18n/I18n.h:enum class Language : uint8_t { EN = 0, ZH = 1, JA = 2, KO = 3, // New: Korean _COUNT }; -
Create translation array in
lib/I18n/I18n.cpp:static const char* const STRINGS_KO[] = { // All strings translated to Korean }; -
Add to language arrays:
static const char* const* const LANGUAGE_STRINGS[] = { STRINGS_EN, STRINGS_ZH, STRINGS_JA, STRINGS_KO, // New }; -
Add language name for the language selection UI:
// In LanguageSelectActivity or I18n const char* languageNames[] = { "English", "简体中文", "日本語", "한국어", // New }; -
Ensure CJK font support for the new language's characters
Best Practices
- Keep translations concise - E-ink displays have limited space
- Test on device - Some characters may render differently
- Use consistent terminology - Keep translations consistent across the UI
- Consider context - Same word may need different translations in different contexts
- Update all languages - When adding new strings, add translations for all languages
Troubleshooting
Characters showing as boxes
- Enable CJK UI font in Settings → Display
- Ensure the font includes the required characters
- Check that the font file is not corrupted
Language not saving
- Check SD card is not write-protected
- Verify
/.crosspoint/directory exists - Check available space on SD card
Missing translations
- Verify string ID exists in the enum
- Check all language arrays have the same number of entries
- Rebuild firmware after adding new strings
Related Documentation
- CJK Font Support - External font installation
- File Formats - Binary file format specifications
- Troubleshooting - General troubleshooting guide