rebuild the app after do something like change the theme or change the current language , iam using the ( easy_localization: ^3.0.0 ) package to change the lang
EasyLocalization(
child: MyApp(currentMode: currentMode),
supportedLocales: const [
Locale('ar'),
Locale('en'),
],
path: 'assets/translations',
startLocale: const Locale('ar'),
assetLoader: const CodegenLoader(),
),
If you're looking for the solution to this problem, this one works perfectly(tested) !
Add the package phoenix from here
Wrap your main widget with Phoenix
void main() {
runApp(
Phoenix(
child: App(),
),
);
}
Call rebirth method anywhere in your app like so Phoenix.rebirth(context);
Or make use of state management solutions like riverpod.
You place your settings in a provider and watch it on the pages that should change when the state updates.
Related
I have a small Flutter app with 2 screens (/login & /home) and I use go_router to navigate and animated_login. The assets are placed on the home screen and they load fine if I directly access the screen, so pubspec.yaml is correctly defined.
The images fail to load only when I redirect to /home after /login. One interesting observation is that when this happens, the Flutter dev server seems to be hanging (stops responding, but doesn't crash, can't restart it with R, the browser tab complains that it lost connection to the server etc.). This problem occurs also with a combination of auto_route and flutter_login.
Thanks for any hints.
Router setup (tried also w/ the redirect parameter at router level rather than individual routes):
GoRouter routerGenerator(UserData userData) {
return GoRouter(
initialLocation: Routes.home,
refreshListenable: userData,
debugLogDiagnostics: true,
routes: [
GoRoute(
path: Routes.home,
builder: (_, __) => BasicScreen(),
redirect: (state) => userData.loggedIn ? null : Routes.login
),
GoRoute(
path: Routes.login,
builder: (_, __) => AnimLoginScreen(),
redirect: (state) => !userData.loggedIn ? null : Routes.home
),
GoRoute(path: '/', builder: (_, __) => BasicScreen())
]);
}
abstract class Routes {
static const home = '/home';
static const login = '/login';
}
Main app:
void main() {
runApp(
MultiProvider(providers: [
//other providers here
ChangeNotifierProvider(create: (_) => UserData()),
], child: MyApp()),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
final router =
routerGenerator(Provider.of<UserData>(context, listen: false));
return MaterialApp.router(
title: 'Playground',
routeInformationParser: router.routeInformationParser,
routeInformationProvider: router.routeInformationProvider,
routerDelegate: router.routerDelegate,
);
}
}
Basic screen:
class BasicScreen extends StatelessWidget {
BasicScreen({super.key});
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
Image(image: AssetImage("assets/images/image1.png")),
Image(image: AssetImage("assets/images/image2.png")),
Image(image: AssetImage("assets/images/image3.png")),
],
),
);
}
}
Solution
Provide a simple proxy over both Flutter DevTool & backend services with SSL capabilities.
Explanation
The issue has nothing to do with routing, but rather the dev setup. Our backend services require SSL connections, but Flutter dev tool doesn't support that. Flow:
Flutter DevTool starts the project (plain HTTP) and opens Chrome window.
Assets load ok.
User logs in, backend service requires HTTPS for secure cookies.
Browser upgrades all localhost connections to HTTPS.
Flutter DevTools fails to provide SSL connection.
Assets fail to load.
The hanging DevTool is caused by the same issue: seems to me that the DevTool is pending the WebSocket connection to be opened by the JS code running in the browser, but as the browser initiates an HTTPS connection to the DevTool, it even fails to load the JS code. Therefore, the DevTool never completes the init process (as it has no incoming connection).
I have integrated flutter localizations dependent of system language, works very well.
But I want to "force" language programmatically, without matters on system language.
My app root:
return GetMaterialApp(
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [
Locale('sr', ''),
Locale('en', ''),
],
My lang config file:
arb-dir: lib/l10n
template-arb-file: app_sr.arb
output-localization-file: app_localizations.dart
Any every next new entering into the app will "keep" the user choose preferred language.
Thank you!
You can add the locale attribute to your MaterialApp, like that:
// Content from your MaterialApp
locale: const Locale('sr'),
// More content from your MaterialApp
If you need change in another part of your app, you can change de Locale in your AppLocalizations class.
I would like to have a clear separation of concerns between user enroll flow and the rest of the app. To do that I have created a MaterialApp for Enroll flow and a MaterialApp for the main application. When the user is done signing up - they should be directed to the main app. So something like this:
void main() async {
// ... init and stuff ... //
if(isUserAccountExists){
runApp(MultiProvider(
providers: [
Provider(create: (context) => DataStorage()),
ChangeNotifierProvider.value(value: settingsController),
ChangeNotifierProvider.value(value: oauthProvider),
ChangeNotifierProvider.value(value: deviceProvider),
ChangeNotifierProvider.value(value: messenger),
],
child: MainApp(settingsController: settingsController),
),);
} else runApp(EnrollApp());
}
My problem is when the user is done signing up, I have no ways to restart the application or reload the main() function. (I must restart due to initialization steps that precede the runApp call).
You can use flutter_phoenix to restart your application.
flutter_phoenix configuration:
dependencies:
flutter_phoenix: "^1.0.0"
import 'package:flutter_phoenix/flutter_phoenix.dart';
void main() {
runApp(
Phoenix(
child: App(),
),
);
}
Phoenix.rebirth(context);
You may follow these steps:
After your sign up, call Phoenix.rebirth(context); method to restart the application
In your splash screen or main widget check the database so that the user is already signed up or not then redirect the user to your ux/view.
You can extract your signup logic in separate Class(Widget) to handle which screen to render based on signup status. Something like here:
class _SeparationClassState extends State<SeparationClass> {
bool isUserAccountExists = false;
#override
Widget build(BuildContext context) {
// update isUserAccountExists to trigger rebuild
return Scaffold(
body: isUserAccountExists
? MultiProvider(
providers: [
Provider(create: (context) => DataStorage()),
ChangeNotifierProvider.value(value: settingsController),
ChangeNotifierProvider.value(value: oauthProvider),
ChangeNotifierProvider.value(value: deviceProvider),
ChangeNotifierProvider.value(value: messenger),
],
child: MainApp(settingsController: settingsController),
)
: EnrollApp(),
);
}
}
It doesn't needs to be a StatefulWidget, you can use Provider or Bloc pattern to handle signup logic and update your state (and ui) accordingly.
When working with this package for localization, and base translation done in EN, I want my 2nd language to show keys if they are present in 2nd language json file, but if they are not, to consume en.json equivalent value. Issue is that by default this package shows key that doesn't exist in JSON file, instead of fallback translation file value. Is there a way to override this?
Usage of the plugin in main.dart file
runApp(
EasyLocalization(
child: MyApp(),
useOnlyLangCode: true,
fallbackLocale: Locale('en'),
supportedLocales: [
Locale('en'),
Locale('es'),
],
path: 'lang',
),
);
And when I want to translate a key that exists in en.json, but doesn't exist in es.json file it looks like this:
tr('appTitle');
Expected result would be "Hello world", but I get "appTitle" on the screen.
Old question, but since I just ran into the same problem:
There is now(?) a parameter "useFallbackTranslations" that you have to set to true. Indeed a bit counterintuitive, because one would assume that setting fallbackLocale should be enough.
EasyLocalization(
fallbackLocale: const Locale('en'),
supportedLocales: const [
Locale('en'),
Locale('es'),
Locale('de'),
],
useOnlyLangCode: true,
useFallbackTranslations: true, // <------
path: 'assets/i18n',
child: const MyApp(),
))
This is the EasyLocalization settings in runApp:
runApp(
EasyLocalization(
useOnlyLangCode: true,
useFallbackTranslations: true,
path: LanguageManager.langAssetPath,
supportedLocales: LanguageManager.instance.supportedLocales,
startLocale: LanguageManager.instance.dlLocale,
fallbackLocale: LanguageManager.instance.dlLocale,
child: const App(),
),
);
And the separated LanguageManager class
class LanguageManager {
LanguageManager._init();
static LanguageManager get instance => _instance ??= LanguageManager._init();
static LanguageManager? _instance;
static const langAssetPath = 'assets/translations';
final dlLocale = const Locale('en', 'US'); // necessary
final enLocale = const Locale('en');
final trLocale = const Locale('tr');
List<Locale> get supportedLocales => [dlLocale, enLocale, trLocale];
// constants
static const supportedLanguages = ['en', 'tr'];
Locale getCurrentLocale() {
return supportedLanguages.contains(getCurrentLang)
? Locale(getCurrentLang)
: const Locale('en');
}
String get getCurrentLang => Platform.localeName.substring(0, 2);
}
Finally assets/translations folder must en-US.json, en.json and tr.json
Don't forget generating
PS: This solution is from Veli Bacik in Turkey
I am having problems switching the language in a flutter-web application.
I added the required dependencies to the package.yml.
dependencies:
flutter:
sdk: flutter
intl: ^0.16.1
flutter_localizations:
sdk: flutter
dev_dependencies:
flutter_test:
sdk: flutter
intl_translation: ^0.17.9
Then I initialized the intl stuff in the MaterialApp.
[...]
child: MaterialApp(
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
S.delegate,
],
supportedLocales: S.delegate.supportedLocales,
[...]
Here is the code I expect to change the locale.
Text(S.of(context).language),
RaisedButton(
child: Text("deutsch"),
onPressed: () {
S.load(Locale('de'));
},
),
RaisedButton(
child: Text("englisch"),
onPressed: () {
S.load(Locale('en'));
},
Here are two arb files containing the translation.
{
"language": "Deutsch"
}
{
"language": "English"
}
Everything compiles and I can access the S.of(context) classes. I am sure I missed something. Since the switching of the language doesn't work either if I start in the Android Emulator.
Switching the system locale in the emulator changes the language.
I would appreciate any help or hints.