feat: app full l10n support

This commit is contained in:
2024-03-16 19:13:49 +08:00
parent 66738abf60
commit a6b69553d5
25 changed files with 636 additions and 501 deletions

View File

@ -99,8 +99,7 @@ class HomeGameLoginUIModel extends _$HomeGameLoginUIModel {
final ok = await showConfirmDialogs(
context,
S.current.home_action_q_auto_password_fill_prompt,
const Text(
"盒子将使用 PIN 与 Windows 凭据加密保存您的密码,密码只存储在您的设备中。\n\n当下次登录需要输入密码时您只需授权PIN即可自动填充登录。"));
Text(S.current.home_login_info_password_encryption_notice));
if (ok == true) {
if (await _localAuth.authenticate(
localizedReason:
@ -131,8 +130,9 @@ class HomeGameLoginUIModel extends _$HomeGameLoginUIModel {
final ok = await showConfirmDialogs(
context,
S.current.home_login_info_game_version_outdated,
Text(
"RSI 服务器报告版本号:${releaseInfo?["versionLabel"]} \n\n本地版本号:${buildInfo["RequestedP4ChangeNum"]} \n\n建议使用 RSI Launcher 更新游戏!"),
Text(S.current.home_login_info_rsi_server_report(
releaseInfo?["versionLabel"],
buildInfo["RequestedP4ChangeNum"])),
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width * .4),
cancel: S.current.home_login_info_action_ignore);
@ -165,10 +165,9 @@ class HomeGameLoginUIModel extends _$HomeGameLoginUIModel {
final ok = await showConfirmDialogs(
context,
S.current.home_login_action_title_box_one_click_launch,
const Text(
"本功能可以帮您更加便利的启动游戏。\n\n为确保账户安全 ,本功能使用汉化浏览器保留登录状态,且不会保存您的密码信息(除非你启用了自动填充功能)。"
"\n\n使用此功能登录账号时请确保您的 SC汉化盒子 是从可信任的来源下载。",
style: TextStyle(fontSize: 16),
Text(
S.current.home_login_info_one_click_launch_description,
style: const TextStyle(fontSize: 16),
),
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width * .6));
@ -183,8 +182,8 @@ class HomeGameLoginUIModel extends _$HomeGameLoginUIModel {
}
if (!await WebviewWindow.isWebviewAvailable()) {
if (!context.mounted) return;
await showToast(context,
S.current.home_login_action_title_need_webview2_runtime);
await showToast(
context, S.current.home_login_action_title_need_webview2_runtime);
if (!context.mounted) return;
await launchUrlString(
"https://developer.microsoft.com/en-us/microsoft-edge/webview2/");

View File

@ -24,13 +24,17 @@ class HomeDownloaderUI extends HookConsumerWidget {
const SizedBox(width: 24),
const SizedBox(width: 12),
for (final item in <MapEntry<String, IconData>, String>{
const MapEntry("settings", FluentIcons.settings): S.current.downloader_speed_limit_settings,
const MapEntry("settings", FluentIcons.settings):
S.current.downloader_speed_limit_settings,
if (state.tasks.isNotEmpty)
const MapEntry("pause_all", FluentIcons.pause): S.current.downloader_action_pause_all,
const MapEntry("pause_all", FluentIcons.pause):
S.current.downloader_action_pause_all,
if (state.waitingTasks.isNotEmpty)
const MapEntry("resume_all", FluentIcons.download): S.current.downloader_action_resume_all,
const MapEntry("resume_all", FluentIcons.download):
S.current.downloader_action_resume_all,
if (state.tasks.isNotEmpty || state.waitingTasks.isNotEmpty)
const MapEntry("cancel_all", FluentIcons.cancel): S.current.downloader_action_cancel_all,
const MapEntry("cancel_all", FluentIcons.cancel):
S.current.downloader_action_cancel_all,
}.entries)
Padding(
padding: const EdgeInsets.only(left: 6, right: 6),
@ -119,7 +123,9 @@ class HomeDownloaderUI extends HookConsumerWidget {
Row(
children: [
Text(
"总大小:${FileSize.getSize(task.totalLength ?? 0)}",
S.current.downloader_info_total_size(
FileSize.getSize(
task.totalLength ?? 0)),
style: const TextStyle(fontSize: 14),
),
const SizedBox(width: 12),
@ -127,17 +133,22 @@ class HomeDownloaderUI extends HookConsumerWidget {
task.verifiedLength != null &&
task.verifiedLength != 0)
Text(
"校验中...${FileSize.getSize(task.verifiedLength)}",
S.current.downloader_info_verifying(
FileSize.getSize(
task.verifiedLength)),
style: const TextStyle(fontSize: 14),
)
else if (task.status == "active")
Text(
"下载中... (${((task.completedLength ?? 0) * 100 / (task.totalLength ?? 1)).toStringAsFixed(4)}%)")
Text(S.current
.downloader_info_downloading(
((task.completedLength ?? 0) *
100 /
(task.totalLength ?? 1))
.toStringAsFixed(4)))
else
Text(
"状态:${model.statusMap[task.status]}",
style: const TextStyle(fontSize: 14),
),
Text(S.current.downloader_info_status(
model.statusMap[task.status] ??
"Unknown")),
const SizedBox(width: 24),
if (task.status == "active" &&
task.verifiedLength == null)
@ -151,10 +162,10 @@ class HomeDownloaderUI extends HookConsumerWidget {
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"已上传:${FileSize.getSize(task.uploadLength)}"),
Text(
"已下载:${FileSize.getSize(task.completedLength)}"),
Text(S.current.downloader_info_uploaded(
FileSize.getSize(task.uploadLength))),
Text(S.current.downloader_info_downloaded(
FileSize.getSize(task.completedLength))),
],
),
const SizedBox(width: 18),
@ -173,20 +184,23 @@ class HomeDownloaderUI extends HookConsumerWidget {
closeAfterClick: false,
title: Padding(
padding: const EdgeInsets.all(3),
child: Text(S.current.downloader_action_options),
child:
Text(S.current.downloader_action_options),
),
items: [
if (task.status == "paused")
MenuFlyoutItem(
leading:
const Icon(FluentIcons.download),
text: Text(S.current.downloader_action_continue_download),
text: Text(S.current
.downloader_action_continue_download),
onPressed: () =>
model.resumeTask(task.gid))
else if (task.status == "active")
MenuFlyoutItem(
leading: const Icon(FluentIcons.pause),
text: Text(S.current.downloader_action_pause_download),
text: Text(S.current
.downloader_action_pause_download),
onPressed: () =>
model.pauseTask(task.gid)),
const MenuFlyoutSeparator(),
@ -195,7 +209,8 @@ class HomeDownloaderUI extends HookConsumerWidget {
FluentIcons.chrome_close,
size: 14,
),
text: Text(S.current.downloader_action_cancel_download),
text: Text(S.current
.downloader_action_cancel_download),
onPressed: () =>
model.cancelTask(context, task.gid)),
MenuFlyoutItem(
@ -231,10 +246,9 @@ class HomeDownloaderUI extends HookConsumerWidget {
),
),
const SizedBox(width: 12),
Text(
"下载: ${FileSize.getSize(state.globalStat?.downloadSpeed ?? 0)}/s 上传:${FileSize.getSize(state.globalStat?.uploadSpeed ?? 0)}/s",
style: const TextStyle(fontSize: 12),
)
Text(S.current.downloader_info_download_upload_speed(
FileSize.getSize(state.globalStat?.downloadSpeed ?? 0),
FileSize.getSize(state.globalStat?.uploadSpeed ?? 0)))
],
),
),
@ -243,4 +257,4 @@ class HomeDownloaderUI extends HookConsumerWidget {
),
useBodyContainer: true);
}
}
}

View File

@ -79,7 +79,9 @@ class HomeDownloaderUIModel extends _$HomeDownloaderUIModel {
return;
case "cancel_all":
final userOK = await showConfirmDialogs(
context, "确认取消全部任务?", Text(S.current.downloader_info_manual_file_deletion_note));
context,
S.current.downloader_action_confirm_cancel_all_tasks,
Text(S.current.downloader_info_manual_file_deletion_note));
if (userOK == true) {
if (!aria2cState.isRunning) return;
try {
@ -170,7 +172,9 @@ class HomeDownloaderUIModel extends _$HomeDownloaderUIModel {
if (gid != null) {
if (!context.mounted) return;
final ok = await showConfirmDialogs(
context, "确认取消下载?", Text(S.current.downloader_info_manual_file_deletion_note));
context,
S.current.downloader_action_confirm_cancel_download,
Text(S.current.downloader_info_manual_file_deletion_note));
if (ok == true) {
final aria2c = ref.read(aria2cModelProvider).aria2c;
await aria2c?.remove(gid);
@ -303,4 +307,4 @@ class HomeDownloaderUIModel extends _$HomeDownloaderUIModel {
}
}
}
}
}

View File

@ -30,7 +30,8 @@ class HomeGameDoctorUI extends HookConsumerWidget {
}, []);
return makeDefaultPage(context,
title: "一键诊断 -> ${homeState.scInstalledPath}",
title: S.current
.doctor_title_one_click_diagnosis(homeState.scInstalledPath ?? ""),
useBodyContainer: true,
content: Stack(
children: [
@ -40,7 +41,7 @@ class HomeGameDoctorUI extends HookConsumerWidget {
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
for (final item in {
for (final item in {
"rsi_log": S.current.doctor_action_rsi_launcher_log,
"game_log": S.current.doctor_action_game_run_log,
}.entries)
@ -82,7 +83,8 @@ class HomeGameDoctorUI extends HookConsumerWidget {
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 12),
Text(S.current.doctor_info_scan_complete_no_issues, maxLines: 1),
Text(S.current.doctor_info_scan_complete_no_issues,
maxLines: 1),
const SizedBox(height: 64),
],
),
@ -121,8 +123,8 @@ class HomeGameDoctorUI extends HookConsumerWidget {
Widget makeRescueBanner(BuildContext context) {
return GestureDetector(
onTap: () async {
await showToast(context,
S.current.doctor_info_game_rescue_service_note);
await showToast(
context, S.current.doctor_info_game_rescue_service_note);
launchUrlString(
"https://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=-M4wEme_bCXbUGT4LFKLH0bAYTFt70Ad&authKey=vHVr0TNgRmKu%2BHwywoJV6EiLa7La2VX74Vkyixr05KA0H9TqB6qWlCdY%2B9jLQ4Ha&noverify=0&group_code=536454632");
},
@ -175,22 +177,26 @@ class HomeGameDoctorUI extends HookConsumerWidget {
Widget makeResultItem(BuildContext context, MapEntry<String, String> item,
HomeGameDoctorState state, HomeGameDoctorUIModel model) {
final errorNames = {
"unSupport_system":
MapEntry("不支持的操作系统,游戏可能无法运行", "请升级您的系统 (${item.value})"),
"unSupport_system": MapEntry(S.current.doctor_info_result_unsupported_os,
S.current.doctor_info_result_upgrade_system(item.value)),
"no_live_path": MapEntry(S.current.doctor_info_result_missing_live_folder,
"点击修复为您创建 LIVE 文件夹,完成后重试安装。(${item.value})"),
"nvme_PhysicalBytes": MapEntry(S.current.doctor_info_result_incompatible_nvme_device,
"为注册表项添加 ForcedPhysicalSectorSizeInBytes 值 模拟旧设备。硬盘分区(${item.value})"),
"eac_file_miss": MapEntry(S.current.doctor_info_result_missing_easyanticheat_files,
S.current.doctor_info_result_create_live_folder(item.value)),
"nvme_PhysicalBytes": MapEntry(
S.current.doctor_info_result_incompatible_nvme_device,
S.current.doctor_info_result_add_registry_value(item.value)),
"eac_file_miss": MapEntry(
S.current.doctor_info_result_missing_easyanticheat_files,
S.current.doctor_info_result_verify_files_with_rsi_launcher),
"eac_not_install": MapEntry(S.current.doctor_info_result_easyanticheat_not_installed,
"eac_not_install": MapEntry(
S.current.doctor_info_result_easyanticheat_not_installed,
S.current.doctor_info_result_install_easyanticheat),
"cn_user_name":
MapEntry("中文用户名!", S.current.doctor_info_result_chinese_username_error),
"cn_install_path": MapEntry(S.current.doctor_info_result_chinese_install_path,
"中文安装路径!这可能会导致游戏 启动/安装 错误!(${item.value}请在RSI启动器更换安装路径。"),
"low_ram": MapEntry(
"物理内存过低", "您至少需要 16GB 的物理内存Memory才可运行此游戏。当前大小${item.value}"),
"cn_user_name": MapEntry(S.current.doctor_info_result_chinese_username,
S.current.doctor_info_result_chinese_username_error),
"cn_install_path": MapEntry(
S.current.doctor_info_result_chinese_install_path,
S.current.doctor_info_result_chinese_install_path_error(item.value)),
"low_ram": MapEntry(S.current.doctor_info_result_low_physical_memory,
S.current.doctor_info_result_memory_requirement(item.value)),
};
bool isCheckedError = errorNames.containsKey(item.key);
@ -211,7 +217,9 @@ class HomeGameDoctorUI extends HookConsumerWidget {
children: [
const SizedBox(height: 4),
Text(
"修复建议: ${errorNames[item.key]?.value ?? "暂无解决方法,请截图反馈"}",
S.current.doctor_info_result_fix_suggestion(
errorNames[item.key]?.value ??
S.current.doctor_info_result_no_solution),
style: TextStyle(
fontSize: 14, color: Colors.white.withOpacity(.7)),
),
@ -225,7 +233,8 @@ class HomeGameDoctorUI extends HookConsumerWidget {
await model.doFix(context, item);
},
child: Padding(
padding: const EdgeInsets.only(left: 8, right: 8, top: 4, bottom: 4),
padding:
const EdgeInsets.only(left: 8, right: 8, top: 4, bottom: 4),
child: Text(S.current.doctor_info_action_fix),
),
),
@ -263,8 +272,8 @@ class HomeGameDoctorUI extends HookConsumerWidget {
launchUrlString(item.value);
},
child: Padding(
padding:
const EdgeInsets.only(left: 8, right: 8, top: 4, bottom: 4),
padding: const EdgeInsets.only(
left: 8, right: 8, top: 4, bottom: 4),
child: Text(S.current.doctor_action_view_solution),
),
)
@ -291,4 +300,4 @@ class HomeGameDoctorUI extends HookConsumerWidget {
return;
}
}
}
}

View File

@ -49,29 +49,30 @@ class HomeGameDoctorUIModel extends _$HomeGameDoctorUIModel {
try {
await Directory(item.value).create(recursive: true);
if (!context.mounted) break;
showToast(context, S.current.doctor_action_result_create_folder_success);
showToast(
context, S.current.doctor_action_result_create_folder_success);
checkResult.remove(item);
state = state.copyWith(checkResult: checkResult);
} catch (e) {
showToast(context, "创建文件夹失败,请尝试手动创建。\n目录:${item.value} \n错误:$e");
showToast(context,
S.current.doctor_action_result_create_folder_fail(item.value, e));
}
break;
case "nvme_PhysicalBytes":
final r = await SystemHelper.addNvmePatch();
if (r == "") {
if (!context.mounted) break;
showToast(context,
S.current.doctor_action_result_fix_success);
showToast(context, S.current.doctor_action_result_fix_success);
checkResult.remove(item);
state = state.copyWith(checkResult: checkResult);
} else {
if (!context.mounted) break;
showToast(context, "修复失败,$r");
showToast(context, S.current.doctor_action_result_fix_fail(r));
}
break;
case "eac_file_miss":
showToast(
context, S.current.doctor_info_result_verify_files_with_rsi_launcher);
showToast(context,
S.current.doctor_info_result_verify_files_with_rsi_launcher);
break;
case "eac_not_install":
final eacJsonPath = "${item.value}\\Settings.json";
@ -84,16 +85,18 @@ class HomeGameDoctorUIModel extends _$HomeGameDoctorUIModel {
dPrint("${item.value}\\EasyAntiCheat_EOS_Setup.exe install $eacID");
if (result.stderr == "") {
if (!context.mounted) break;
showToast(context, S.current.doctor_action_result_game_start_success);
showToast(
context, S.current.doctor_action_result_game_start_success);
checkResult.remove(item);
state = state.copyWith(checkResult: checkResult);
} else {
if (!context.mounted) break;
showToast(context, "修复失败,${result.stderr}");
showToast(context,
S.current.doctor_action_result_fix_fail(result.stderr));
}
} catch (e) {
if (!context.mounted) break;
showToast(context, "修复失败,$e");
showToast(context, S.current.doctor_action_result_fix_fail(e));
}
break;
case "cn_user_name":
@ -112,7 +115,8 @@ class HomeGameDoctorUIModel extends _$HomeGameDoctorUIModel {
// ignore: avoid_build_context_in_providers
doCheck(BuildContext context) async {
if (state.isChecking) return;
state = state.copyWith(isChecking: true, lastScreenInfo: S.current.doctor_action_analyzing);
state = state.copyWith(
isChecking: true, lastScreenInfo: S.current.doctor_action_analyzing);
dPrint("-------- start docker check -----");
if (!context.mounted) return;
await _statCheck(context);
@ -140,7 +144,9 @@ class HomeGameDoctorUIModel extends _$HomeGameDoctorUIModel {
final lastScreenInfo = S.current.doctor_action_result_analysis_no_issue;
state = state.copyWith(checkResult: null, lastScreenInfo: lastScreenInfo);
} else {
final lastScreenInfo = "分析完毕,发现 ${checkResult.length} 个问题";
final lastScreenInfo = S.current
.doctor_action_result_analysis_issues_found(
checkResult.length.toString());
state = state.copyWith(
checkResult: checkResult, lastScreenInfo: lastScreenInfo);
}
@ -162,10 +168,13 @@ class HomeGameDoctorUIModel extends _$HomeGameDoctorUIModel {
final info = SCLoggerHelper.getGameRunningLogInfo(logs);
if (info != null) {
if (info.key != "_") {
checkResult.add(MapEntry("游戏异常退出:${info.key}", info.value));
checkResult.add(MapEntry(
S.current.doctor_action_info_game_abnormal_exit(info..key),
info.value));
} else {
checkResult
.add(MapEntry("游戏异常退出:未知异常", "info:${info.value},请点击右下角加群反馈。"));
checkResult.add(MapEntry(
S.current.doctor_action_info_game_abnormal_exit_unknown,
S.current.doctor_action_info_info_feedback(info.value)));
}
}
}
@ -212,7 +221,8 @@ class HomeGameDoctorUIModel extends _$HomeGameDoctorUIModel {
Platform.operatingSystemVersion.contains("Windows 11"))) {
checkResult
.add(MapEntry("unSupport_system", Platform.operatingSystemVersion));
final lastScreenInfo = "不支持的操作系统:${Platform.operatingSystemVersion}";
final lastScreenInfo = S.current.doctor_action_result_info_unsupported_os(
Platform.operatingSystemVersion);
state = state.copyWith(lastScreenInfo: lastScreenInfo);
await showToast(context, lastScreenInfo);
}
@ -226,7 +236,8 @@ class HomeGameDoctorUIModel extends _$HomeGameDoctorUIModel {
if (ramSize < 16) {
checkResult.add(MapEntry("low_ram", "$ramSize"));
}
state = state.copyWith(lastScreenInfo: S.current.doctor_action_info_checking_install_info);
state = state.copyWith(
lastScreenInfo: S.current.doctor_action_info_checking_install_info);
// 检查安装分区
try {
final listData = await SCLoggerHelper.getGameInstallPath(
@ -270,4 +281,4 @@ class HomeGameDoctorUIModel extends _$HomeGameDoctorUIModel {
dPrint(e);
}
}
}
}

View File

@ -207,10 +207,13 @@ class HomeUI extends HookConsumerWidget {
colorFilter: makeSvgColor(Colors.white),
height: 18,
),
name: S.current.home_action_star_citizen_website_localization,
webTitle: S.current.home_action_star_citizen_website_localization,
name: S.current
.home_action_star_citizen_website_localization,
webTitle: S.current
.home_action_star_citizen_website_localization,
webURL: "https://robertsspaceindustries.com",
info: S.current.home_action_info_roberts_space_industries_origin,
info: S.current
.home_action_info_roberts_space_industries_origin,
useLocalization: true,
width: width,
touchKey: "webLocalization_rsi"),
@ -228,7 +231,8 @@ class HomeUI extends HookConsumerWidget {
name: S.current.home_action_uex_localization,
webTitle: S.current.home_action_uex_localization,
webURL: "https://uexcorp.space/",
info: S.current.home_action_info_mining_refining_trade_calculator,
info: S.current
.home_action_info_mining_refining_trade_calculator,
useLocalization: true,
width: width,
touchKey: "webLocalization_uex"),
@ -244,9 +248,11 @@ class HomeUI extends HookConsumerWidget {
],
),
name: S.current.home_action_dps_calculator_localization,
webTitle: S.current.home_action_dps_calculator_localization,
webTitle:
S.current.home_action_dps_calculator_localization,
webURL: "https://www.erkul.games/live/calculator",
info: S.current.home_action_info_ship_upgrade_damage_value_query,
info: S.current
.home_action_info_ship_upgrade_damage_value_query,
useLocalization: true,
width: width,
touchKey: "webLocalization_dps"),
@ -434,11 +440,20 @@ class HomeUI extends HookConsumerWidget {
Widget makeIndexActionLists(BuildContext context, HomeUIModel model,
HomeUIModelState homeState, WidgetRef ref) {
final items = [
_HomeItemData("game_doctor", "一键诊断", S.current.home_action_info_one_click_diagnosis_star_citizen,
_HomeItemData(
"game_doctor",
S.current.home_action_one_click_diagnosis,
S.current.home_action_info_one_click_diagnosis_star_citizen,
FluentIcons.auto_deploy_settings),
_HomeItemData(
"localization", "汉化管理", S.current.home_action_info_quick_install_localization_resources, FluentIcons.locale_language),
_HomeItemData("performance", "性能优化", S.current.home_action_info_engine_config_optimization,
"localization",
S.current.home_action_localization_management,
S.current.home_action_info_quick_install_localization_resources,
FluentIcons.locale_language),
_HomeItemData(
"performance",
S.current.home_action_performance_optimization,
S.current.home_action_info_engine_config_optimization,
FluentIcons.process_meta_task),
];
return Padding(
@ -591,7 +606,8 @@ class HomeUI extends HookConsumerWidget {
double width, HomeUIModelState homeState) {
final statusCnName = {
"Platform": S.current.home_action_rsi_status_platform,
"Persistent Universe": S.current.home_action_rsi_status_persistent_universe,
"Persistent Universe":
S.current.home_action_rsi_status_persistent_universe,
"Electronic Access": S.current.home_action_rsi_status_electronic_access,
"Arena Commander": S.current.home_action_rsi_status_arena_commander
};
@ -601,7 +617,9 @@ class HomeUI extends HookConsumerWidget {
borderRadius: BorderRadius.circular(12),
child: GestureDetector(
onTap: () {
model.goWebView(context, S.current.home_action_rsi_status_rsi_server_status,
model.goWebView(
context,
S.current.home_action_rsi_status_rsi_server_status,
"https://status.robertsspaceindustries.com/",
useLocalization: true);
},
@ -741,7 +759,8 @@ class HomeUI extends HookConsumerWidget {
context: context,
builder: (context) {
return HomeMdContentDialogUI(
title: homeState.appPlacardData?.title ?? S.current.home_announcement_details,
title: homeState.appPlacardData?.title ??
S.current.home_announcement_details,
url: homeState.appPlacardData?.link,
);
});
@ -757,7 +776,7 @@ class HomeUI extends HookConsumerWidget {
_onMenuTap(BuildContext context, String key, HomeUIModelState homeState,
WidgetRef ref) async {
String gameInstallReqInfo =
"该功能需要一个有效的安装位置\n\n如果您的游戏未下载完成,请等待下载完毕后使用此功能。\n\n如果您的游戏已下载完毕但未识别,请启动一次游戏后重新打开盒子 或 在设置选项中手动设置安装位置。";
S.current.home_action_info_valid_install_location_required;
switch (key) {
case "localization":
if (homeState.scInstalledPath == "not_install") {
@ -786,4 +805,4 @@ class _HomeItemData {
String name;
String infoString;
IconData icon;
}
}

View File

@ -91,7 +91,9 @@ class HomeUIModel extends _$HomeUIModel {
if (scInstallPaths.isNotEmpty) {
scInstalledPath = scInstallPaths.first;
}
final lastScreenInfo = "扫描完毕,共找到 ${scInstallPaths.length} 个有效安装目录";
final lastScreenInfo = S.current
.home_action_info_scan_complete_valid_directories_found(
scInstallPaths.length.toString());
state = state.copyWith(
scInstalledPath: scInstalledPath,
scInstallPaths: scInstallPaths,
@ -141,10 +143,9 @@ class HomeUIModel extends _$HomeUIModel {
final ok = await showConfirmDialogs(
context,
S.current.home_action_title_star_citizen_website_localization,
const Text(
"本插功能件仅供大致浏览使用,不对任何有关本功能产生的问题负责!在涉及账号操作前请注意确认网站的原本内容!"
"\n\n\n使用此功能登录账号时请确保您的 SC汉化盒子 是从可信任的来源下载。",
style: TextStyle(fontSize: 16),
Text(
S.current.home_action_info_web_localization_plugin_disclaimer,
style: const TextStyle(fontSize: 16),
),
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width * .6));
@ -159,8 +160,8 @@ class HomeUIModel extends _$HomeUIModel {
}
if (!await WebviewWindow.isWebviewAvailable()) {
if (!context.mounted) return;
showToast(context,
S.current.home_login_action_title_need_webview2_runtime);
showToast(
context, S.current.home_login_action_title_need_webview2_runtime);
launchUrlString(
"https://developer.microsoft.com/en-us/microsoft-edge/webview2/");
return;
@ -171,13 +172,12 @@ class HomeUIModel extends _$HomeUIModel {
if (useLocalization) {
state = state.copyWith(
isFixing: true,
isFixingString:
S.current.home_action_info_initializing_resources);
isFixingString: S.current.home_action_info_initializing_resources);
try {
await webViewModel.initLocalization(state.webLocalizationVersionsData!);
} catch (e) {
if (!context.mounted) return;
showToast(context, "初始化网页汉化资源失败!$e");
showToast(context, S.current.home_action_info_initialization_failed(e));
}
state = state.copyWith(isFixingString: "", isFixing: false);
}
@ -294,7 +294,8 @@ class HomeUIModel extends _$HomeUIModel {
if (toastContent != null) {
final xmlNodeList = toastContent.getElementsByTagName('text');
final title = S.current.home_localization_new_version_available;
final content = '您在 ${updates.first} 安装的汉化有新版本啦!';
final content =
S.current.home_localization_new_version_installed(updates.first);
xmlNodeList.item(0)?.appendChild(toastContent.createTextNode(title));
xmlNodeList
.item(1)
@ -329,8 +330,7 @@ class HomeUIModel extends _$HomeUIModel {
final ok = await showConfirmDialogs(
context,
S.current.home_info_one_click_launch_warning,
const Text("为确保账户安全,一键启动功能已在开发版中禁用,我们将在微软商店版本中提供此功能。"
"\n\n微软商店版由微软提供可靠的分发下载与数字签名,可有效防止软件被恶意篡改。\n\n提示:您无需使用盒子启动游戏也可使用汉化。"),
Text(S.current.home_info_account_security_warning),
confirm: S.current.home_action_install_microsoft_store_version,
cancel: S.current.home_action_cancel);
if (ok == true) {
@ -389,8 +389,21 @@ class HomeUIModel extends _$HomeUIModel {
}
}
if (!context.mounted) return;
showToast(context,
"游戏非正常退出\nexitCode=${result.exitCode}\nstdout=${result.stdout ?? ""}\nstderr=${result.stderr ?? ""}\n\n诊断信息:${exitInfo == null ? "未知错误,请通过一键诊断加群反馈。" : exitInfo.key} \n${hasUrl ? "请查看弹出的网页链接获得详细信息。" : exitInfo?.value ?? ""}");
// showToast(context,
// "游戏非正常退出\nexitCode=${result.exitCode}\nstdout=${result.stdout ?? ""}\nstderr=${result.stderr ?? ""}\n\n诊断信息${exitInfo == null ? "未知错误,请通过一键诊断加群反馈。" : exitInfo.key} \n${hasUrl ? "请查看弹出的网页链接获得详细信息。" : exitInfo?.value ?? ""}");
// S.current.home_action_info_abnormal_game_exit
showToast(
context,
S.current.home_action_info_abnormal_game_exit(
result.exitCode.toString(),
result.stdout ?? "",
result.stderr ?? "",
exitInfo == null
? S.current.home_action_info_unknown_error
: exitInfo.key,
hasUrl
? S.current.home_action_info_check_web_link
: exitInfo?.value ?? ""));
if (hasUrl) {
await Future.delayed(const Duration(seconds: 3));
launchUrlString(exitInfo!.value);

View File

@ -41,8 +41,8 @@ class LocalizationDialogUI extends HookConsumerWidget {
padding: const EdgeInsets.only(bottom: 12),
child: InfoBar(
title: Text(S.current.home_action_info_warning),
content: Text(
S.current.localization_info_machine_translation_warning),
content: Text(S.current
.localization_info_machine_translation_warning),
severity: InfoBarSeverity.info,
style: InfoBarThemeData(decoration: (severity) {
return const BoxDecoration(
@ -66,8 +66,10 @@ class LocalizationDialogUI extends HookConsumerWidget {
Row(
children: [
Center(
child: Text(
"启用(${LocalizationUIModel.languageSupport[state.selectedLanguage]}"),
child: Text(S.current.localization_info_enabled(
LocalizationUIModel.languageSupport[
state.selectedLanguage] ??
"")),
),
const Spacer(),
ToggleSwitch(
@ -79,7 +81,8 @@ class LocalizationDialogUI extends HookConsumerWidget {
const SizedBox(height: 12),
Row(
children: [
Text("已安装版本:${state.patchStatus?.value}"),
Text(S.current.localization_info_installed_version(
state.patchStatus?.value ?? "")),
const Spacer(),
if (state.patchStatus?.value !=
S.current.home_action_info_game_built_in)
@ -93,8 +96,8 @@ class LocalizationDialogUI extends HookConsumerWidget {
children: [
const Icon(FluentIcons.feedback),
const SizedBox(width: 6),
Text(
S.current.localization_action_translation_feedback),
Text(S.current
.localization_action_translation_feedback),
],
),
)),
@ -107,8 +110,8 @@ class LocalizationDialogUI extends HookConsumerWidget {
children: [
const Icon(FluentIcons.delete),
const SizedBox(width: 6),
Text(
S.current.localization_action_uninstall_translation),
Text(S.current
.localization_action_uninstall_translation),
],
),
)),
@ -185,8 +188,7 @@ class LocalizationDialogUI extends HookConsumerWidget {
? FluentIcons.chevron_up
: FluentIcons.chevron_down),
const SizedBox(width: 12),
Text(
S.current.localization_action_advanced_features),
Text(S.current.localization_action_advanced_features),
],
),
onPressed: model.toggleCustomize),
@ -233,8 +235,8 @@ class LocalizationDialogUI extends HookConsumerWidget {
right: 8,
top: 4,
bottom: 4),
child: Text(
S.current.localization_action_install),
child: Text(S.current
.localization_action_install),
))
],
)
@ -288,17 +290,20 @@ class LocalizationDialogUI extends HookConsumerWidget {
),
const SizedBox(height: 4),
Text(
"版本号:${item.value.versionName}",
S.current.localization_info_version_number(
item.value.versionName ?? ""),
style: TextStyle(color: Colors.white.withOpacity(.6)),
),
const SizedBox(height: 4),
Text(
"通道:${item.value.gameChannel}",
S.current.localization_info_channel(
item.value.gameChannel ?? ""),
style: TextStyle(color: Colors.white.withOpacity(.6)),
),
const SizedBox(height: 4),
Text(
"更新时间:${item.value.updateAt}",
S.current.localization_info_update_time(
item.value.updateAt ?? ""),
style: TextStyle(color: Colors.white.withOpacity(.6)),
),
],
@ -332,7 +337,7 @@ class LocalizationDialogUI extends HookConsumerWidget {
Text(isInstalled
? S.current.localization_info_installed
: ((item.value.enable ?? false)
? "安装"
? S.current.localization_action_install
: S.current.localization_info_unavailable)),
],
),

View File

@ -16,6 +16,7 @@ import 'package:starcitizen_doctor/common/io/rs_http.dart';
import 'package:starcitizen_doctor/common/utils/log.dart';
import 'package:starcitizen_doctor/common/utils/provider.dart';
import 'package:starcitizen_doctor/data/sc_localization_data.dart';
import 'package:starcitizen_doctor/generated/no_l10n_strings.dart';
import 'package:starcitizen_doctor/ui/home/home_ui_model.dart';
import 'package:starcitizen_doctor/widgets/widgets.dart';
import 'package:url_launcher/url_launcher_string.dart';
@ -38,9 +39,9 @@ class LocalizationUIState with _$LocalizationUIState {
@riverpod
class LocalizationUIModel extends _$LocalizationUIModel {
static const languageSupport = {
"chinese_(simplified)": "简体中文",
"chinese_(traditional)": "繁體中文",
static const languageSupport = {
"chinese_(simplified)": NoL10n.langZHS,
"chinese_(traditional)": NoL10n.langZHT,
};
late final _downloadDir =
@ -123,8 +124,8 @@ class LocalizationUIModel extends _$LocalizationUIModel {
final ok = await showConfirmDialogs(
context,
S.current.localization_info_remove_incompatible_translation_params,
const Text(
"USER.cfg 包含不兼容的汉化参数,这可能是以前的汉化文件的残留信息。\n\n这将可能导致汉化无效或乱码,点击确认为您一键移除(不会影响其他配置)。"),
Text(S.current
.localization_info_incompatible_translation_params_warning),
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width * .35));
if (ok == true) {
@ -226,7 +227,9 @@ class LocalizationUIModel extends _$LocalizationUIModel {
state = state.copyWith(workingVersion: filePath);
final str = await f.readAsString();
await _installFormString(
StringBuffer(str), "自定义_${getCustomizeFileName(filePath)}");
StringBuffer(str),
S.current
.localization_info_custom_file(getCustomizeFileName(filePath)));
state = state.copyWith(workingVersion: "");
};
}
@ -256,8 +259,7 @@ class LocalizationUIModel extends _$LocalizationUIModel {
}
openDir(BuildContext context) async {
showToast(context,
"即将打开本地化文件夹,请将自定义的 任意名称.ini 文件放入 Customize_ini 文件夹。\n\n添加新文件后未显示请使用右上角刷新按钮。\n\n安装时请确保选择了正确的语言。");
showToast(context, S.current.localization_info_custom_file_instructions);
await Process.run(SystemHelper.powershellPath,
["explorer.exe", "/select,\"${_customizeDir.absolute.path}\"\\"]);
}
@ -293,7 +295,8 @@ class LocalizationUIModel extends _$LocalizationUIModel {
await _installFormString(globalIni, value.versionName ?? "");
} catch (e) {
if (!context.mounted) return;
await showToast(context, "安装出错!\n\n $e");
await showToast(
context, S.current.localization_info_installation_error(e));
if (await savePath.exists()) await savePath.delete();
}
state = state.copyWith(workingVersion: "");
@ -371,7 +374,9 @@ class LocalizationUIModel extends _$LocalizationUIModel {
static Future<String> _getInstalledIniVersion(String iniPath) async {
final iniFile = File(iniPath);
if (!await iniFile.exists()) return S.current.home_action_info_game_built_in;
if (!await iniFile.exists()) {
return S.current.home_action_info_game_built_in;
}
final iniStringSplit = (await iniFile.readAsString()).split("\n");
for (var i = iniStringSplit.length - 1; i > 0; i--) {
if (iniStringSplit[i]
@ -408,7 +413,9 @@ class LocalizationUIModel extends _$LocalizationUIModel {
if (element.path.contains(lang)) {
final installedVersion =
await _getInstalledIniVersion("${element.path}\\global.ini");
if (installedVersion == S.current.home_action_info_game_built_in) continue;
if (installedVersion == S.current.home_action_info_game_built_in) {
continue;
}
final curData = _allVersionLocalizationData[lang];
dPrint("check Localization update $scInstallPath");
if (!(curData?.keys.contains(installedVersion) ?? false)) {
@ -428,4 +435,4 @@ class LocalizationUIModel extends _$LocalizationUIModel {
}
return updates;
}
}
}

View File

@ -30,10 +30,11 @@ class HomePerformanceUI extends HookConsumerWidget {
children: [
if (state.showGraphicsPerformanceTip)
InfoBar(
title: Text(
S.current.performance_info_graphic_optimization_hint),
title: Text(S.current
.performance_info_graphic_optimization_hint),
content: Text(
S.current.performance_info_graphic_optimization_warning,
S.current
.performance_info_graphic_optimization_warning,
),
onClose: () => model.closeTip(),
),
@ -41,7 +42,10 @@ class HomePerformanceUI extends HookConsumerWidget {
Row(
children: [
Text(
"当前状态:${state.enabled ? "已应用" : "未应用"}",
S.current.performance_info_current_status(
state.enabled
? S.current.performance_info_applied
: S.current.performance_info_not_applied),
style: const TextStyle(fontSize: 18),
),
const SizedBox(width: 32),
@ -66,8 +70,8 @@ class HomePerformanceUI extends HookConsumerWidget {
onPressed: () =>
model.onChangePreProfile(item.key)),
),
Text(
S.current.performance_action_info_preset_only_changes_graphics),
Text(S.current
.performance_action_info_preset_only_changes_graphics),
const Spacer(),
Button(
onPressed: () => model.refresh(),
@ -93,7 +97,8 @@ class HomePerformanceUI extends HookConsumerWidget {
const SizedBox(width: 6),
Button(
child: Text(
S.current.performance_action_apply_and_clear_shaders,
S.current
.performance_action_apply_and_clear_shaders,
style: const TextStyle(fontSize: 16),
),
onPressed: () => model.applyProfile(true)),
@ -138,7 +143,8 @@ class HomePerformanceUI extends HookConsumerWidget {
}
return makeDefaultPage(context,
title: "性能优化 -> ${model.scPath}",
title:
S.current.performance_title_performance_optimization(model.scPath),
useBodyContainer: true,
content: content);
}
@ -246,8 +252,7 @@ class HomePerformanceUI extends HookConsumerWidget {
else if (item.type == "customize")
TextFormBox(
maxLines: 10,
placeholder:
"您可以在这里输入未收录进盒子的自定义参数。配置示例:\n\nr_displayinfo=0\nr_VSync=0",
placeholder: S.current.performance_action_custom_parameters_input,
controller: model.customizeCtrl,
),
if (item.info != null && item.info!.isNotEmpty) ...[
@ -264,7 +269,8 @@ class HomePerformanceUI extends HookConsumerWidget {
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
"${item.key} 最小值: ${item.min} / 最大值: ${item.max}",
S.current.performance_info_min_max_values(
item.key ?? "", item.min ?? "", item.max ?? ""),
style: TextStyle(color: Colors.white.withOpacity(.6)),
)
],