Why does flutter localization not work properly? - flutter

I want to add the tr tag to the Flutter localization section. I am
getting an error although there is support for Tr. The error is as
follows; error: The element type 'Locale (where Locale is defined in
C:\Users\StatTark\AppData\Roaming\Pub\Cache\hosted\pub.dartlang.org\intl-0.16.1\lib\src\locale.dart)'
can't be assigned to the list type 'Locale (where Locale is defined in
C:\flutter\bin\cache\pkg\sky_engine\lib\ui\window.dart)'.
error: Abstract classes can't be instantiated.
(instantiate_abstract_class at [ajanda] lib\pages\mainmenu.dart:36)
I do not understand if I am making a mistake in use, I will be glad if you help.
class MainMenu extends StatelessWidget {
MainMenu({Key key}) : super(key: key);
final _sdb = SettingsDbHelper();
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: _sdb.getSettings(),
builder: (context, snapshot) {
if (snapshot.data == null) {
return MaterialApp(
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate
],
supportedLocales: [Locale('en','US'),Locale('tr','')], //The error is here
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: Text(proTranslate["Yükleniyor....."][Language.languageIndex]),
),
),
);
} else {
Language.languageIndex = snapshot.data[0].language;
return DynamicTheme(
defaultBrightness: Brightness.light,
data: (brightness) => ThemeData(
brightness: brightness,
fontFamily: snapshot.data[0].fontName,
floatingActionButtonTheme: FloatingActionButtonThemeData(
foregroundColor: Colors.green,
),
),
themedWidgetBuilder: (context, theme) {
return MaterialApp(
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate
],
supportedLocales: [Locale('en','US'),Locale('tr','')],
debugShowCheckedModeBanner: false,
theme: theme,
home: MainMenuBody(
warning: snapshot.data[0].warning,
),
// navigatorKey: navigatorKey,
);
});
}
},
);
}
}
class MainMenuBody extends StatefulWidget {....}

I'm coming a bit late but I just fixed this same issue I had.
I'm pretty sure your file is importing intl/locale.dart instead of flutter/material.dart as both define a Local type.
To fix it, just replace your import at the top of the file from:
import 'package:intl/locale.dart';
to
import 'package:flutter/material.dart';
and you should be OK.

Few suggestions you can try/test, see below.
Replace [Locale('en','US'),Locale('tr','')], with [Locale('en'),Locale('tr')],
init list of supported locales first and use it accordingly.
// init before build
final List<Locale> appSupportedLocales = [
Locale('en'),
Locale('tr')
];
// ...
// then use it like this
supportedLocales: appSupportedLocales,

Related

Internationalization with cubit

I'm working on a project and I've been asked to use cubit for internationalization, preferably using the lazy method. For that I have a LocalizationContainer as follows:
class LocalizationContainer extends BlocContainer {
final Widget child;
LocalizationContainer({required this.child});
#override
Widget build(BuildContext context) {
return BlocProvider<CurrentLocaleCubit>(
create: (context) => CurrentLocaleCubit(),
child: child,
);
}
}
class CurrentLocaleCubit extends Cubit<String> {
CurrentLocaleCubit() : super("pt-br");
CurrentLocaleCubit() : super("en-us");
}
In my main file I have the following:
MaterialApp(
title: 'Example',
theme: exampleTheme(context),
debugShowCheckedModeBanner: false,
home: LocalizationContainer(
child: InitialScreenContainer(),
),
);
In this example the child of LocalizationContainer is another container representing the screen. Each screen is structured into container, cubit and view:
The container for screen have the following structure:
class ExampleScreenContainer extends BlocContainer {
#override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => ExampleScreenCubit(),
child: I18NLoadingContainer(
language: BlocProvider.of<CurrentLocaleCubit>(context).state,
viewKey : "Example",
creator: (messages) => ExampleScreenView(ExampleScreenViewLazyI18N(messages)),
),
);
}
}
Everytime a new page needs to be opened, I do the following:
Navigator.of(blocContext).push(
MaterialPageRoute(
builder: (context) => BlocProvider.value(
value: BlocProvider.of<CurrentLocaleCubit>(blocContext),
child: NewScreenContainer(),
),
),
);
But whenever I try to hot reload a error pops up. It only works if I do the hot restart. Does somebody know how to solve this problem, or this internationalization method is wrong?
I did not really get the problem (I think if you put the error that's pop up I can help you more), but this way I do localizations (I use bloc).
first off all you need to add BlocProvider above MaterialApp so he become ancestor to every widget in context tree, so when ever you called BlocProvider.of(context)
you can get the instance of this bloc where ever you are in the tree (no need to do BlocProvider above every screen you are pushing).
now when ever you change language of your app and yield the new state the BlocBuilder will rebuild the whole app with the new language.
class AppProvider extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiBlocProvider(providers: [
BlocProvider<AppBloc>(
create: (_) => sl<AppBloc>()
//get app default language
..add(const AppEvent.initialEvent()),
),
], child: App());
}
}
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return BlocBuilder<AppBloc, AppState>(
builder: (context, state) => MaterialApp(
debugShowCheckedModeBanner: false,
home: SplashScreen()),
locale: state.language == AppLanguageKeys.AR
? const Locale('ar', '')
: const Locale('en', ''),
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: [
const Locale('en', ''), // English
const Locale('ar', ''), // Arabic
],
),
);
}
}

(watch)The expression doesn't evaluate to a function, so it can't be invoked

I'm trying to set up a theme for my flutter project, ill greatly appreciate if you kindly show me another way to do that.
import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:firebase_analytics/observer.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:picpuzzle/routes/route_name.dart';
import 'package:picpuzzle/widgets/login/login_screen.dart';
import 'package:picpuzzle/widgets/main/main_page.dart';
import 'package:picpuzzle/widgets/puzzle/puzzle_list_page.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'common/constants.dart';
/// use for DarkMode,not sync with system
final DarkModeProvider = StateProvider((ref) => false);
class MyApp extends StatelessWidget {
// This widget is the root of your application.
static FirebaseAnalytics analytics = FirebaseAnalytics.instance;
static FirebaseAnalyticsObserver observer =
FirebaseAnalyticsObserver(analytics: analytics);
void initApp(BuildContext context) {}
#override
Widget build(BuildContext context) {
/// init
initApp(context);
return Consumer(
builder: (context, watch, _) {
return MaterialApp(
debugShowCheckedModeBanner: false,
localizationsDelegates: [
AppLocalizations.delegate, // Add this line
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
const Locale('en', ''), // English, no country code
const Locale('ja', ''), // Japanese, no country code
],
title: 'Pic Puzzle',
initialRoute: RouteName.Login,
routes: {
RouteName.Login: (context) => LoginScreen(),
RouteName.Main: (context) => MainPage(),
RouteName.Home: (context) => PuzzleListPage(),
},
theme: watch(DarkModeProvider).state ? darkTheme : lightTheme,
// darkTheme: darkTheme,
);
},
);
}
}
but it won't be able to make it ,becouse of this
lib/my_app.dart:49:23: Error: The method 'call' isn't defined for the
class 'WidgetRef'.
- 'WidgetRef' is from 'package:flutter_riverpod/src/consumer.dart'
('../Documents/flutter_windows_2.8.1-stable/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_riverpod-1.0.3/lib/src/consumer.dart').
Try correcting the name to the name of an existing method, or defining a method named 'call'.
theme: watch(DarkModeProvider).state ? darkTheme : lightTheme,
This part
theme: watch(DarkModeProvider).state ? darkTheme : lightTheme,
should be changed to:
theme: watch.watch(DarkModeProvider.state).state ? darkTheme : lightTheme,

Flutter - app localization using intl translations for messages inside Cubit/ Bloc

I am working on a multilingual app in Flutter.
I had no problem with implementing the localized strings in widgets/ screens following the official docs: https://flutter.dev/docs/development/accessibility-and-localization/internationalization.
But ... my app does a lot of calls to an API which are handled behind the scenes by appropriate Cubits and Repositories. For these calls and other deeper logic I would like to provide status messages in appropriate languages (e.g. for snackbars). The problem I face is that I cannot access localized strings inside the Cubits to provide messages to the state. Even if I try to pass the context to the Cubit it does not see them.
Anyone have an idea please? I would prefer following the official approach and not having to totally refactor the app ...
Thanks in anticipation!
Somebody helped me with this.
The solution is simple(ish).
You have to pass appLocalizations themselves into the Cubits. Here is my main.dart:
runApp(
MaterialApp(
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
const Locale('en', ''),
const Locale('pl', ''),
],
title: 'MySuperApp',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.orange,
accentColor: Colors.deepOrangeAccent,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
initialRoute: '/',
routes: {
UserAuthScreen.routeName: (context) => const UserAuthScreen(),
HomePage.routeName: (context) => HomePage(),
...
},
builder: (context, child) {
final appLocalizations = AppLocalizations.of(context); //IMPORTANT
return MultiBlocProvider(
providers: [
BlocProvider<ConstantsCubit>(
lazy: true,
create: (context) => ConstantsCubit(
constantsRepository: ConstantsRepository(),
),
),
BlocProvider<UserAuthCubit>(
lazy: true,
create: (context) => UserAuthCubit(
localizations: appLocalizations, //THIS IS WHERE THE MAGIC HAPPENS
repository: UserAuthRepository(),
),
),
BlocProvider<DoerInfoCubit>(
lazy: true,
create: (context) => DoerInfoCubit(
doerInfoRepository: DoerInfoRepository(),
userAuthCubit: BlocProvider.of<UserAuthCubit>(context),
)),
...
],
child: child,
);
},
home:
BlocBuilder<UserAuthCubit, UserAuthState>(builder: (context, state) {
if (state is UserAuthLogged) {
return HomePage();
} else {
return const UserAuthScreen();
}
}),
),
);
The UserAuthCubit declaration looks like this:
class UserAuthCubit extends Cubit<UserAuthState> {
final UserAuthRepository repository;
final AppLocalizations localizations; //THIS IS WHERE THE MAGIC HAPPENS
UserAuthCubit({
#required this.repository,
#required this.localizations,
}) : super(const UserAuthInitial()) {
getUserAuthState();
}
IMPORTANT - to make sure the solutions works - AppLocalizatons have to be declared before the Cubits in the main.dart.
ALSO - the app adopts new localizations in the widgets straight away after language change. However with this setup I was not able to achieve this for Cubits. They need a restart of the app. In real life scenario this should not be a problem ... I guess.
It's easy to do with the easy_localization package. The only downside is code generation to be done on every string change. Otherwise it doesn't need a context to get a string, like so:
LocaleKeys.app_title.tr()
Check out the whole tutorial on how to setup and use EasyLocalization.

ChangeNotifierProxyProvider getting null value

I am new to flutter.
In my application locale information is found when the user login.
So the idea is when the user login, it will pass the locale to AppLanguage.
I have written ChangeNotifierProxyProvider to get the locale inside authentication information and create a AppLanuage object
In the ChangeNotifierProxyProvider I am getting appLang as null. auth object is correctly NOT null.
What I don't understand why I am getting null?
I did create it here right?
create: (_) => AppLanguage(),
shouldn't it come as a parameter for the update?
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider.value(value: Auth()),
ChangeNotifierProxyProvider<Auth, AppLanguage>(
create: (_) => AppLanguage(),
update: (ctx, auth, appLang) {
print(auth);
print(appLang);
}
//appLang.setLocale(auth == null ? 'en' : auth.language),
),
],
child: Consumer2<Auth, AppLanguage>(
builder: (ctx, auth, lang, child) => MaterialApp(
title: 'Test App',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
locale: lang.appLocal,
supportedLocales: [
const Locale('en', 'US'),
const Locale('ja', ''),
],
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
home: LandingView(),
),
),
);
}
I would try something like:
ChangeNotifierProxyProvider<Auth, AppLanguage>(
create: (_) => AppLanguage(),
update: (ctx, auth, appLang) => appLang..update(auth),
),
class AppLanguage with ChangeNotifier {
void update(Auth auth) {
// Do some custom work based on myModel that may call `notifyListeners`
}
}
That way your child will be able to get the correct updated values when they're available.
You can check more how to deal properly with that on the provider docs.

Flutter Local routes issue

I have a small problem with a flutter local app. I am trying to have 2 routes depending on device languageCode. When I build the app, that second option are launched. If I save the app, the right route are picked. I think the
final lang = locale.languageCode;
Do not have a value when this is called:
"/newsfeed": lang == "da"
? (BuildContext context) => News()
: (BuildContext context) => NewsEN(),
The print statement I have in the code have the right value, so are a bit lost Here are the code:
class MyApp3 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
// List all of the app's supported locales here
supportedLocales: [
Locale('en', 'US'),
Locale('da', 'DK'),
],
// These delegates make sure that the localization data for the proper language is loaded
localizationsDelegates: [
// A class which loads the translations from JSON files
AppLocalizations.delegate,
// Built-in localization of basic text for Material widgets
GlobalMaterialLocalizations.delegate,
// Built-in localization for text direction LTR/RTL
GlobalWidgetsLocalizations.delegate,
],
// Returns a locale which will be used by the app
localeResolutionCallback: (locale, supportedLocales) {
// Check if the current device locale is supported
for (var supportedLocale in supportedLocales) {
//print(locale.languageCode);
final lang = locale.languageCode;
print(lang);
if (supportedLocale.languageCode == locale.languageCode &&
supportedLocale.countryCode == locale.countryCode) {
return supportedLocale;
}
}
// If the locale of the device is not supported, use the first one
// from the list (English, in this case).
return supportedLocales.first;
},
home: MyHomePage(),
routes: <String, WidgetBuilder> {
//"/Knowledge_pick": (BuildContext context) => SplashScreen(),
"/calculator_pick": (BuildContext context) => Pickcalculator(),
//"/receipe_pick": (BuildContext context) => Receipemenu(),
"/receipe_pick": (BuildContext context) => Wrapper(),
"/newsfeed": lang == "da"
? (BuildContext context) => News()
: (BuildContext context) => NewsEN(),
Hope someone can help me with this problem.
Honestly I don't see why this wouldn't work but what you should try to do is setup two different routes, one from 'da' and one for 'en'
"/newsfeedDA": (BuildContext context) => News(),
"/newsfeedEN": (BuildContext context) => NewsEN(),
and have your logic for selecting them in the initState or constructor of MyHomePage().