From 5350017085d81abd645a67b9b3c05292eaa6fac8 Mon Sep 17 00:00:00 2001 From: yecong Date: Wed, 17 Jun 2026 14:09:47 +0800 Subject: [PATCH] Update DFU translations and ignore local sdk workspace --- .gitignore | 3 ++ src/DfuScreen.tsx | 113 +++++++++++++++++++++++---------------- src/InfoScreen.tsx | 22 +++++--- src/i18n/locales/en.json | 9 +++- src/i18n/locales/zh.json | 9 +++- 5 files changed, 103 insertions(+), 53 deletions(-) diff --git a/.gitignore b/.gitignore index 6f92ce9..ad0a611 100644 --- a/.gitignore +++ b/.gitignore @@ -74,3 +74,6 @@ yarn-error.log !.yarn/releases !.yarn/sdks !.yarn/versions + +# Local SDK workspace +sdk/ diff --git a/src/DfuScreen.tsx b/src/DfuScreen.tsx index b9c1597..0716643 100644 --- a/src/DfuScreen.tsx +++ b/src/DfuScreen.tsx @@ -9,6 +9,7 @@ import { DfuProgressEvent, DfuStateEvent, } from "@systemic-games/react-native-nordic-nrf5-dfu"; +import { useTranslation } from "react-i18next"; import MyStatusbar from "./component/MyStatusbar"; import MyHeader from "./component/MyHeader"; @@ -66,39 +67,40 @@ export default function DfuScreen({ route, navigation }: Props) { name, firmware: deviceFirmware, } = route.params; + const { t } = useTranslation(); const [progress, setProgress] = useState(0); - const [state, setState] = useState("准备中..."); + const [state, setState] = useState(t("dfu.preparing")); const [error, setError] = useState(); - const [latestVersion, setLatestVersion] = useState("读取中..."); + const [latestVersion, setLatestVersion] = useState(t("dfu.reading")); const [isDfuRunning, setIsDfuRunning] = useState(false); const startedRef = useRef(false); - const mapDfuStateToChinese = (s: string): string => { + const mapDfuStateToLabel = (s: string): string => { switch (s) { case "connecting": - return "连接中…"; + return t("dfu.stateConnecting"); case "starting": - return "初始化中…"; + return t("dfu.stateStarting"); case "enablingDfuMode": - return "启用 DFU 模式…"; + return t("dfu.stateEnablingDfuMode"); case "uploading": - return "上传固件中…"; + return t("dfu.stateUploading"); case "validating": - return "校验固件…"; + return t("dfu.stateValidating"); case "disconnecting": - return "断开连接…"; + return t("dfu.stateDisconnecting"); case "completed": - return "升级完成"; + return t("dfu.stateCompleted"); case "aborted": - return "已取消"; + return t("dfu.stateAborted"); case "failed": case "dfu_failed": - return "升级失败"; + return t("dfu.stateFailed"); case "initializing": - return "启动中…"; + return t("dfu.stateInitializing"); case "errored": - return "升级出错!"; + return t("dfu.stateErrored"); default: return s; } @@ -108,11 +110,11 @@ export default function DfuScreen({ route, navigation }: Props) { const unsubscribe = navigation.addListener("beforeRemove", (e) => { if (!isDfuRunning) return; e.preventDefault(); - Alert.alert("请稍候", "正在升级,请勿返回或关闭应用!"); + Alert.alert(t("dfu.pleaseWait"), t("dfu.doNotReturn")); }); return unsubscribe; - }, [navigation, isDfuRunning]); + }, [navigation, isDfuRunning, t]); useEffect(() => { trace("screen mounted", { @@ -163,7 +165,7 @@ export default function DfuScreen({ route, navigation }: Props) { }); if (!safeDeviceId) { - throw new Error("无法生成 DFU 目标设备 ID"); + throw new Error(t("dfu.invalidTargetDeviceId")); } const currentFw = parseFirmwareVersion(firmwareText); @@ -178,7 +180,9 @@ export default function DfuScreen({ route, navigation }: Props) { trace("manifest fetch response", { status: manifestResp.status }); if (!manifestResp.ok) { - throw new Error(`manifest 下载失败,HTTP ${manifestResp.status}`); + throw new Error( + t("dfu.manifestDownloadFailed", { status: manifestResp.status }) + ); } const manifestText = await manifestResp.text(); @@ -192,7 +196,11 @@ export default function DfuScreen({ route, navigation }: Props) { try { manifest = JSON.parse(manifestText) as { devices: DeviceInfo[] }; } catch (e) { - throw new Error("manifest 不是合法 JSON: " + manifestText.slice(0, 200)); + throw new Error( + t("dfu.manifestInvalidJson", { + preview: manifestText.slice(0, 200), + }) + ); } const deviceInfo = manifest.devices.find( @@ -204,9 +212,9 @@ export default function DfuScreen({ route, navigation }: Props) { if (!deviceInfo) { setIsDfuRunning(false); Alert.alert( - "无法升级", - `未找到 hardware=${currentFw.hardware} 的固件`, - [{ text: "确认", onPress: () => navigation.goBack() }] + t("dfu.cannotUpgrade"), + t("dfu.hardwareNotFound", { hardware: currentFw.hardware }), + [{ text: t("dfu.confirm"), onPress: () => navigation.goBack() }] ); return; } @@ -218,14 +226,17 @@ export default function DfuScreen({ route, navigation }: Props) { if (latestFw.hardware !== currentFw.hardware) { throw new Error( - `服务器固件硬件号不匹配:当前 ${currentFw.hardware},服务器 ${latestFw.hardware}` + t("dfu.hardwareMismatch", { + current: currentFw.hardware, + latest: latestFw.hardware, + }) ); } if (latestFw.iteration <= currentFw.iteration) { setIsDfuRunning(false); - Alert.alert("无需升级", "已是最新固件,无需升级", [ - { text: "确认", onPress: () => navigation.goBack() }, + Alert.alert(t("dfu.noNeedUpgrade"), t("dfu.alreadyLatest"), [ + { text: t("dfu.confirm"), onPress: () => navigation.goBack() }, ]); return; } @@ -258,14 +269,18 @@ export default function DfuScreen({ route, navigation }: Props) { trace("firmware download result", downloadResult); if (downloadResult.statusCode !== 200) { - throw new Error(`固件包下载失败,HTTP ${downloadResult.statusCode}`); + throw new Error( + t("dfu.firmwareDownloadFailed", { + status: downloadResult.statusCode, + }) + ); } const fileExists = await RNFS.exists(localPath); trace("firmware exists check", { fileExists }); if (!fileExists) { - throw new Error(`固件包下载后文件不存在: ${localPath}`); + throw new Error(t("dfu.firmwareFileMissing", { path: localPath })); } const fileStat = await RNFS.stat(localPath); @@ -273,7 +288,9 @@ export default function DfuScreen({ route, navigation }: Props) { trace("firmware stat", fileStat); if (!Number.isFinite(fileSize) || fileSize <= 0) { - throw new Error(`固件包文件无效,大小为 ${fileStat.size}`); + throw new Error( + t("dfu.firmwareFileInvalid", { size: String(fileStat.size) }) + ); } const dfuFilePath = "file://" + localPath; @@ -310,9 +327,9 @@ export default function DfuScreen({ route, navigation }: Props) { trace("startDfu resolved successfully"); setIsDfuRunning(false); - Alert.alert("升级成功", "升级成功,请重连设备", [ + Alert.alert(t("dfu.upgradeSuccess"), t("dfu.upgradeSuccessMessage"), [ { - text: "确认", + text: t("dfu.confirm"), onPress: () => { navigation.reset({ index: 0, @@ -329,21 +346,21 @@ export default function DfuScreen({ route, navigation }: Props) { error: err, }); setIsDfuRunning(false); - setError(err?.message || "DFU失败"); - Alert.alert("升级失败", err?.message || "DFU失败", [ - { text: "确认", onPress: () => navigation.goBack() }, + setError(err?.message || t("dfu.dfuFailed")); + Alert.alert(t("dfu.upgradeFailed"), err?.message || t("dfu.dfuFailed"), [ + { text: t("dfu.confirm"), onPress: () => navigation.goBack() }, ]); } }; runDfu(); - }, [deviceId, name, deviceFirmware, navigation]); + }, [deviceId, name, deviceFirmware, navigation, t]); return ( - 蓝牙名称: {name || "--"} - - - - 最新版本: {latestVersion} - - - - 当前版本: {deviceFirmware || "--"} + + {t("dfu.bluetoothName")}: {name || "--"} + - 升级状态: {mapDfuStateToChinese(state)} + {t("dfu.latestVersion")}: {latestVersion} + + + + + + {t("dfu.currentVersion")}: {deviceFirmware || "--"} + + + + + + {t("dfu.upgradeStatus")}: {mapDfuStateToLabel(state)} diff --git a/src/InfoScreen.tsx b/src/InfoScreen.tsx index 1751fd3..d6d21f6 100644 --- a/src/InfoScreen.tsx +++ b/src/InfoScreen.tsx @@ -217,24 +217,34 @@ export default function InfoScreen({ route, navigation }: Props) { }; const readBatteryCharacteristic = async () => { - for (let attempt = 0; attempt < 3; attempt += 1) { + let lastValidBattery: number | null = null; + + for (let attempt = 0; attempt < 4; attempt += 1) { try { const bytes = await readCharacteristicWithRetry("180f", "2a19", 1); const batteryValue = bytes[0]; - if (Number.isInteger(batteryValue) && batteryValue >= 0 && batteryValue <= 100) { - return `${batteryValue}%`; + if ( + Number.isInteger(batteryValue) && + batteryValue >= 0 && + batteryValue <= 100 + ) { + if (lastValidBattery !== null && lastValidBattery === batteryValue) { + return `${batteryValue}%`; + } + + lastValidBattery = batteryValue; } } catch { // Continue retrying with a short gap below. } - if (attempt < 2) { - await sleep(180); + if (attempt < 3) { + await sleep(220); } } - return "未知"; + return lastValidBattery !== null ? `${lastValidBattery}%` : "未知"; }; const subscribePowerDataIfNeeded = async () => { diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index af137b3..1e040b8 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -189,9 +189,16 @@ "doNotReturn": "Updating in progress, do not go back or close the app!", "cannotUpgrade": "Cannot Update", - "hardwareNotFound": "Firmware not found for hardware version {hardware}", + "hardwareNotFound": "Firmware not found for hardware version {{hardware}}", "noNeedUpgrade": "No Update Needed", "alreadyLatest": "Already the latest firmware, no update needed", + "invalidTargetDeviceId": "Unable to generate DFU target device ID", + "manifestDownloadFailed": "Manifest download failed, HTTP {{status}}", + "manifestInvalidJson": "Manifest is not valid JSON: {{preview}}", + "hardwareMismatch": "Firmware hardware mismatch: current {{current}}, server {{latest}}", + "firmwareDownloadFailed": "Firmware package download failed, HTTP {{status}}", + "firmwareFileMissing": "Firmware package file not found after download: {{path}}", + "firmwareFileInvalid": "Firmware package file is invalid, size {{size}}", "upgradeSuccess": "Update Successful", "upgradeSuccessMessage": "Update successful, please reconnect the device", diff --git a/src/i18n/locales/zh.json b/src/i18n/locales/zh.json index df27188..074f3fe 100644 --- a/src/i18n/locales/zh.json +++ b/src/i18n/locales/zh.json @@ -189,9 +189,16 @@ "doNotReturn": "正在升级,请勿返回或关闭应用!", "cannotUpgrade": "无法升级", - "hardwareNotFound": "未找到硬件版本 {hardware} 的固件", + "hardwareNotFound": "未找到硬件版本 {{hardware}} 的固件", "noNeedUpgrade": "无需升级", "alreadyLatest": "已是最新固件,无需升级", + "invalidTargetDeviceId": "无法生成 DFU 目标设备 ID", + "manifestDownloadFailed": "manifest 下载失败,HTTP {{status}}", + "manifestInvalidJson": "manifest 不是合法 JSON: {{preview}}", + "hardwareMismatch": "服务器固件硬件号不匹配:当前 {{current}},服务器 {{latest}}", + "firmwareDownloadFailed": "固件包下载失败,HTTP {{status}}", + "firmwareFileMissing": "固件包下载后文件不存在: {{path}}", + "firmwareFileInvalid": "固件包文件无效,大小为 {{size}}", "upgradeSuccess": "升级成功", "upgradeSuccessMessage": "升级成功,请重连设备",