修复:Material 内置组件中文化——挂 zh-CN 三件套 delegate(M3.5-01)

用户 Linux 桌面实测反馈「日期选择器全英文」。根因是 MaterialApp 从一迭代
建起就没配 localizationsDelegates/supportedLocales/locale,pubspec 也没有
flutter_localizations;Flutter 在缺 delegate 时静默回退内置的
DefaultMaterialLocalizations(只有英文),于是业务自绘文案全中文、Material
内置组件全英文,同一弹窗里中英混排:

  Select date → 选择日期
  OK / Cancel → 确定 / 取消
  Enter Date → 输入日期
  Switch to input → 切换到输入模式
  Invalid format. / Out of range. → 格式无效。/ 超出范围。
  mm/dd/yyyy → yyyy/mm/dd(zh 顺序年在前)
  September 2026 → 2026年9月

处置:

- pubspec 加 flutter_localizations(sdk)与 intl(日期符号底座,显式直接
  依赖以锁定与 SDK 一致的版本)。
- 新增 lib/app/app_localization.dart 把 Global{Material,Cupertino,Widgets}
  三件套 delegate、supportedLocales、locale 收在一处常量:widget 测试若只
  pumpWidget(MaterialApp(home: ...)) 而不挂 delegate,测到的「中文」是假的,
  测试直接引用同一份常量,生产与测试不会各配一套而漂移。
- 单语言 zh-CN,不列 en:避免设备语言为英文时回退英文,再造混排。
- pets 域三份 widget 测试的 MaterialApp 同步挂上 delegate,
  tap(find.text('OK')) 相应改 '确定'——让测试与生产一致,而不是在英文兜底下测。

新增 test/app/app_localization_test.dart 守住这一行不被回删:断言根
MaterialApp 实际挂上三件套 + locale zh-CN,并从运行期 MaterialLocalizations
取回中文文案。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-10 17:59:21 +08:00
parent 0e87413360
commit 6038901099
8 changed files with 127 additions and 3 deletions
+49
View File
@@ -0,0 +1,49 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:patbond_flutter/app/app.dart';
import 'package:patbond_flutter/app/app_localization.dart';
import 'package:patbond_flutter/features/auth/session_manager.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../helpers/auth_test_helpers.dart';
import '../helpers/community_test_helpers.dart';
import '../helpers/pet_test_helpers.dart';
/// M3.5-01:根 [MaterialApp] 实际挂上 zh-CN 本地化。
///
/// 用户桌面实测反馈「日期选择器全英文」的根因就在这里——delegate 一行没配,
/// Material 静默回退英文兜底。本测试守住这一行不被回删。
void main() {
testWidgets('MaterialApp 挂三件套 delegate + 单语言 zh-CN', (tester) async {
SharedPreferences.setMockInitialValues({});
final session = SessionManager(store: InMemoryTokenStore())
..markAuthenticated();
await tester.pumpWidget(
App(
sessionManager: session,
authRepository: FakeAuthRepository(),
petsRepository: FakePetsRepository(),
communityRepository: FakeCommunityRepository()
..onFeed = (_, _) async => feedPage(const []),
),
);
await tester.pumpAndSettle();
final app = tester.widget<MaterialApp>(find.byType(MaterialApp));
expect(app.localizationsDelegates, appLocalizationsDelegates);
expect(app.supportedLocales, appSupportedLocales);
expect(app.locale, const Locale('zh', 'CN'));
// 运行期实际解析出的 Material 文案为中文(不是 Default* 英文兜底)。
final context = tester.element(find.byType(NavigationBar));
final l10n = MaterialLocalizations.of(context);
expect(l10n.okButtonLabel, '确定');
expect(l10n.cancelButtonLabel, '取消');
expect(l10n.datePickerHelpText, '选择日期');
expect(l10n.dateInputLabel, '输入日期');
expect(l10n.inputDateModeButtonLabel, '切换到输入模式');
expect(l10n.invalidDateFormatLabel, '格式无效。');
expect(l10n.formatMonthYear(DateTime(2026, 9, 10)), '2026年9月');
});
}