feat: 更新AppSettingFeature以增强用户体验和本地化支持
- 在AppSettingFeature中新增登出确认和关于我们弹窗的状态和Action。 - 更新AppSettingView以支持登出确认和关于我们弹窗的逻辑。 - 替换多个视图中的NSLocalizedString为LocalizedString,提升本地化一致性。 - 在Localizable.strings中新增相关本地化文本,确保多语言支持。
This commit is contained in:
@@ -47,6 +47,10 @@ struct AppSettingFeature {
|
||||
var showImageSourceActionSheet: Bool = false
|
||||
// 新增:选择的图片源
|
||||
var selectedImageSource: AppImageSource? = nil
|
||||
|
||||
// 新增:弹窗状态
|
||||
var showLogoutConfirmation: Bool = false
|
||||
var showAboutUs: Bool = false
|
||||
}
|
||||
|
||||
enum Action: Equatable {
|
||||
@@ -87,6 +91,11 @@ struct AppSettingFeature {
|
||||
case setShowImageSourceActionSheet(Bool)
|
||||
// 新增:图片源选择
|
||||
case selectImageSource(AppImageSource)
|
||||
|
||||
// 新增:弹窗相关
|
||||
case showLogoutConfirmation(Bool)
|
||||
case showAboutUs(Bool)
|
||||
case logoutConfirmed
|
||||
}
|
||||
|
||||
@Dependency(\.apiService) var apiService
|
||||
@@ -101,6 +110,11 @@ struct AppSettingFeature {
|
||||
return .none
|
||||
|
||||
case .logoutTapped:
|
||||
// 显示登出确认弹窗
|
||||
state.showLogoutConfirmation = true
|
||||
return .none
|
||||
|
||||
case .logoutConfirmed:
|
||||
// 清理所有认证信息,并向上层发送登出事件
|
||||
return .run { send in
|
||||
await UserInfoManager.clearAllAuthenticationData()
|
||||
@@ -162,7 +176,7 @@ struct AppSettingFeature {
|
||||
return .none
|
||||
|
||||
case .aboutUsTapped:
|
||||
// 预留关于我们逻辑
|
||||
state.showAboutUs = true
|
||||
return .none
|
||||
|
||||
case .deactivateAccountTapped:
|
||||
@@ -277,6 +291,14 @@ struct AppSettingFeature {
|
||||
state.selectedImageSource = source
|
||||
// 这里可以传递选择的源到 ImagePickerWithPreviewView
|
||||
return .none
|
||||
|
||||
case .showLogoutConfirmation(let show):
|
||||
state.showLogoutConfirmation = show
|
||||
return .none
|
||||
|
||||
case .showAboutUs(let show):
|
||||
state.showAboutUs = show
|
||||
return .none
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -55,12 +55,12 @@ struct EMailLoginFeature {
|
||||
|
||||
case .getVerificationCodeTapped:
|
||||
guard !state.email.isEmpty else {
|
||||
state.errorMessage = NSLocalizedString("email_login.email_required", comment: "")
|
||||
state.errorMessage = LocalizedStringSync("email_login.email_required", comment: "")
|
||||
return .none
|
||||
}
|
||||
|
||||
guard ValidationHelper.isValidEmail(state.email) else {
|
||||
state.errorMessage = NSLocalizedString("email_login.invalid_email", comment: "")
|
||||
state.errorMessage = LocalizedStringSync("email_login.invalid_email", comment: "")
|
||||
return .none
|
||||
}
|
||||
|
||||
@@ -105,12 +105,12 @@ struct EMailLoginFeature {
|
||||
|
||||
case .loginButtonTapped(let email, let verificationCode):
|
||||
guard !email.isEmpty && !verificationCode.isEmpty else {
|
||||
state.errorMessage = NSLocalizedString("email_login.fields_required", comment: "")
|
||||
state.errorMessage = LocalizedStringSync("email_login.fields_required", comment: "")
|
||||
return .none
|
||||
}
|
||||
|
||||
guard ValidationHelper.isValidEmail(email) else {
|
||||
state.errorMessage = NSLocalizedString("email_login.invalid_email", comment: "")
|
||||
state.errorMessage = LocalizedStringSync("email_login.invalid_email", comment: "")
|
||||
return .none
|
||||
}
|
||||
|
||||
|
@@ -57,12 +57,12 @@ struct RecoverPasswordFeature {
|
||||
|
||||
case .getVerificationCodeTapped:
|
||||
guard !state.email.isEmpty else {
|
||||
state.errorMessage = NSLocalizedString("recover_password.email_required", comment: "")
|
||||
state.errorMessage = LocalizedStringSync("recover_password.email_required", comment: "")
|
||||
return .none
|
||||
}
|
||||
|
||||
guard ValidationHelper.isValidEmail(state.email) else {
|
||||
state.errorMessage = NSLocalizedString("recover_password.invalid_email", comment: "")
|
||||
state.errorMessage = LocalizedStringSync("recover_password.invalid_email", comment: "")
|
||||
return .none
|
||||
}
|
||||
|
||||
@@ -101,23 +101,23 @@ struct RecoverPasswordFeature {
|
||||
if let apiError = error as? APIError {
|
||||
state.errorMessage = apiError.localizedDescription
|
||||
} else {
|
||||
state.errorMessage = NSLocalizedString("recover_password.code_send_failed", comment: "")
|
||||
state.errorMessage = LocalizedStringSync("recover_password.code_send_failed", comment: "")
|
||||
}
|
||||
return .none
|
||||
|
||||
case .resetPasswordTapped:
|
||||
guard !state.email.isEmpty && !state.verificationCode.isEmpty && !state.newPassword.isEmpty else {
|
||||
state.errorMessage = NSLocalizedString("recover_password.fields_required", comment: "")
|
||||
state.errorMessage = LocalizedStringSync("recover_password.fields_required", comment: "")
|
||||
return .none
|
||||
}
|
||||
|
||||
guard ValidationHelper.isValidEmail(state.email) else {
|
||||
state.errorMessage = NSLocalizedString("recover_password.invalid_email", comment: "")
|
||||
state.errorMessage = LocalizedStringSync("recover_password.invalid_email", comment: "")
|
||||
return .none
|
||||
}
|
||||
|
||||
guard ValidationHelper.isValidPassword(state.newPassword) else {
|
||||
state.errorMessage = NSLocalizedString("recover_password.invalid_password", comment: "")
|
||||
state.errorMessage = LocalizedStringSync("recover_password.invalid_password", comment: "")
|
||||
return .none
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ struct RecoverPasswordFeature {
|
||||
if let apiError = error as? APIError {
|
||||
state.errorMessage = apiError.localizedDescription
|
||||
} else {
|
||||
state.errorMessage = NSLocalizedString("recover_password.reset_failed", comment: "")
|
||||
state.errorMessage = LocalizedStringSync("recover_password.reset_failed", comment: "")
|
||||
}
|
||||
return .none
|
||||
|
||||
@@ -199,7 +199,7 @@ struct ResetPasswordResponse: Codable, Equatable {
|
||||
|
||||
/// 错误消息(如果有)
|
||||
var errorMessage: String {
|
||||
return message ?? NSLocalizedString("recover_password.reset_failed", comment: "")
|
||||
return message ?? LocalizedStringSync("recover_password.reset_failed", comment: "")
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -37,6 +37,9 @@
|
||||
"id_login.forgot_password" = "Forgot Password?";
|
||||
"id_login.login_button" = "Login";
|
||||
"id_login.logging_in" = "Logging in...";
|
||||
"id_login.password" = "Password";
|
||||
"id_login.login" = "Login";
|
||||
"id_login.user_id" = "User ID";
|
||||
|
||||
// MARK: - Email Login Page
|
||||
"email_login.title" = "Email Login";
|
||||
@@ -48,6 +51,9 @@
|
||||
"email_login.code_sent" = "Verification code sent";
|
||||
"email_login.login_button" = "Login";
|
||||
"email_login.logging_in" = "Logging in...";
|
||||
"email_login.email" = "Email";
|
||||
"email_login.verification_code" = "Verification Code";
|
||||
"email_login.login" = "Login";
|
||||
"placeholder.enter_email" = "Please enter email";
|
||||
"placeholder.enter_verification_code" = "Please enter verification code";
|
||||
|
||||
@@ -129,6 +135,10 @@
|
||||
"appSetting.checkUpdates" = "Check for Updates";
|
||||
"appSetting.logout" = "Log Out";
|
||||
"appSetting.aboutUs" = "About Us";
|
||||
"appSetting.aboutUs.title" = "About Us";
|
||||
"appSetting.logoutConfirmation.title" = "Confirm Logout";
|
||||
"appSetting.logoutConfirmation.confirm" = "Confirm Logout";
|
||||
"appSetting.logoutConfirmation.message" = "Are you sure you want to logout from your current account?";
|
||||
"appSetting.deactivateAccount" = "Deactivate Account";
|
||||
"appSetting.logoutAccount" = "Log out of account";
|
||||
|
||||
@@ -206,4 +216,8 @@
|
||||
"config.last_updated" = "Last Updated: %@";
|
||||
"config.click_to_load" = "Click the button below to load configuration";
|
||||
"config.use_new_tca" = "Use new TCA API component";
|
||||
"config.clear_error" = "Clear Error";
|
||||
"config.clear_error" = "Clear Error";
|
||||
"config.version" = "Version";
|
||||
"config.debug_mode" = "Debug Mode";
|
||||
"config.api_timeout" = "API Timeout";
|
||||
"config.max_retries" = "Max Retries";
|
@@ -38,6 +38,9 @@
|
||||
"id_login.forgot_password" = "忘记密码?";
|
||||
"id_login.login_button" = "登录";
|
||||
"id_login.logging_in" = "登录中...";
|
||||
"id_login.password" = "密码";
|
||||
"id_login.login" = "登录";
|
||||
"id_login.user_id" = "用户ID";
|
||||
|
||||
// MARK: - 邮箱登录页面
|
||||
"email_login.title" = "邮箱登录";
|
||||
@@ -49,6 +52,9 @@
|
||||
"email_login.code_sent" = "验证码已发送";
|
||||
"email_login.login_button" = "登录";
|
||||
"email_login.logging_in" = "登录中...";
|
||||
"email_login.email" = "邮箱";
|
||||
"email_login.verification_code" = "验证码";
|
||||
"email_login.login" = "登录";
|
||||
"placeholder.enter_email" = "请输入邮箱";
|
||||
"placeholder.enter_verification_code" = "请输入验证码";
|
||||
|
||||
@@ -125,6 +131,10 @@
|
||||
"appSetting.checkUpdates" = "检查更新";
|
||||
"appSetting.logout" = "退出登录";
|
||||
"appSetting.aboutUs" = "关于我们";
|
||||
"appSetting.aboutUs.title" = "关于我们";
|
||||
"appSetting.logoutConfirmation.title" = "确认退出";
|
||||
"appSetting.logoutConfirmation.confirm" = "确认退出";
|
||||
"appSetting.logoutConfirmation.message" = "确定要退出当前账户吗?";
|
||||
"appSetting.deactivateAccount" = "注销帐号";
|
||||
"appSetting.logoutAccount" = "退出账户";
|
||||
|
||||
@@ -203,3 +213,7 @@
|
||||
"config.click_to_load" = "点击下方按钮加载配置";
|
||||
"config.use_new_tca" = "使用新的 TCA API 组件";
|
||||
"config.clear_error" = "清除错误";
|
||||
"config.version" = "版本";
|
||||
"config.debug_mode" = "调试模式";
|
||||
"config.api_timeout" = "API 超时";
|
||||
"config.max_retries" = "最大重试次数";
|
||||
|
@@ -46,6 +46,8 @@ class LocalizationManager: ObservableObject {
|
||||
} catch {
|
||||
debugErrorSync("❌ 保存语言设置失败: \(error)")
|
||||
}
|
||||
// 同时更新 UserDefaults 供同步版本使用
|
||||
UserDefaults.standard.set(currentLanguage.rawValue, forKey: "AppLanguage")
|
||||
// 通知视图更新
|
||||
objectWillChange.send()
|
||||
}
|
||||
@@ -67,6 +69,9 @@ class LocalizationManager: ObservableObject {
|
||||
// 如果没有保存过语言设置,使用系统首选语言
|
||||
self.currentLanguage = Self.getSystemPreferredLanguage()
|
||||
}
|
||||
|
||||
// 确保 UserDefaults 也同步了当前语言设置
|
||||
UserDefaults.standard.set(self.currentLanguage.rawValue, forKey: "AppLanguage")
|
||||
}
|
||||
|
||||
// MARK: - 本地化方法
|
||||
@@ -150,6 +155,26 @@ func LocalizedString(_ key: String, comment: String = "") -> String {
|
||||
return LocalizationManager.shared.localizedString(key)
|
||||
}
|
||||
|
||||
/// 同步版本的本地化字符串获取方法
|
||||
/// 用于 TCA reducer 等同步上下文
|
||||
/// - Parameters:
|
||||
/// - key: 本地化 key
|
||||
/// - comment: 注释(保持与 NSLocalizedString 兼容)
|
||||
/// - Returns: 本地化后的字符串
|
||||
func LocalizedStringSync(_ key: String, comment: String = "") -> String {
|
||||
// 直接从 UserDefaults 读取当前语言设置(避免 @MainActor 隔离问题)
|
||||
let currentLanguage = UserDefaults.standard.string(forKey: "AppLanguage") ?? "en"
|
||||
|
||||
// 根据语言设置获取本地化字符串
|
||||
guard let path = Bundle.main.path(forResource: currentLanguage, ofType: "lproj"),
|
||||
let bundle = Bundle(path: path) else {
|
||||
// 如果找不到对应语言包,返回 key 本身
|
||||
return NSLocalizedString(key, comment: comment)
|
||||
}
|
||||
|
||||
return NSLocalizedString(key, bundle: bundle, comment: comment)
|
||||
}
|
||||
|
||||
// MARK: - LocalizedTextModifier
|
||||
/// 本地化文本修饰符
|
||||
struct LocalizedTextModifier: ViewModifier {
|
||||
|
@@ -29,7 +29,7 @@ struct AppSettingView: View {
|
||||
@ViewBuilder
|
||||
private func mainView() -> some View {
|
||||
WithPerceptionTracking {
|
||||
GeometryReader { geometry in
|
||||
let baseView = GeometryReader { geometry in
|
||||
ZStack {
|
||||
// 背景图片
|
||||
Image("bg")
|
||||
@@ -93,68 +93,143 @@ struct AppSettingView: View {
|
||||
}
|
||||
}
|
||||
.navigationBarHidden(true)
|
||||
// 图片源选择 ActionSheet
|
||||
.confirmationDialog(
|
||||
"请选择图片来源",
|
||||
isPresented: Binding(
|
||||
get: { store.showImageSourceActionSheet },
|
||||
set: { store.send(.setShowImageSourceActionSheet($0)) }
|
||||
),
|
||||
titleVisibility: .visible
|
||||
) {
|
||||
Button(LocalizedString("app_settings.take_photo", comment: "拍照")) {
|
||||
store.send(.selectImageSource(AppImageSource.camera))
|
||||
// 直接触发相机
|
||||
pickerStore.send(.inner(.selectSource(.camera)))
|
||||
|
||||
let viewWithActionSheet = baseView
|
||||
.confirmationDialog(
|
||||
"请选择图片来源",
|
||||
isPresented: Binding(
|
||||
get: { store.showImageSourceActionSheet },
|
||||
set: { store.send(.setShowImageSourceActionSheet($0)) }
|
||||
),
|
||||
titleVisibility: .visible
|
||||
) {
|
||||
Button(LocalizedString("app_settings.take_photo", comment: "拍照")) {
|
||||
store.send(.selectImageSource(AppImageSource.camera))
|
||||
// 直接触发相机
|
||||
pickerStore.send(.inner(.selectSource(.camera)))
|
||||
}
|
||||
Button(LocalizedString("app_settings.select_from_album", comment: "从相册选择")) {
|
||||
store.send(.selectImageSource(AppImageSource.photoLibrary))
|
||||
// 直接触发相册
|
||||
pickerStore.send(.inner(.selectSource(.photoLibrary)))
|
||||
}
|
||||
Button(LocalizedString("common.cancel", comment: "取消"), role: .cancel) { }
|
||||
}
|
||||
Button(LocalizedString("app_settings.select_from_album", comment: "从相册选择")) {
|
||||
store.send(.selectImageSource(AppImageSource.photoLibrary))
|
||||
// 直接触发相册
|
||||
pickerStore.send(.inner(.selectSource(.photoLibrary)))
|
||||
}
|
||||
Button(LocalizedString("common.cancel", comment: "取消"), role: .cancel) { }
|
||||
}
|
||||
// 头像选择器
|
||||
.sheet(isPresented: Binding(
|
||||
get: { store.showImagePicker },
|
||||
set: { store.send(.setShowImagePicker($0)) }
|
||||
)) {
|
||||
ImagePickerWithPreviewView(
|
||||
store: pickerStore,
|
||||
onUpload: { images in
|
||||
if let firstImage = images.first,
|
||||
let imageData = firstImage.jpegData(compressionQuality: 0.8) {
|
||||
store.send(.avatarSelected(imageData))
|
||||
|
||||
let viewWithImagePicker = viewWithActionSheet
|
||||
.sheet(isPresented: Binding(
|
||||
get: { store.showImagePicker },
|
||||
set: { store.send(.setShowImagePicker($0)) }
|
||||
)) {
|
||||
ImagePickerWithPreviewView(
|
||||
store: pickerStore,
|
||||
onUpload: { images in
|
||||
if let firstImage = images.first,
|
||||
let imageData = firstImage.jpegData(compressionQuality: 0.8) {
|
||||
store.send(.avatarSelected(imageData))
|
||||
}
|
||||
store.send(.setShowImagePicker(false))
|
||||
},
|
||||
onCancel: {
|
||||
store.send(.setShowImagePicker(false))
|
||||
}
|
||||
store.send(.setShowImagePicker(false))
|
||||
},
|
||||
onCancel: {
|
||||
store.send(.setShowImagePicker(false))
|
||||
)
|
||||
}
|
||||
|
||||
let viewWithAlert = viewWithImagePicker
|
||||
.alert(LocalizedString("appSetting.nickname", comment: "编辑昵称"), isPresented: Binding(
|
||||
get: { store.isEditingNickname },
|
||||
set: { store.send(.nicknameEditAlert($0)) }
|
||||
)) {
|
||||
TextField(LocalizedString("appSetting.nickname", comment: "请输入昵称"), text: Binding(
|
||||
get: { store.nicknameInput },
|
||||
set: { store.send(.nicknameInputChanged($0)) }
|
||||
))
|
||||
Button(LocalizedString("common.cancel", comment: "取消")) {
|
||||
store.send(.nicknameEditAlert(false))
|
||||
}
|
||||
Button(LocalizedString("common.confirm", comment: "确认")) {
|
||||
let trimmed = store.nicknameInput.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
if !trimmed.isEmpty {
|
||||
store.send(.nicknameEditConfirmed(trimmed))
|
||||
}
|
||||
store.send(.nicknameEditAlert(false))
|
||||
}
|
||||
} message: {
|
||||
Text(LocalizedString("appSetting.nickname", comment: "请输入新的昵称"))
|
||||
}
|
||||
|
||||
let viewWithPrivacyPolicy = viewWithAlert
|
||||
.webView(
|
||||
isPresented: Binding(
|
||||
get: { store.showPrivacyPolicy },
|
||||
set: { isPresented in
|
||||
if !isPresented {
|
||||
store.send(.privacyPolicyDismissed)
|
||||
}
|
||||
}
|
||||
),
|
||||
url: APIConfiguration.webURL(for: .privacyPolicy)
|
||||
)
|
||||
}
|
||||
// 昵称编辑弹窗
|
||||
.alert(LocalizedString("appSetting.nickname", comment: "编辑昵称"), isPresented: Binding(
|
||||
get: { store.isEditingNickname },
|
||||
set: { store.send(.nicknameEditAlert($0)) }
|
||||
)) {
|
||||
TextField(LocalizedString("appSetting.nickname", comment: "请输入昵称"), text: Binding(
|
||||
get: { store.nicknameInput },
|
||||
set: { store.send(.nicknameInputChanged($0)) }
|
||||
))
|
||||
Button(LocalizedString("common.cancel", comment: "取消")) {
|
||||
store.send(.nicknameEditAlert(false))
|
||||
}
|
||||
Button(LocalizedString("common.confirm", comment: "确认")) {
|
||||
let trimmed = store.nicknameInput.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
if !trimmed.isEmpty {
|
||||
store.send(.nicknameEditConfirmed(trimmed))
|
||||
|
||||
let viewWithUserAgreement = viewWithPrivacyPolicy
|
||||
.webView(
|
||||
isPresented: Binding(
|
||||
get: { store.showUserAgreement },
|
||||
set: { isPresented in
|
||||
if !isPresented {
|
||||
store.send(.userAgreementDismissed)
|
||||
}
|
||||
}
|
||||
),
|
||||
url: APIConfiguration.webURL(for: .userAgreement)
|
||||
)
|
||||
|
||||
let viewWithDeactivateAccount = viewWithUserAgreement
|
||||
.webView(
|
||||
isPresented: Binding(
|
||||
get: { store.showDeactivateAccount },
|
||||
set: { isPresented in
|
||||
if !isPresented {
|
||||
store.send(.deactivateAccountDismissed)
|
||||
}
|
||||
}
|
||||
),
|
||||
url: APIConfiguration.webURL(for: .deactivateAccount)
|
||||
)
|
||||
|
||||
viewWithDeactivateAccount
|
||||
// 登出确认弹窗
|
||||
.alert(LocalizedString("appSetting.logoutConfirmation.title", comment: "确认退出"), isPresented: Binding(
|
||||
get: { store.showLogoutConfirmation },
|
||||
set: { store.send(.showLogoutConfirmation($0)) }
|
||||
)) {
|
||||
Button(LocalizedString("common.cancel", comment: "取消"), role: .cancel) {
|
||||
store.send(.showLogoutConfirmation(false))
|
||||
}
|
||||
Button(LocalizedString("appSetting.logoutConfirmation.confirm", comment: "确认退出"), role: .destructive) {
|
||||
store.send(.logoutConfirmed)
|
||||
store.send(.showLogoutConfirmation(false))
|
||||
}
|
||||
} message: {
|
||||
Text(LocalizedString("appSetting.logoutConfirmation.message", comment: "确定要退出当前账户吗?"))
|
||||
}
|
||||
// 关于我们弹窗
|
||||
.alert(LocalizedString("appSetting.aboutUs.title", comment: "关于我们"), isPresented: Binding(
|
||||
get: { store.showAboutUs },
|
||||
set: { store.send(.showAboutUs($0)) }
|
||||
)) {
|
||||
Button(LocalizedString("common.ok", comment: "确定")) {
|
||||
store.send(.showAboutUs(false))
|
||||
}
|
||||
} message: {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text(LocalizedString("feedList.title", comment: "享受您的生活时光"))
|
||||
.font(.headline)
|
||||
Text(LocalizedString("feedList.slogan", comment: "疾病如同残酷的统治者,\n而时间是我们最宝贵的财富。\n我们活着的每一刻,都是对不可避免命运的胜利。"))
|
||||
.font(.body)
|
||||
}
|
||||
store.send(.nicknameEditAlert(false))
|
||||
}
|
||||
} message: {
|
||||
Text(LocalizedString("appSetting.nickname", comment: "请输入新的昵称"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,10 +405,13 @@ struct SettingRow: View {
|
||||
.foregroundColor(.white)
|
||||
.frame(width: 24)
|
||||
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
HStack {
|
||||
Text(title)
|
||||
.font(.system(size: 16))
|
||||
.foregroundColor(.white)
|
||||
.multilineTextAlignment(.leading)
|
||||
|
||||
Spacer()
|
||||
|
||||
if !subtitle.isEmpty {
|
||||
Text(subtitle)
|
||||
|
@@ -37,7 +37,7 @@ struct CreateFeedView: View {
|
||||
isTextEditorFocused = false // 点击空白处收起键盘
|
||||
}
|
||||
}
|
||||
.navigationTitle(NSLocalizedString("createFeed.title", comment: "Image & Text Publish"))
|
||||
.navigationTitle(LocalizedString("createFeed.title", comment: "Image & Text Publish"))
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbarBackground(.hidden, for: .navigationBar)
|
||||
.navigationBarBackButtonHidden(true)
|
||||
@@ -53,7 +53,7 @@ struct CreateFeedView: View {
|
||||
}
|
||||
|
||||
ToolbarItem(placement: .principal) {
|
||||
Text(NSLocalizedString("createFeed.title", comment: "Image & Text Publish"))
|
||||
Text(LocalizedString("createFeed.title", comment: "Image & Text Publish"))
|
||||
.font(.system(size: 18, weight: .medium))
|
||||
.foregroundColor(.white)
|
||||
}
|
||||
@@ -120,9 +120,9 @@ struct CreateFeedView: View {
|
||||
if store.isUploadingImages {
|
||||
return "上传中..."
|
||||
} else if store.isLoading {
|
||||
return NSLocalizedString("createFeed.publishing", comment: "Publishing...")
|
||||
return LocalizedString("createFeed.publishing", comment: "Publishing...")
|
||||
} else {
|
||||
return NSLocalizedString("createFeed.publish", comment: "Publish")
|
||||
return LocalizedString("createFeed.publish", comment: "Publish")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ struct ContentInputSection: View {
|
||||
RoundedRectangle(cornerRadius: 8)
|
||||
.fill(Color.init(hex: 0x1C143A))
|
||||
if store.content.isEmpty {
|
||||
Text(NSLocalizedString("createFeed.enterContent", comment: "Enter Content"))
|
||||
Text(LocalizedString("createFeed.enterContent", comment: "Enter Content"))
|
||||
.foregroundColor(.white.opacity(0.5))
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.vertical, 12)
|
||||
@@ -322,9 +322,9 @@ struct PublishButtonSection: View {
|
||||
if store.isUploadingImages {
|
||||
return "上传图片中..."
|
||||
} else if store.isLoading {
|
||||
return NSLocalizedString("createFeed.publishing", comment: "Publishing...")
|
||||
return LocalizedString("createFeed.publishing", comment: "Publishing...")
|
||||
} else {
|
||||
return NSLocalizedString("createFeed.publish", comment: "Publish")
|
||||
return LocalizedString("createFeed.publish", comment: "Publish")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -22,7 +22,7 @@ struct DetailView: View {
|
||||
// 自定义导航栏
|
||||
WithPerceptionTracking {
|
||||
CustomNavigationBar(
|
||||
title: NSLocalizedString("detail.title", comment: "Detail page title"),
|
||||
title: LocalizedString("detail.title", comment: "Detail page title"),
|
||||
showDeleteButton: isCurrentUserDynamic,
|
||||
isDeleteLoading: store.isDeleteLoading,
|
||||
onBack: {
|
||||
|
@@ -162,7 +162,7 @@ struct LoginView: View {
|
||||
Button(action: {
|
||||
showLanguageSettings = true
|
||||
}) {
|
||||
Text(LocalizedString("login.language", comment: ""))
|
||||
Text(LocalizedString("setting.language", comment: ""))
|
||||
.font(.system(size: 14))
|
||||
.foregroundColor(.white.opacity(0.8))
|
||||
}
|
||||
@@ -170,7 +170,7 @@ struct LoginView: View {
|
||||
Button(action: {
|
||||
showUserAgreement = true
|
||||
}) {
|
||||
Text(LocalizedString("login.user_agreement", comment: ""))
|
||||
Text(LocalizedString("login.agreement", comment: ""))
|
||||
.font(.system(size: 14))
|
||||
.foregroundColor(.white.opacity(0.8))
|
||||
}
|
||||
@@ -178,7 +178,7 @@ struct LoginView: View {
|
||||
Button(action: {
|
||||
showPrivacyPolicy = true
|
||||
}) {
|
||||
Text(LocalizedString("login.privacy_policy", comment: ""))
|
||||
Text(LocalizedString("login.policy", comment: ""))
|
||||
.font(.system(size: 14))
|
||||
.foregroundColor(.white.opacity(0.8))
|
||||
}
|
||||
|
@@ -58,7 +58,7 @@ struct RecoverPasswordView: View {
|
||||
} else if countdown > 0 {
|
||||
return "\(countdown)s"
|
||||
} else {
|
||||
return NSLocalizedString("recover_password.get_code", comment: "")
|
||||
return LocalizedString("recover_password.get_code", comment: "")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ struct RecoverPasswordView: View {
|
||||
.frame(height: 60)
|
||||
|
||||
// 标题
|
||||
Text(NSLocalizedString("recover_password.title", comment: ""))
|
||||
Text(LocalizedString("recover_password.title", comment: ""))
|
||||
.font(.system(size: 28, weight: .medium))
|
||||
.foregroundColor(.white)
|
||||
.padding(.bottom, 80)
|
||||
@@ -165,7 +165,7 @@ struct RecoverPasswordView: View {
|
||||
|
||||
TextField("", text: $email)
|
||||
.placeholder(when: email.isEmpty) {
|
||||
Text(NSLocalizedString("recover_password.placeholder_email", comment: ""))
|
||||
Text(LocalizedString("recover_password.placeholder_email", comment: ""))
|
||||
.foregroundColor(.white.opacity(0.6))
|
||||
}
|
||||
.foregroundColor(.white)
|
||||
@@ -189,7 +189,7 @@ struct RecoverPasswordView: View {
|
||||
HStack {
|
||||
TextField("", text: $verificationCode)
|
||||
.placeholder(when: verificationCode.isEmpty) {
|
||||
Text(NSLocalizedString("recover_password.placeholder_verification_code", comment: ""))
|
||||
Text(LocalizedString("recover_password.placeholder_verification_code", comment: ""))
|
||||
.foregroundColor(.white.opacity(0.6))
|
||||
}
|
||||
.foregroundColor(.white)
|
||||
@@ -238,7 +238,7 @@ struct RecoverPasswordView: View {
|
||||
if isNewPasswordVisible {
|
||||
TextField("", text: $newPassword)
|
||||
.placeholder(when: newPassword.isEmpty) {
|
||||
Text(NSLocalizedString("recover_password.placeholder_new_password", comment: ""))
|
||||
Text(LocalizedString("recover_password.placeholder_new_password", comment: ""))
|
||||
.foregroundColor(.white.opacity(0.6))
|
||||
}
|
||||
.foregroundColor(.white)
|
||||
@@ -246,7 +246,7 @@ struct RecoverPasswordView: View {
|
||||
} else {
|
||||
SecureField("", text: $newPassword)
|
||||
.placeholder(when: newPassword.isEmpty) {
|
||||
Text(NSLocalizedString("recover_password.placeholder_new_password", comment: ""))
|
||||
Text(LocalizedString("recover_password.placeholder_new_password", comment: ""))
|
||||
.foregroundColor(.white.opacity(0.6))
|
||||
}
|
||||
.foregroundColor(.white)
|
||||
@@ -287,7 +287,7 @@ struct RecoverPasswordView: View {
|
||||
.progressViewStyle(CircularProgressViewStyle(tint: .white))
|
||||
.scaleEffect(0.8)
|
||||
}
|
||||
Text(store.isResetLoading ? NSLocalizedString("recover_password.resetting", comment: "") : NSLocalizedString("recover_password.confirm_button", comment: ""))
|
||||
Text(store.isResetLoading ? LocalizedString("recover_password.resetting", comment: "") : LocalizedString("recover_password.confirm_button", comment: ""))
|
||||
.font(.system(size: 18, weight: .semibold))
|
||||
.foregroundColor(.white)
|
||||
}
|
||||
|
@@ -70,7 +70,7 @@ struct SplashView: View {
|
||||
.frame(width: 100, height: 100)
|
||||
|
||||
// 应用标题 - 白色,40pt字体
|
||||
Text(NSLocalizedString("splash.title", comment: "E-Parti"))
|
||||
Text(LocalizedString("splash.title", comment: "E-Parti"))
|
||||
.font(.system(size: 40, weight: .regular))
|
||||
.foregroundColor(.white)
|
||||
|
||||
|
Reference in New Issue
Block a user