Files
kangkang/康康/Features/Quick/A2ConfirmView.swift
link2026 d2c77d5c51 feat: 国际化(i18n) en/ja/ko + App 内语言切换
主体:多语言支持(简体中文源 + 英/日/韩)
- 基础设施:Localizable.xcstrings(String Catalog,sourceLanguage=zh-Hans)
  + pbxproj developmentRegion/knownRegions 注册 en/ja/ko
- 全部硬编码 Locale("zh_CN") → Locale.current;中文 dateFormat → Date.FormatStyle(跟随系统)
- UI 中文字面量统一为 String(appLoc:)(显式绑定所选语言 bundle+locale,即时切换)
  Text 字面量走环境 \.locale + Bundle 重定向
- 549 个 catalog key 全部 en/ja/ko 翻译完成(0 未翻译)
- App 内语言切换:我的 → 语言(LanguageManager + 即时生效,无需重启)
- 双用预设(症状/监测指标/慢病)本地化:static→computed 避免缓存

注:本提交为 WIP,一并打包了并行进行的功能模块
(HealthExport 健康导出、Security/Face ID 锁、DiaryAssist 日记 AI 辅助)
及 App 图标、CLAUDE.md、docs/scripts。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 10:28:24 +08:00

181 lines
6.8 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import SwiftUI
struct A2ConfirmView: View {
var onSave: () -> Void
var onNext: () -> Void
var onBack: () -> Void
@State private var expanded = false
var body: some View {
VStack(spacing: 0) {
header
ScrollView(showsIndicators: false) {
VStack(alignment: .leading, spacing: 0) {
croppedPhoto.padding(.bottom, 14)
resultCard.padding(.bottom, 16)
actions
}
.padding(.horizontal, 18)
.padding(.bottom, 18)
}
}
.background(Tj.Palette.sand.ignoresSafeArea())
}
private var header: some View {
HStack(spacing: 6) {
Button(action: onBack) {
Image(systemName: "chevron.left")
.font(.system(size: 18, weight: .semibold))
.foregroundStyle(Tj.Palette.text)
.frame(width: 36, height: 36)
}
Text("核对识别结果")
.font(.system(size: 15, weight: .semibold))
.foregroundStyle(Tj.Palette.text)
Spacer()
Text("识别用时 0.4s · 本地")
.font(.system(size: 10, design: .monospaced))
.foregroundStyle(Tj.Palette.text3)
.padding(.horizontal, 8)
.padding(.vertical, 4)
.background(Capsule().fill(Tj.Palette.sand2))
}
.padding(.horizontal, 12)
.padding(.top, 4)
.padding(.bottom, 8)
}
private var croppedPhoto: some View {
ZStack(alignment: .topTrailing) {
Text("低密度脂蛋白 3.84 mmol/L ↑")
.font(.system(size: 13, design: .monospaced))
.fontWeight(.semibold)
.tracking(0.3)
.foregroundStyle(Tj.Palette.text)
.padding(.vertical, 14)
.padding(.horizontal, 16)
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color(red: 0.96, green: 0.93, blue: 0.87).opacity(0.92))
.clipShape(RoundedRectangle(cornerRadius: Tj.Radius.md, style: .continuous))
.shadow(color: Color(red: 0.196, green: 0.157, blue: 0.098).opacity(0.06),
radius: 2, x: 0, y: 1)
Text("已裁剪")
.font(.system(size: 9))
.tracking(0.5)
.foregroundStyle(Tj.Palette.text3)
.padding(.top, 8)
.padding(.trailing, 10)
}
}
private var resultCard: some View {
VStack(alignment: .leading, spacing: 14) {
HStack(alignment: .top) {
VStack(alignment: .leading, spacing: 4) {
Text("指标名 · 可编辑")
.font(.system(size: 11))
.foregroundStyle(Tj.Palette.text3)
Text("低密度脂蛋白胆固醇")
.font(.system(size: 19, weight: .semibold))
.foregroundStyle(Tj.Palette.text)
Text("LDL-C")
.font(.system(size: 12))
.foregroundStyle(Tj.Palette.text3)
}
Spacer()
TjBadge(text: String(appLoc: "偏高"), style: .brick)
}
HStack(spacing: 12) {
FieldBox(label: String(appLoc: "数值")) {
HStack(alignment: .firstTextBaseline, spacing: 4) {
Text("3.84")
.font(.system(size: 30, weight: .semibold))
.foregroundStyle(Tj.Palette.brick)
Text("mmol/L")
.font(.system(size: 11, design: .monospaced))
.foregroundStyle(Tj.Palette.text3)
}
}
FieldBox(label: String(appLoc: "参考范围")) {
HStack(alignment: .firstTextBaseline, spacing: 4) {
Text("< 3.40")
.font(.system(size: 14, design: .monospaced))
.foregroundStyle(Tj.Palette.text2)
Text("mmol/L")
.font(.system(size: 11, design: .monospaced))
.foregroundStyle(Tj.Palette.text3)
}
}
}
Button { withAnimation { expanded.toggle() } } label: {
HStack(alignment: .top, spacing: 10) {
RoundedRectangle(cornerRadius: 2, style: .continuous)
.fill(Tj.Palette.brick)
.frame(width: 4)
Text(expanded
? "超过参考上限 0.44属轻度偏高。建议关注饮食结构减少动物脂肪摄入3 个月内复查。若家族有心血管病史,可与医生沟通是否需要药物干预。"
: "超过参考上限 0.44,属轻度偏高。点击展开详细解读 ")
.font(.system(size: 12))
.foregroundStyle(Tj.Palette.text2)
.lineSpacing(5)
.multilineTextAlignment(.leading)
.frame(maxWidth: .infinity, alignment: .leading)
}
.padding(12)
.background(
RoundedRectangle(cornerRadius: Tj.Radius.sm, style: .continuous)
.fill(Tj.Palette.sand)
)
}
.buttonStyle(.plain)
}
.padding(18)
.tjCard()
}
private var actions: some View {
VStack(spacing: 10) {
Button(action: onSave) {
Text("保存到记录")
.frame(maxWidth: .infinity)
}
.buttonStyle(TjPrimaryButton())
Button(action: onNext) {
HStack(spacing: 8) {
Image(systemName: "camera.fill").font(.system(size: 14))
Text("继续拍下一项")
}
.frame(maxWidth: .infinity)
}
.buttonStyle(TjGhostButton())
}
}
}
private struct FieldBox<Content: View>: View {
let label: String
@ViewBuilder var content: Content
var body: some View {
VStack(alignment: .leading, spacing: 4) {
Text(label)
.font(.system(size: 10))
.tracking(0.5)
.foregroundStyle(Tj.Palette.text3)
content
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.vertical, 10)
.padding(.horizontal, 12)
.overlay(
RoundedRectangle(cornerRadius: Tj.Radius.sm, style: .continuous)
.strokeBorder(Tj.Palette.lineSoft, lineWidth: 1)
)
}
}