如何用flutter_intl本地化Flutter中OnBoardingViewModel静态列表字符串
解决OnBoardingViewModel静态列表本地化的方案
方案1:ViewModel存储本地化Key,Widget层完成文本转换
ViewModel只维护本地化对应的标识(用枚举避免硬编码字符串),在有context的Widget中完成文本的本地化转换:
- 定义枚举对应本地化项:
enum OnBoardingLocalKey { title1, subtitle1, title2, subtitle2, }
- 修改ViewModel,存储图片和本地化标识:
class OnBoardingViewModel with ChangeNotifier { final List<Map<String, dynamic>> onBoardingRawData = [ { 'image': ImageManager.onBoardingImage1, 'titleKey': OnBoardingLocalKey.title1, 'subtitleKey': OnBoardingLocalKey.subtitle1, }, { 'image': ImageManager.onBoardingImage2, 'titleKey': OnBoardingLocalKey.title2, 'subtitleKey': OnBoardingLocalKey.subtitle2, } ]; // 其他代码... }
- 在Widget的
build方法中借助context生成最终的页面内容列表:
@override Widget build(BuildContext context) { final viewModel = Provider.of<OnBoardingViewModel>(context); final localizedPages = viewModel.onBoardingRawData.map((rawData) { final titleKey = rawData['titleKey'] as OnBoardingLocalKey; final subtitleKey = rawData['subtitleKey'] as OnBoardingLocalKey; String getTitle() { switch(titleKey) { case OnBoardingLocalKey.title1: return S.of(context).onBoardingTitle1; case OnBoardingLocalKey.title2: return S.of(context).onBoardingTitle2; default: return ''; } } String getSubtitle() { switch(subtitleKey) { case OnBoardingLocalKey.subtitle1: return S.of(context).onBoardingSubTitle1; case OnBoardingLocalKey.subtitle2: return S.of(context).onBoardingSubTitle2; default: return ''; } } return OnBoardingPageContent( image: rawData['image'], title: getTitle(), subtitle: getSubtitle(), ); }).toList(); // 使用localizedPages构建UI return ...; }
方案2:ViewModel提供生成本地化列表的方法,依赖Widget传入context
让ViewModel不直接存储静态列表,而是提供一个接收context的方法,在Widget层调用生成本地化后的列表:
class OnBoardingViewModel with ChangeNotifier { List<OnBoardingPageContent> generateLocalizedPages(BuildContext context) { return [ OnBoardingPageContent( image: ImageManager.onBoardingImage1, title: S.of(context).onBoardingTitle1, subtitle: S.of(context).onBoardingSubTitle1, ), OnBoardingPageContent( image: ImageManager.onBoardingImage2, title: S.of(context).onBoardingTitle2, subtitle: S.of(context).onBoardingSubTitle2, ) ]; } // 其他代码... }
在Widget中调用:
@override Widget build(BuildContext context) { final viewModel = Provider.of<OnBoardingViewModel>(context); final onBoardingPages = viewModel.generateLocalizedPages(context); // 构建UI return ...; }
方案3:监听语言变化,ViewModel动态更新列表(进阶)
如果需要语言切换时自动刷新列表,可以通过监听系统locale变化,让ViewModel动态更新内容(ViewModel不持有context):
- ViewModel中添加locale管理和列表更新逻辑:
class OnBoardingViewModel with ChangeNotifier { late Locale _currentLocale; List<OnBoardingPageContent> _onBoardingPages = []; List<OnBoardingPageContent> get onBoardingPages => _onBoardingPages; OnBoardingViewModel(Locale initialLocale) { _currentLocale = initialLocale; _refreshPages(); } void updateLocale(Locale newLocale) { if (_currentLocale != newLocale) { _currentLocale = newLocale; _refreshPages(); notifyListeners(); } } void _refreshPages() async { // 通过flutter_intl的delegate加载对应locale的本地化资源 final localizedStrings = await S.delegate.load(_currentLocale); _onBoardingPages = [ OnBoardingPageContent( image: ImageManager.onBoardingImage1, title: localizedStrings.onBoardingTitle1, subtitle: localizedStrings.onBoardingSubTitle1, ), OnBoardingPageContent( image: ImageManager.onBoardingImage2, title: localizedStrings.onBoardingTitle2, subtitle: localizedStrings.onBoardingSubTitle2, ) ]; } }
- 在Widget中监听locale变化并通知ViewModel:
class MyOnBoardingScreen extends StatefulWidget { const MyOnBoardingScreen({super.key}); @override State<MyOnBoardingScreen> createState() => _MyOnBoardingScreenState(); } class _MyOnBoardingScreenState extends State<MyOnBoardingScreen> { late OnBoardingViewModel _viewModel; @override void didChangeDependencies() { super.didChangeDependencies(); final currentLocale = Localizations.localeOf(context); _viewModel = Provider.of<OnBoardingViewModel>(context, listen: false); _viewModel.updateLocale(currentLocale); } @override Widget build(BuildContext context) { final onBoardingPages = Provider.of<OnBoardingViewModel>(context).onBoardingPages; // 构建UI return ...; } }
为什么之前的方法不可行?
- 直接传key字符串调用
S.of(context)[key]:flutter_intl生成的S类是强类型结构,没有下标运算符,这种写法不符合语法规范。 - ViewModel持有context:ViewModel属于业务逻辑层,不应该依赖UI层的
BuildContext,且静态列表初始化时context可能尚未完成初始化,会导致空指针异常。
内容的提问来源于stack exchange,提问作者Basheer AL-MOMANI
相关产品推荐
相关产品推荐

