# i18n_tool **Repository Path**: Jumping99/i18n_tool ## Basic Information - **Project Name**: i18n_tool - **Description**: 这是一个将 CSV 国际化翻译表 编译为自定义 LAN 二进制文件 的命令行工具 - **Primary Language**: C++ - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-16 - **Last Updated**: 2026-09-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # i18n_tool > 版本:0.1 ## 介绍 i18n_tool 是一个命令行工具,用于将 **CSV 国际化翻译表** 编译为嵌入式设备可用的资源文件。 CSV文件可用excel表格工具编辑,方便维护和更新,需注意文件编码为UTF-8,避免解析异常。 支持两种输出格式: - **C 字符串数组格式**(`.c` + `.h`):生成含枚举和数组的 C 源码,通过索引偏移直接访问,读取效率高。 - **哈希表格式**(`.lan` / `.c`):生成哈希表结构的文件,支持通过字符串直接查找,开发更灵活。 --- ## 快速开始 ### 编译 ```bash # 1. 配置 mkdir build && cd build # Windows (MinGW) cmake .. -G "MinGW Makefiles" # Windows (Visual Studio 2022) cmake .. -G "Visual Studio 17 2022" # Linux / macOS cmake .. # 2. 构建 cmake --build . # 或 make ``` 编译产物: - `i18n_tool.exe` / `i18n_tool` — 主工具 - `example.exe` / `example` — 示例程序(包含字符串数组格式和哈希表格式的对比测试) ### 基本用法 ```bash # 显示帮助信息 i18n_tool -h # 将 test.csv 编译为 C 字符串数组格式(默认), 并指定输出文件名为 output i18n_tool -i test.csv -o output # 生成 output.c 和 output.h # 将 test.csv 编译为哈希表格式的二进制文件, 并指定输出文件名为 output i18n_tool -i test.csv -o output --hash-table -b # 生成 output.lan(二进制) # 将 test.csv 编译为哈希表格式的 C 数组文件, 并指定输出文件名为 output i18n_tool -i test.csv -o output --hash-table # 生成 output.c(C 数组文本) ``` --- ## 命令行选项 | 选项 | 说明 | |------|------| | `-i ` | **(必要)** 指定输入的 CSV 文件路径 | | `-o ` | 指定输出文件名(不含后缀)。**C 字符串数组格式下,该名称同时作为生成的数组变量名和头文件宏名前缀**。也可指定输出路径,如 `../src/dictionary` | | `-b` | 生成二进制 `.lan` 文件,仅在使用 `--hash-table` 时有效;未指定则生成 C 数组文本文件(`.c`) | | `--hash-table` | 使用哈希表格式输出;未指定则默认生成 C 字符串数组格式(`.c` + `.h`) | | `--align ` | 指定各区块、数据段的对齐字节数(1-128),默认 4 字节对齐。对于嵌入式设备,合适的对齐值可提升内存访问效率 | | `-h`, `--help` | 显示英文帮助信息 | | `--help-zh` | 显示中文帮助信息(UTF-8 编码) | --- ## CSV 文件格式 CSV 文件的第一列必须是 `Code`(文本标识符),后续列是各语言的翻译文本,列标题为语言名称。 ### 列忽略规则 如果某列标题以 `*` 开头,则该语言列将被跳过,不会输出到最终文件中。这在需要临时禁用某个语言版本时非常有用。 示例(`test.csv`): ```csv Code,English,Chinese,Spanish Monday,Monday,周一,Lunes Tuesday,Tuesday,周二,Martes Wednesday,Wednesday,周三,Miércoles Thursday,Thursday,周四,Juves Friday,Friday,周五,Viernes Saturday,Saturday,周六,Sábado Sunday,Sunday,周日,Domingo ``` > - **文件编码**:建议使用 UTF-8 编码保存 CSV 文件,以正确支持中文等非 ASCII 字符。 > - **C 字符串数组格式**:Code 列和标题行必须符合 C 语言标识符规则,不能包含特殊字符。哈希表格式无此限制。 > - **空字符串处理**:哈希表格式下,翻译文本为空字符串的记录会被自动过滤,不写入输出文件。C 字符串数组格式则保留为 `NULL`,查找时返回 `"null"`。 --- ## 输出格式对比 | 特性 | C 字符串数组格式 | 哈希表格式 | |------|-----------------|-----------| | 输出文件 | `.c` + `.h` | `.lan`(二进制)或 `.c`(C数组) | | 查找方式 | 枚举索引偏移 | FNV-1a 哈希值二分查找 | | Code 列要求 | 必须符合 C 标识符规则 | 任意字符串 | | 空翻译文本 | 保留为 `NULL`,返回 `"null"` | 自动过滤,不写入输出 | | 查找失败行为 | 返回 `"null"` | 返回原查找字符串 | | 读取效率 | **高** | 中等 | | 开发体验 | 需先完善 Code 列 | 直接用字符串查找,更灵活 | | 完整性校验 | 无 | CRC32 头部校验 | --- ## LAN 文件二进制格式 使用 `--hash-table -b` 生成的 `.lan` 文件具有以下内部结构(小端字节序): ### 文件头(Header) | 字段 | 大小 | 说明 | |------|------|------| | `magic` | 4 字节 | 魔数 `0xFC9559CF` | | `header_size` | 4 字节 | 头部总字节数(含 CRC) | | `language_count` | 4 字节 | 语言数量 | | `language_dsc[]` | 变长 | 每个语言的语言描述块 | | `crc32` | 4 字节 | 头部 CRC32 校验值(不含自身) | | `padding` | 变长 | 对齐填充字节 | ### 语言描述块(Language DSC) | 字段 | 大小 | 说明 | |------|------|------| | `name` | 变长 | 语言名称(`\0` 结尾的 C 字符串) | | `string_count` | 4 字节 | 该语言的字串数量(哈希表条目数) | | `hash_section_offset` | 4 字节 | 该语言哈希区块相对于文件头的偏移量 | ### 语言区块 每个语言区块包含三个子区域: 1. **哈希表** — 有序的 `(hash_value, info_offset)` 对,按 hash_value 升序排列 2. **信息节** — 哈希碰撞信息及译文字符串偏移量 3. **字串节** — 以 `\0` 结尾的译文字符串 各区块之间按 `--align` 指定的字节数对齐。 ### 哈希冲突处理 当多个原始字符串产生相同 FNV-1a 哈希值时: - 信息节记录冲突数量及每个冲突的原字符串 - 查找时先通过哈希值二分定位,若存在冲突则逐个比较原字符串 > 二进制格式文件可以直接嵌入项目(如作为 C 数组编译进固件),也可以作为独立 `.lan` 资源文件存放在文件系统中动态加载。 --- ## 运行时集成 ### C 字符串数组格式 生成的 `.c` 和 `.h` 文件可直接加入项目编译,通过以下 API 访问: ```c #include "output.h" unsigned int count = language_get_count(); // 获取语言数量 const char *name = language_get_name(LANGUAGE_ENGLISH); // 获取语言名称 const char *text = language_get_text(LANGUAGE_ENGLISH, TEXT_Monday); // 获取翻译文本(参数无效或者翻译文本为空时返回"null"字符串) ``` ### 哈希表格式 使用 `lan_image_decoder/` 目录下的运行时解码库(纯 C,无依赖,但编译器需要支持 C99 及以上标准): ```c #include "lan_decoder.h" // 将 .lan 文件加载到内存后,或者直接使用 C 数组数据: lan_decoder_t *decoder = lan_decoder_create(image_data, image_size); const char *text = lan_decoder_get_language_text(decoder, 0, "Monday"); lan_decoder_destroy(decoder); ``` #### 解码器 API 完整列表 | 函数 | 说明 | |------|------| | `lan_decoder_create(image_data, image_size)` | 创建解码器实例。返回 `NULL` 表示数据无效(魔数不匹配或 CRC 校验失败) | | `lan_decoder_destroy(decoder)` | 销毁解码器实例,释放所有已分配内存 | | `lan_decoder_get_language_count(decoder)` | 获取语言数量 | | `lan_decoder_get_language_name(decoder, lan_id)` | 获取指定索引的语言名称 | | `lan_decoder_get_language_text(decoder, lan_id, text)` | 获取翻译文本。查找失败时返回原字符串 `text`;`text` 为 `NULL` 时返回 `"null"` | #### 解码库可选配置(`lan_config.h`) 解码库通过宏提供便携配置,无需修改源代码即可适配不同平台: ```c // 自定义内存分配函数(默认使用标准库 malloc/free) #define lan_malloc(size) malloc(size) #define lan_free(ptr) free(ptr) // 日志开关(设为 1 开启调试日志,默认 0 关闭) #define LAN_USE_LOG 0 ``` > 对于嵌入式 RTOS 环境,可以将 `lan_malloc` / `lan_free` 重定向到 `pvPortMalloc` / `vPortFree` 等平台内存函数。 --- ## 工程结构 ``` i18n_tool/ ├── main.cpp # 程序入口 ├── CMakeLists.txt # CMake 构建配置 ├── 语言文件描述.png # LAN 文件二进制格式示意图 ├── 语言文件描述.xmind # LAN 文件二进制格式思维导图 ├── source/ # 源文件 │ ├── param.cpp # 命令行参数解析 │ ├── dictionary.cpp # CSV 文件解析 │ ├── file_generator.cpp # 文件生成调度 │ ├── lan_file_encoder.cpp # LAN 镜像编码器 │ └── byte_array.cpp # 字节数组工具 ├── include/ # 头文件 │ ├── param.h │ ├── dictionary.h │ ├── file_generator.h │ ├── lan_file_encoder.h │ ├── byte_array.h │ ├── csv.h # 第三方 CSV 解析库(BSD-3) │ └── string_array_file_template.h # C 代码模板 ├── lan_image_decoder/ # 运行时解码库(纯 C,无依赖) │ ├── lan_decoder.h # 解码器 API 头文件 │ ├── lan_decoder.c # 解码器实现 │ ├── lan_type.h # 内部类型定义 │ └── lan_config.h # 平台适配配置(内存/日志) ├── OptionParser/ # 自研命令行解析库 │ ├── OptionParser.h │ └── OptionParser.cpp └── example/ # 示例文件 ├── test.csv # 示例翻译表 ├── test.c / test.h # C 字符串数组格式示例输出 ├── test_hash.c # 哈希表格式示例输出(C 数组) ├── test_hash.lan # 哈希表格式示例输出(二进制) └── main.cpp # 示例入口(含性能对比测试) ``` --- ## 依赖 - CMake >= 3.12.4 - C++17 编译器(如 GCC、Clang、MSVC) - 无其他第三方依赖 ## 更新日志 #### 2026.09.17-v0.1版本 第一个版本发布