Files
photo-live/apps/mobile/lib/l10n/app_localizations.dart
T
浅念 8be21b856b feat(mobile): login, password change and logout screens
P3 Task 3 移动端(对接 Task 2 api client + 本任务新增的后端契约):

- 登录页实装:账号/密码表单(空值客户端校验)→ api.login(会话自动
  持久化)→ pushReplacement /home;错误码本地化(AUTH_INVALID_
  CREDENTIALS / AUTH_RATE_LIMITED(含稍后再试文案)/ 网络 / 校验);
  提交加载态防重复提交。
- 修改密码页(设置页入口):当前/新/确认三字段,客户端校验(≥8 位、
  两次一致)→ api.changePassword → toast + pop;成功后本地会话不变
  (服务端保留当前会话);旧密码错误(401 AUTH_INVALID_CREDENTIALS)
  显示「当前密码错误」且不触发 401 驱逐。
- 退出登录:设置页按钮 → api.logout 尽力而为 → 清会话 → 清栈回
  /login;App 壳 initState 注册 onUnauthorized(业务 401 → 清栈 /login),
  根 navigatorKey 接线;password-change 的 401 豁免会话驱逐(拦截器
  豁免集合与令牌附加分离)。
- l10n:新增 16 组 zh/en 文案;错误码 → 文案解析扩展
  (core/error_l10n.dart,errorCode→AppLocalizations)。
- 测试:ApiClient.changePassword 单测 ×2(Bearer+请求体;旧密码 401
  不驱逐);widget 测试 ×12(登录 5:空值/成功跳转/凭据错误/限速文案/
  加载禁用;改密 4:过短/不一致/旧密码错误文案+会话保留/成功 toast+pop
  且令牌不变;设置 2:改密入口跳转/登出清会话回登录;App 壳 1:401
  清栈回 /login)。flutter analyze 0 issue;flutter test 81/81。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-19 01:19:57 +08:00

357 lines
10 KiB
Dart
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 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:intl/intl.dart' as intl;
import 'app_localizations_en.dart';
import 'app_localizations_zh.dart';
// ignore_for_file: type=lint
/// Callers can lookup localized strings with an instance of AppLocalizations
/// returned by `AppLocalizations.of(context)`.
///
/// Applications need to include `AppLocalizations.delegate()` in their app's
/// `localizationDelegates` list, and the locales they support in the app's
/// `supportedLocales` list. For example:
///
/// ```dart
/// import 'l10n/app_localizations.dart';
///
/// return MaterialApp(
/// localizationsDelegates: AppLocalizations.localizationsDelegates,
/// supportedLocales: AppLocalizations.supportedLocales,
/// home: MyApplicationHome(),
/// );
/// ```
///
/// ## Update pubspec.yaml
///
/// Please make sure to update your pubspec.yaml to include the following
/// packages:
///
/// ```yaml
/// dependencies:
/// # Internationalization support.
/// flutter_localizations:
/// sdk: flutter
/// intl: any # Use the pinned version from flutter_localizations
///
/// # Rest of dependencies
/// ```
///
/// ## iOS Applications
///
/// iOS applications define key application metadata, including supported
/// locales, in an Info.plist file that is built into the application bundle.
/// To configure the locales supported by your app, you’ll need to edit this
/// file.
///
/// First, open your project’s ios/Runner.xcworkspace Xcode workspace file.
/// Then, in the Project Navigator, open the Info.plist file under the Runner
/// project’s Runner folder.
///
/// Next, select the Information Property List item, select Add Item from the
/// Editor menu, then select Localizations from the pop-up menu.
///
/// Select and expand the newly-created Localizations item then, for each
/// locale your application supports, add a new item and select the locale
/// you wish to add from the pop-up menu in the Value field. This list should
/// be consistent with the languages listed in the AppLocalizations.supportedLocales
/// property.
abstract class AppLocalizations {
AppLocalizations(String locale)
: localeName = intl.Intl.canonicalizedLocale(locale.toString());
final String localeName;
static AppLocalizations of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations)!;
}
static const LocalizationsDelegate<AppLocalizations> delegate =
_AppLocalizationsDelegate();
/// A list of this localizations delegate along with the default localizations
/// delegates.
///
/// Returns a list of localizations delegates containing this delegate along with
/// GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate,
/// and GlobalWidgetsLocalizations.delegate.
///
/// Additional delegates can be added by appending to this list in
/// MaterialApp. This list does not have to be used at all if a custom list
/// of delegates is preferred or required.
static const List<LocalizationsDelegate<dynamic>> localizationsDelegates =
<LocalizationsDelegate<dynamic>>[
delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
];
/// A list of this localizations delegate's supported locales.
static const List<Locale> supportedLocales = <Locale>[
Locale('en'),
Locale('zh'),
];
/// No description provided for @appName.
///
/// In zh, this message translates to:
/// **'现场影像'**
String get appName;
/// No description provided for @login.
///
/// In zh, this message translates to:
/// **'登录'**
String get login;
/// No description provided for @logout.
///
/// In zh, this message translates to:
/// **'退出登录'**
String get logout;
/// No description provided for @username.
///
/// In zh, this message translates to:
/// **'账号'**
String get username;
/// No description provided for @password.
///
/// In zh, this message translates to:
/// **'密码'**
String get password;
/// No description provided for @albums.
///
/// In zh, this message translates to:
/// **'相册'**
String get albums;
/// No description provided for @albumDetail.
///
/// In zh, this message translates to:
/// **'相册详情'**
String get albumDetail;
/// No description provided for @queue.
///
/// In zh, this message translates to:
/// **'上传队列'**
String get queue;
/// No description provided for @settings.
///
/// In zh, this message translates to:
/// **'设置'**
String get settings;
/// No description provided for @language.
///
/// In zh, this message translates to:
/// **'语言'**
String get language;
/// No description provided for @localeFollowSystem.
///
/// In zh, this message translates to:
/// **'跟随系统'**
String get localeFollowSystem;
/// No description provided for @localeChinese.
///
/// In zh, this message translates to:
/// **'中文'**
String get localeChinese;
/// No description provided for @localeEnglish.
///
/// In zh, this message translates to:
/// **'English'**
String get localeEnglish;
/// No description provided for @retry.
///
/// In zh, this message translates to:
/// **'重试'**
String get retry;
/// No description provided for @cancel.
///
/// In zh, this message translates to:
/// **'取消'**
String get cancel;
/// No description provided for @errorGeneric.
///
/// In zh, this message translates to:
/// **'出错了,请重试'**
String get errorGeneric;
/// No description provided for @ok.
///
/// In zh, this message translates to:
/// **'好的'**
String get ok;
/// No description provided for @homeTabAlbums.
///
/// In zh, this message translates to:
/// **'相册'**
String get homeTabAlbums;
/// No description provided for @homeTabQueue.
///
/// In zh, this message translates to:
/// **'队列'**
String get homeTabQueue;
/// No description provided for @homeTabSettings.
///
/// In zh, this message translates to:
/// **'设置'**
String get homeTabSettings;
/// No description provided for @loginHint.
///
/// In zh, this message translates to:
/// **'使用工作人员账号登录'**
String get loginHint;
/// No description provided for @fieldRequired.
///
/// In zh, this message translates to:
/// **'此项为必填项'**
String get fieldRequired;
/// No description provided for @passwordChangeTitle.
///
/// In zh, this message translates to:
/// **'修改密码'**
String get passwordChangeTitle;
/// No description provided for @currentPassword.
///
/// In zh, this message translates to:
/// **'当前密码'**
String get currentPassword;
/// No description provided for @newPassword.
///
/// In zh, this message translates to:
/// **'新密码'**
String get newPassword;
/// No description provided for @confirmNewPassword.
///
/// In zh, this message translates to:
/// **'确认新密码'**
String get confirmNewPassword;
/// No description provided for @passwordMinLength.
///
/// In zh, this message translates to:
/// **'新密码至少需要 8 个字符'**
String get passwordMinLength;
/// No description provided for @passwordMismatch.
///
/// In zh, this message translates to:
/// **'两次输入的新密码不一致'**
String get passwordMismatch;
/// No description provided for @passwordChangeSuccess.
///
/// In zh, this message translates to:
/// **'密码已修改'**
String get passwordChangeSuccess;
/// No description provided for @errorAuthInvalidCredentials.
///
/// In zh, this message translates to:
/// **'账号或密码错误'**
String get errorAuthInvalidCredentials;
/// No description provided for @errorOldPasswordIncorrect.
///
/// In zh, this message translates to:
/// **'当前密码错误'**
String get errorOldPasswordIncorrect;
/// No description provided for @errorAuthRateLimited.
///
/// In zh, this message translates to:
/// **'尝试次数过多,请稍后再试'**
String get errorAuthRateLimited;
/// No description provided for @errorAuthTokenExpired.
///
/// In zh, this message translates to:
/// **'会话已过期,请重新登录'**
String get errorAuthTokenExpired;
/// No description provided for @errorValidation.
///
/// In zh, this message translates to:
/// **'输入有误,请检查后重试'**
String get errorValidation;
/// No description provided for @errorNetwork.
///
/// In zh, this message translates to:
/// **'网络连接失败,请检查网络后重试'**
String get errorNetwork;
/// No description provided for @errorNetworkTimeout.
///
/// In zh, this message translates to:
/// **'网络超时,请重试'**
String get errorNetworkTimeout;
/// No description provided for @errorInternal.
///
/// In zh, this message translates to:
/// **'服务暂时不可用,请稍后重试'**
String get errorInternal;
}
class _AppLocalizationsDelegate
extends LocalizationsDelegate<AppLocalizations> {
const _AppLocalizationsDelegate();
@override
Future<AppLocalizations> load(Locale locale) {
return SynchronousFuture<AppLocalizations>(lookupAppLocalizations(locale));
}
@override
bool isSupported(Locale locale) =>
<String>['en', 'zh'].contains(locale.languageCode);
@override
bool shouldReload(_AppLocalizationsDelegate old) => false;
}
AppLocalizations lookupAppLocalizations(Locale locale) {
// Lookup logic when only language code is specified.
switch (locale.languageCode) {
case 'en':
return AppLocalizationsEn();
case 'zh':
return AppLocalizationsZh();
}
throw FlutterError(
'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely '
'an issue with the localizations generation tool. Please file an issue '
'on GitHub with a reproducible sample app and the gen-l10n configuration '
'that was used.',
);
}