@@ -23,7 +23,9 @@ import 'package:collection/collection.dart';
2323import 'package:flutter/material.dart' ;
2424import 'package:shared_preferences/shared_preferences.dart' ;
2525import 'package:wger/helpers/consts.dart' ;
26+ import 'package:wger/helpers/locale.dart' ;
2627import 'package:wger/helpers/shared_preferences.dart' ;
28+ import 'package:wger/l10n/generated/app_localizations.dart' ;
2729import 'package:wger/models/user/profile.dart' ;
2830import 'package:wger/providers/base_provider.dart' ;
2931
@@ -63,12 +65,14 @@ class DashboardItem {
6365
6466class UserProvider with ChangeNotifier {
6567 ThemeMode themeMode = ThemeMode .system;
68+ Locale ? userLocale;
6669 final WgerBaseProvider baseProvider;
6770 late SharedPreferencesAsync prefs;
6871
6972 UserProvider (this .baseProvider, {SharedPreferencesAsync ? prefs}) {
7073 this .prefs = prefs ?? PreferenceHelper .asyncPref;
7174 _loadThemeMode ();
75+ _loadUserLocale ();
7276 _loadDashboardConfig ();
7377 }
7478
@@ -96,6 +100,38 @@ class UserProvider with ChangeNotifier {
96100 notifyListeners ();
97101 }
98102
103+ /// Load saved user locale override from SharedPreferences. A null value means
104+ /// the app should follow the system locale.
105+ Future <void > _loadUserLocale () async {
106+ final raw = await prefs.getString (PREFS_USER_LOCALE );
107+ userLocale = _matchSupportedLocale (raw);
108+ notifyListeners ();
109+ }
110+
111+ /// Match a stored locale tag (`languageCode` or `languageCode_subtag` ) against
112+ /// the app's [AppLocalizations.supportedLocales] . Returns the exact supported
113+ /// instance to keep dropdown identity stable, or null when no match is found.
114+ static Locale ? _matchSupportedLocale (String ? raw) {
115+ if (raw == null || raw.isEmpty) {
116+ return null ;
117+ }
118+ for (final locale in AppLocalizations .supportedLocales) {
119+ if (encodeLocale (locale) == raw) {
120+ return locale;
121+ }
122+ }
123+ // Fallback: match by language only (e.g. stored "pl" picks the only pl).
124+ final lang = raw.split ('_' ).first;
125+ for (final locale in AppLocalizations .supportedLocales) {
126+ if (locale.languageCode == lang &&
127+ (locale.countryCode == null || locale.countryCode! .isEmpty) &&
128+ (locale.scriptCode == null || locale.scriptCode! .isEmpty)) {
129+ return locale;
130+ }
131+ }
132+ return null ;
133+ }
134+
99135 // Dashboard configuration
100136 List <DashboardItem > _dashboardItems = DashboardWidget .values
101137 .map ((w) => DashboardItem (w))
@@ -193,6 +229,20 @@ class UserProvider with ChangeNotifier {
193229 notifyListeners ();
194230 }
195231
232+ /// Override the app locale. Passing `null` clears the override and falls
233+ /// back to the system locale via `localeListResolutionCallback` .
234+ Future <void > setUserLocale (Locale ? locale) async {
235+ userLocale = locale;
236+
237+ if (locale == null ) {
238+ await prefs.remove (PREFS_USER_LOCALE );
239+ } else {
240+ await prefs.setString (PREFS_USER_LOCALE , encodeLocale (locale));
241+ }
242+
243+ notifyListeners ();
244+ }
245+
196246 /// Fetch the current user's profile
197247 Future <void > fetchAndSetProfile () async {
198248 final userData = await baseProvider.fetch (baseProvider.makeUrl (PROFILE_URL ));
0 commit comments