本次提交包含多项迭代优化和问题修复: 1. 新增缩略图图片组件、数字格式化工具类,补充多语言翻译类型与本地化支持 2. 优化底部导航栏主题色统一使用动态accent色值 3. 修复多处图表动画、路由跳转、API请求相关问题 4. 简化服务器公告文案,调整默认分屏状态为关闭 5. 新增安卓/iOS桌面快捷方式配置 6. 重构多处状态管理类使用SafeNotifierInit统一异常保护 7. 替换硬编码蓝色为主题色,更新版本号获取方式为动态读取 8. 优化缓存预加载逻辑,移除无用代码 9. 调整默认设置项,优化用户体验细节
313 lines
8.0 KiB
Dart
313 lines
8.0 KiB
Dart
/// ============================================================
|
||
/// 闲言APP — 动态翻译函数
|
||
/// 创建时间: 2026-05-29
|
||
/// 更新时间: 2026-05-31
|
||
/// 作用: 带参数的动态翻译函数(复数、性别、插值等),支持CLDR标准复数规则
|
||
/// 上次更新: 新增plural/gender/format通用方法,补全_locale映射
|
||
/// ============================================================
|
||
|
||
import 'package:intl/intl.dart';
|
||
|
||
class TFunc {
|
||
TFunc(this._langId);
|
||
|
||
final String _langId;
|
||
|
||
// ============================================================
|
||
// 通用复数选择 — 基于CLDR标准
|
||
// ============================================================
|
||
|
||
/// 通用复数选择
|
||
/// [count] 数量
|
||
/// [zero] 0个时的文本(可选,阿拉伯语等需要)
|
||
/// [one] 1个时的文本
|
||
/// [two] 2个时的文本(可选,阿拉伯语/俄语等需要)
|
||
/// [few] 少数时的文本(可选,阿拉伯语/俄语等需要)
|
||
/// [many] 多数时的文本(可选,阿拉伯语/俄语等需要)
|
||
/// [other] 其他数量时的文本(必填)
|
||
///
|
||
/// 用法:
|
||
/// ```dart
|
||
/// tFunc.plural(count, one: '1 tool', other: '$count tools')
|
||
/// tFunc.plural(count, zero: '无条目', one: '$count条', other: '$count条')
|
||
/// ```
|
||
String plural(
|
||
int count, {
|
||
String? zero,
|
||
String? one,
|
||
String? two,
|
||
String? few,
|
||
String? many,
|
||
required String other,
|
||
}) {
|
||
return Intl.plural(
|
||
count,
|
||
zero: zero,
|
||
one: one,
|
||
two: two,
|
||
few: few,
|
||
many: many,
|
||
other: other,
|
||
locale: _locale,
|
||
);
|
||
}
|
||
|
||
// ============================================================
|
||
// 性别选择
|
||
// ============================================================
|
||
|
||
/// 性别选择
|
||
/// [genderValue] 性别: 'male', 'female', 'other'
|
||
/// [male] 男性文本
|
||
/// [female] 女性文本
|
||
/// [other] 其他性别文本(必填,作为默认值)
|
||
///
|
||
/// 用法:
|
||
/// ```dart
|
||
/// tFunc.gender('male', male: '他', female: '她', other: 'TA')
|
||
/// ```
|
||
String gender(
|
||
String genderValue, {
|
||
String? male,
|
||
String? female,
|
||
required String other,
|
||
}) {
|
||
switch (genderValue) {
|
||
case 'male':
|
||
return male ?? other;
|
||
case 'female':
|
||
return female ?? other;
|
||
default:
|
||
return other;
|
||
}
|
||
}
|
||
|
||
// ============================================================
|
||
// 模板插值
|
||
// ============================================================
|
||
|
||
/// 统一插值函数,将模板中的 {0}, {1}, {key} 替换为对应值
|
||
/// 用法: tFunc.interpolate(t.home.readLaterCountFormat, {'0': '$_total'})
|
||
/// 或: tFunc.interpolate(t.home.searchQuery, {'0': query})
|
||
String interpolate(String template, Map<String, String> args) {
|
||
var result = template;
|
||
args.forEach((key, value) {
|
||
result = result.replaceAll('{$key}', value);
|
||
});
|
||
return result;
|
||
}
|
||
|
||
/// format 是 interpolate 的别名,语义更清晰
|
||
/// 用法: tFunc.format(t.discover.toolRemoved, {'0': tool.name})
|
||
String format(String template, Map<String, String> args) {
|
||
return interpolate(template, args);
|
||
}
|
||
|
||
// ============================================================
|
||
// 特定场景复数方法
|
||
// ============================================================
|
||
|
||
/// 条目数量(复数形式)
|
||
String entriesCount(int count) {
|
||
switch (_langId) {
|
||
case 'zh_CN':
|
||
case 'zh_TW':
|
||
return '$count 条';
|
||
case 'ja':
|
||
return '$count件';
|
||
case 'en':
|
||
return Intl.plural(
|
||
count,
|
||
one: '$count entry',
|
||
other: '$count entries',
|
||
locale: _locale,
|
||
);
|
||
case 'es':
|
||
return Intl.plural(
|
||
count,
|
||
one: '$count entrada',
|
||
other: '$count entradas',
|
||
locale: _locale,
|
||
);
|
||
case 'ar':
|
||
return Intl.plural(
|
||
count,
|
||
zero: '$count إدخال',
|
||
one: '$count إدخال',
|
||
two: '$count إدخالين',
|
||
few: '$count إدخالات',
|
||
many: '$count إدخالاً',
|
||
other: '$count إدخالات',
|
||
locale: _locale,
|
||
);
|
||
case 'bn':
|
||
return Intl.plural(
|
||
count,
|
||
one: '$countটি',
|
||
other: '$countটি',
|
||
locale: _locale,
|
||
);
|
||
case 'ru':
|
||
return Intl.plural(
|
||
count,
|
||
one: '$count запись',
|
||
few: '$count записи',
|
||
many: '$count записей',
|
||
other: '$count записей',
|
||
locale: _locale,
|
||
);
|
||
default:
|
||
return '$count';
|
||
}
|
||
}
|
||
|
||
/// 问候语(插值)
|
||
String greeting(String name) {
|
||
switch (_langId) {
|
||
case 'zh_CN':
|
||
case 'zh_TW':
|
||
return '你好,$name';
|
||
case 'ja':
|
||
return 'こんにちは、$name';
|
||
case 'en':
|
||
return 'Hello, $name';
|
||
case 'es':
|
||
return 'Hola, $name';
|
||
case 'ar':
|
||
return 'مرحباً، $name';
|
||
case 'bn':
|
||
return 'হ্যালো, $name';
|
||
case 'ru':
|
||
return 'Привет, $name';
|
||
case 'fr':
|
||
return 'Bonjour, $name';
|
||
case 'pt':
|
||
return 'Olá, $name';
|
||
case 'hi':
|
||
return 'नमस्ते, $name';
|
||
default:
|
||
return name;
|
||
}
|
||
}
|
||
|
||
/// 已选数量
|
||
String itemsSelected(int count) {
|
||
switch (_langId) {
|
||
case 'zh_CN':
|
||
case 'zh_TW':
|
||
return '已选$count项';
|
||
case 'ja':
|
||
return '$count件選択済み';
|
||
case 'en':
|
||
return Intl.plural(
|
||
count,
|
||
one: '$count selected',
|
||
other: '$count selected',
|
||
locale: _locale,
|
||
);
|
||
case 'es':
|
||
return '$count seleccionados';
|
||
case 'ar':
|
||
return '$count محدد';
|
||
case 'bn':
|
||
return '$countটি নির্বাচিত';
|
||
default:
|
||
return '$count';
|
||
}
|
||
}
|
||
|
||
/// 项目数量(复数形式)
|
||
String pluralItems(int count) {
|
||
switch (_langId) {
|
||
case 'zh_CN':
|
||
case 'zh_TW':
|
||
return '$count 个项目';
|
||
case 'ja':
|
||
return '$countアイテム';
|
||
case 'en':
|
||
return Intl.plural(
|
||
count,
|
||
one: '1 item',
|
||
other: '$count items',
|
||
locale: _locale,
|
||
);
|
||
case 'es':
|
||
return Intl.plural(
|
||
count,
|
||
one: '1 artículo',
|
||
other: '$count artículos',
|
||
locale: _locale,
|
||
);
|
||
case 'ar':
|
||
return Intl.plural(
|
||
count,
|
||
zero: '$count عنصر',
|
||
one: '$count عنصر',
|
||
two: '$count عنصران',
|
||
few: '$count عناصر',
|
||
many: '$count عنصراً',
|
||
other: '$count عنصر',
|
||
locale: _locale,
|
||
);
|
||
case 'bn':
|
||
return Intl.plural(
|
||
count,
|
||
one: '1টি আইটেম',
|
||
other: '$countটি আইটেম',
|
||
locale: _locale,
|
||
);
|
||
case 'ru':
|
||
return Intl.plural(
|
||
count,
|
||
one: '$count элемент',
|
||
few: '$count элемента',
|
||
many: '$count элементов',
|
||
other: '$count элементов',
|
||
locale: _locale,
|
||
);
|
||
default:
|
||
return '$count';
|
||
}
|
||
}
|
||
|
||
// ============================================================
|
||
// 内部工具
|
||
// ============================================================
|
||
|
||
/// 将语言ID转换为intl Locale格式
|
||
String get _locale {
|
||
switch (_langId) {
|
||
case 'zh_CN':
|
||
return 'zh';
|
||
case 'zh_TW':
|
||
return 'zh_TW';
|
||
case 'en':
|
||
return 'en';
|
||
case 'ja':
|
||
return 'ja';
|
||
case 'es':
|
||
return 'es';
|
||
case 'ar':
|
||
return 'ar';
|
||
case 'bn':
|
||
return 'bn';
|
||
case 'hi':
|
||
return 'hi';
|
||
case 'pt':
|
||
return 'pt';
|
||
case 'ru':
|
||
return 'ru';
|
||
case 'fr':
|
||
return 'fr';
|
||
case 'ko':
|
||
return 'ko';
|
||
case 'de':
|
||
return 'de';
|
||
case 'it':
|
||
return 'it';
|
||
default:
|
||
return 'zh';
|
||
}
|
||
}
|
||
}
|