为什么:a) 应用对外名称要统一成 FruitShorts(产品名,nontonki 是原型代号); b) 首发市场是印尼,界面必须有印尼语;c) 归档要求"新增 id-ID 与改名合并生成一次 l10n,别分两次"。 改名: - pubspec name: nontonki → fruitshorts(Dart 包名),description 同步;28 个文件的 package: 导入前缀替换 - Android android:label、iOS CFBundleDisplayName/CFBundleName → FruitShorts - 图标资源 assets/icon/nontonki.png → fruitshorts.png(含 pubspec 两处引用) - README 同步(补印尼语说明,顺带修掉写错的模块名 reelshort-app-api → fruitshorts-app-api) 文案: - 三份 arb 的 appName → FruitShorts、brandMark → FRUITSHORTS、shareFooter → FruitShorts(不留 demo 标记) - 新增 lib/l10n/app_id.arb:174 个值键与 en/zh 完全一致,按印尼语习惯翻译(Coin→Koin、Episode→Episode) - 一次性 flutter gen-l10n 生成 app_localizations_id.dart;id 自动进入 supportedLocales,默认 locale 未改 - 新增 test/config/l10n_id_test.dart:钉住 id 文案、supportedLocales 含 id、品牌文案无 demo 标记、占位符渲染 不动:applicationId / bundle id(lumadrama 遗留,等裁定)、目录名、业务逻辑与页面结构、语言选择页(仍只有 en/zh) 门禁:dart analyze lib test 零告警;flutter test 159 全过(基线 155 + 新增 4);残留扫描 0 命中; 三份 arb 键集一致(174/174/174);真机(iPhone iOS 26.6.1)构建安装启动成功,devicectl 列出显示名 FruitShorts
97 lines
3.6 KiB
Dart
97 lines
3.6 KiB
Dart
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:fruitshorts/core/data/models/drama.dart';
|
|
import 'package:fruitshorts/core/formatting/localized_content.dart';
|
|
import 'package:fruitshorts/l10n/app_localizations_en.dart';
|
|
import 'package:fruitshorts/l10n/app_localizations_zh.dart';
|
|
|
|
Drama _drama({required String id, String title = 'raw', String synopsis = 'raw'}) =>
|
|
Drama(
|
|
id: id,
|
|
title: title,
|
|
synopsis: synopsis,
|
|
posterUrl: '/files/poster.png',
|
|
episodes: const [],
|
|
);
|
|
|
|
void main() {
|
|
final en = AppLocalizationsEn();
|
|
final zh = AppLocalizationsZh();
|
|
|
|
test('should_map_each_seeded_drama_to_its_own_localized_copy_when_looked_up', () {
|
|
final signal = _drama(id: 'the-signal-demo');
|
|
final city = _drama(id: 'city-lights-demo');
|
|
final vengeance = _drama(id: 'vengeance-demo');
|
|
|
|
expect(localizedDramaTitle(en, signal), en.dramaSignalTitle);
|
|
expect(localizedDramaTitle(en, city), en.dramaCityTitle);
|
|
expect(localizedDramaTitle(en, vengeance), en.dramaVengeanceTitle);
|
|
|
|
expect(localizedDramaSynopsis(en, signal), en.dramaSignalSynopsis);
|
|
expect(localizedDramaSynopsis(en, city), en.dramaCitySynopsis);
|
|
expect(localizedDramaSynopsis(en, vengeance), en.dramaVengeanceSynopsis);
|
|
});
|
|
|
|
test('should_keep_two_dramas_apart_when_localized_copy_is_mapped', () {
|
|
final titles = {
|
|
localizedDramaTitle(en, _drama(id: 'the-signal-demo')),
|
|
localizedDramaTitle(en, _drama(id: 'city-lights-demo')),
|
|
localizedDramaTitle(en, _drama(id: 'vengeance-demo')),
|
|
};
|
|
final synopses = {
|
|
localizedDramaSynopsis(en, _drama(id: 'the-signal-demo')),
|
|
localizedDramaSynopsis(en, _drama(id: 'city-lights-demo')),
|
|
localizedDramaSynopsis(en, _drama(id: 'vengeance-demo')),
|
|
};
|
|
|
|
expect(titles, hasLength(3));
|
|
expect(synopses, hasLength(3));
|
|
});
|
|
|
|
test('should_translate_localized_copy_when_content_is_looked_up', () {
|
|
final signal = _drama(id: 'the-signal-demo');
|
|
|
|
expect(localizedDramaTitle(zh, signal), zh.dramaSignalTitle);
|
|
expect(localizedDramaSynopsis(zh, signal), zh.dramaSignalSynopsis);
|
|
expect(localizedDramaTitle(zh, signal), isNot(en.dramaSignalTitle));
|
|
});
|
|
|
|
test('should_keep_catalog_text_in_every_locale_when_drama_is_unknown', () {
|
|
final custom = _drama(
|
|
id: 'custom-demo',
|
|
title: 'Custom Title',
|
|
synopsis: 'Custom synopsis',
|
|
);
|
|
|
|
expect(localizedDramaTitle(en, custom), 'Custom Title');
|
|
expect(localizedDramaTitle(zh, custom), 'Custom Title');
|
|
expect(localizedDramaSynopsis(en, custom), 'Custom synopsis');
|
|
expect(localizedDramaSynopsis(zh, custom), 'Custom synopsis');
|
|
});
|
|
|
|
test('should_ignore_raw_catalog_text_when_drama_is_seeded', () {
|
|
final signal = _drama(
|
|
id: 'the-signal-demo',
|
|
title: 'stale title',
|
|
synopsis: 'stale synopsis',
|
|
);
|
|
|
|
expect(localizedDramaTitle(en, signal), isNot('stale title'));
|
|
expect(localizedDramaSynopsis(en, signal), isNot('stale synopsis'));
|
|
});
|
|
|
|
test('should_use_named_titles_when_episode_number_is_one_to_four', () {
|
|
expect(localizedEpisodeTitle(en, 1), en.episodeOneTitle);
|
|
expect(localizedEpisodeTitle(en, 2), en.episodeTwoTitle);
|
|
expect(localizedEpisodeTitle(en, 3), en.episodeThreeTitle);
|
|
expect(localizedEpisodeTitle(en, 4), en.episodeFourTitle);
|
|
});
|
|
|
|
test('should_fall_back_to_numbered_label_when_episode_number_is_later', () {
|
|
for (final number in <int>[5, 12, 100]) {
|
|
expect(localizedEpisodeTitle(en, number), en.episodeLabel(number));
|
|
expect(localizedEpisodeTitle(en, number), contains('$number'));
|
|
}
|
|
expect(localizedEpisodeTitle(zh, 12), zh.episodeLabel(12));
|
|
});
|
|
}
|