一、背景
开发的桌面应用要求对应用名称进行多语言个性化:
-
支持多语言安装环境:
- 中文环境生成程序入口为
中文应用.exe
- 其他语言环境生成程序入口为
AppEN.exe
- 中文环境生成程序入口为
-
安装包在安装后,快捷方式、任务管理器显示的进程名需对应语言环境。
-
用户数据、SharedPreferences(SP)、数据库等持久化存储路径需保持一致,不随程序入口名称变化,保证原有逻辑不受干扰,最小程度侵入;
-
CI/CD 流程基于 Jenkins,需要支持远程自动打包。
二、遇到的问题记录
1. NSIS 中文语句报错
最初尝试在 NSIS 脚本中直接使用中文程序名:
nsis
OutFile "中文应用.exe"
CreateShortCut "$DESKTOP\中文应用.lnk" "$INSTDIR\中文应用.exe"
或者直接重命名 exe
nsis
File "${EXE_NAME}"
Rename "$INSTDIR\${EXE_NAME}" "$INSTDIR\中文应用.exe"
问题现象:
- 本地编译正常,但 Jenkins 执行构建时失败
- 错误信息多为 "Invalid character set" 或找不到文件
原因分析:
- NSIS 默认 ANSI 编码,如果脚本中包含中文字符,在英文系统或 Jenkins 执行环境(通常非中文)下无法正确解析
- 中文字符可能在 UTF-8 或系统默认编码下被误处理,导致编译失败
2. CMake 多 EXE 输出
尝试在 CMake 中配置多程序入口:
camke
cmake_minimum_required(VERSION 3.15)
project(MyApp)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
# 原始可执行文件
add_executable(myapp main.cpp)
# 生成多语言版本(仅重命名副本,避免在 NSIS 内部硬编码中文)
add_custom_command(TARGET myapp POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
$<TARGET_FILE:myapp> ${CMAKE_BINARY_DIR}/bin/myapp_en.exe
COMMAND ${CMAKE_COMMAND} -E copy
$<TARGET_FILE:myapp> ${CMAKE_BINARY_DIR}/bin/myapp_zh.exe
)
问题现象:
- 构建阶段可以生成多个 EXE(
中文应用.exe
和English App.exe
) - 安装界面文本仍然固定
- 程序启动及任务管理器显示名称不稳定
- SP、数据库等存储路径未受影响,但在某些安装目录下出现权限或访问异常
原因分析:
- CMake 对
RUNTIME_OUTPUT_NAME
的编码依赖系统环境,中文名称在 Jenkins 或英文环境下可能无法正确生成 - 即便 EXE 成功生成,NSIS 拷贝或快捷方式创建过程中仍可能因中文文件名报错
3. CMake 多 EXE 输出 + LangString
Tips
安装界面多语言采用 NSIS 官方推荐的 LangString
机制: Reference/LangString - NSIS
LangString
定义一组以 语言 ID 区分的字符串常量- 在运行时,NSIS 会根据用户选择的安装语言自动切换对应的字符串
- 使用时通过
$(变量名)
引用,而不是直接写死在脚本里
具体实现
根据安装平台拷贝 exe
nsis
${If} $LANGUAGE == ${LANG_SIMPCHINESE}
File /oname=$(EXE_NAME_LOCALIZED) "..\build\windows\x64\runner\${BT}\中文应用.exe"
${ElseIf} $LANGUAGE == ${LANG_TRADCHINESE}
File /oname=$(EXE_NAME_LOCALIZED) "..\build\windows\x64\runner\${BT}\中文应用.exe"
${Else}
File /oname=$(EXE_NAME_LOCALIZED) "..\build\windows\x64\runner\${BT}\AppEN.exe"
${EndIf}
安装界面多语言
nsis
!include MUI2.nsh
!insertmacro MUI_LANGUAGE "English"
!insertmacro MUI_LANGUAGE "SimpChinese"
; 定义不同语言下的应用名称
LangString APP_NAME ${LANG_ENGLISH} "AppEN"
LangString APP_NAME ${LANG_SIMPCHINESE} "我的应用"
Section "Install"
; 在快捷方式创建中引用 LangString
CreateShortcut "$DESKTOP\$(APP_NAME).lnk" "$INSTDIR\myapp.exe"
SectionEnd
效果验证:
- 不论 Jenkins 或本地环境,NSIS 编译均可通过
- 安装后,中文系统显示
中文应用.exe
,英文系统显示AppEN.exe
- 任务管理器显示名称符合语言环境
- 用户 SP、数据库路径保持不变,不受 EXE 重命名影响
原因分析:
LangString
内部使用 Unicode 编码,支持多语言环境安全解析- 避免了在 NSIS 脚本中直接书写中文字符,兼容 Jenkins 的英文系统环境
三、最终构建流程
flowchart TD
A["用户运行安装程序"] --> B["NSIS 检测系统语言($LANGUAGE)"]
B --> C{"语言判断分支"}
C -->|LANG_SIMPCHINESE| D["选择 '中文应用.exe'"]
C -->|LANG_ENGLISH默认| F["选择 'AppEN.exe'"]
D --> G["LangString 动态设置界面文本和文件名"]
F --> G
G --> H["File /oname=$(EXE_NAME_LOCALIZED)\n复制对应 exe"]
H --> I["创建快捷方式\n$(PRODUCT_NAME_LOCALIZED).lnk"]
-
Flutter build
- 执行
flutter build windows
,生成默认 EXE。 - 使用 CMake 配置生成多语言输出(可选,作为中间文件管理)。
- 执行
-
NSIS 安装包生成
- 脚本中使用
LangString
定义不同语言的 EXE 名称。 - 拷贝构建生成的 EXE,并在安装目录重命名。
- 创建语言对应的快捷方式。
- 脚本中使用
-
持久化数据路径管理
- Flutter 应用中 SP、数据库路径固定使用
AppData\Roaming\MyApp
或其他固定路径。 - 重命名 EXE 不影响数据访问。
- Flutter 应用中 SP、数据库路径固定使用
-
Jenkins CI/CD
- Jenkins 执行 NSIS 脚本时,无需额外修改系统语言环境。
- 编译流程全程 Unicode 安全。
四、总结与建议
graph TD
A[Flutter项目] --> B[flutter build windows]
B --> C[CMake配置]
C --> D[生成两个exe: AppEN.exe & AppCN.exe]
D --> E[NSIS安装脚本]
E --> F{系统语言环境判断}
F -->|中文环境| G[设置名称为 中文命名.exe]
F -->|其他语言| H[设置名称为 AppEN.exe]
G --> I[拷贝文件到安装目录]
H --> I
I --> J[创建桌面快捷方式]
J --> K[保持用户数据路径一致性]
K --> L[安装完成]
%% 问题说明
M[NSIS中文命名兼容性问题] --> D
N[多exe生成配置] --> C
O[LangString多语言解决方案] --> F
- NSIS 不直接使用中文字符:避免编码问题,特别是 CI/CD 英文系统环境。
- 使用 LangString 实现多语言文件名:安全可靠,支持简繁中文及英文。
- CMake 输出多 EXE 可选:主要用于本地或调试环境,生产安装包依赖 NSIS 重命名更稳定。
- 持久化路径固定:保证用户数据、SP、数据库不随 EXE 名称变化,提升跨语言环境兼容性。
- CI/CD 环境安全:Unicode + LangString 可以在 Jenkins 英文系统下顺利打包。