import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; /// 全局语言状态管理 /// /// userLocale = null 时跟随系统语言 /// 用户在设置页选择后,持久化到 SharedPreferences,下次启动自动恢复 class LocaleManager { static final ValueNotifier userLocale = ValueNotifier(null); static const _prefKey = 'user_locale'; static const supportedLocales = [ Locale('zh', 'CN'), Locale('zh', 'TW'), Locale('en'), Locale('ja'), ]; /// 启动时调用,从 SharedPreferences 恢复用户选择的语言 static Future init() async { final prefs = await SharedPreferences.getInstance(); final saved = prefs.getString(_prefKey); if (saved != null) { final locale = _parseLocale(saved); if (locale != null) { userLocale.value = locale; } } } /// 设置用户语言并持久化(传 null 表示恢复跟随系统) static Future setLocale(Locale? locale) async { userLocale.value = locale; final prefs = await SharedPreferences.getInstance(); if (locale == null) { await prefs.remove(_prefKey); } else { await prefs.setString(_prefKey, _serializeLocale(locale)); } } /// 根据系统 locale 解析最佳匹配 static Locale resolve(List? systemLocales, Iterable supported) { if (systemLocales == null || systemLocales.isEmpty) { return const Locale('zh', 'CN'); } final system = systemLocales.first; // 精确匹配 for (final s in supported) { if (s.languageCode == system.languageCode && s.countryCode == system.countryCode) { return s; } } // 语言码匹配 for (final s in supported) { if (s.languageCode == system.languageCode) { return s; } } // 默认中文 return const Locale('zh', 'CN'); } /// 根据语言获取默认货币 static String defaultCurrencyForLocale(Locale locale) { switch (locale.languageCode) { case 'zh': return locale.countryCode == 'TW' ? 'TWD' : 'CNY'; case 'ja': return 'JPY'; case 'en': default: return 'USD'; } } /// Locale 转显示名称 static String localeDisplayName(Locale locale) { final key = '${locale.languageCode}_${locale.countryCode ?? ''}'; switch (key) { case 'zh_CN': return '简体中文'; case 'zh_TW': return '繁體中文'; case 'en_': case 'en_US': return 'English'; case 'ja_': case 'ja_JP': return '日本語'; default: return locale.toString(); } } static String _serializeLocale(Locale locale) { if (locale.countryCode != null && locale.countryCode!.isNotEmpty) { return '${locale.languageCode}_${locale.countryCode}'; } return locale.languageCode; } static Locale? _parseLocale(String str) { final parts = str.split('_'); if (parts.length == 2) { return Locale(parts[0], parts[1]); } else if (parts.length == 1 && parts[0].isNotEmpty) { return Locale(parts[0]); } return null; } }