Reputation: 1837
I am using Flutter to build a Web-App and I want to use the internationalization feature of flutter on my new app. I was following the Flutter-Tutorial and I try to set the app-title using the arb-file. As mentioned in the tutorial, the app_localization.dart-files are created properly for 'en' and 'de'. Yet, I get a null pointer exception in the following code.
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'MyApp',
localizationsDelegates: [
AppLocalizations.delegate, // Post-EDIT due to croxx5f
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
Locale('de', ''),
Locale('en', ''),
],
theme: ThemeData(
primarySwatch: Colors.red,
),
home: Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context)!.appTitle),
),
body: Text(AppLocalizations.of(context)!.appTitle)
),
);
}
}
In fact, AppLocalizations.of(context) returns null.
Upvotes: 28
Views: 14502
Reputation: 106
In version 0.19.0 the AppLocalizations class also provides auto-generated localizationsDelegates and supportedLocales lists.
Here it is a complete exemple.
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
locale: Locale('es', 'ES'),
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context)!.helloWorld),
),
body: Center(
child: Text(AppLocalizations.of(context)!.helloWorld),
),
);
}
}
Remember add
flutter pub add flutter_localizations --sdk=flutter
flutter pub add intl
You may need to modify the pubspec.yaml file and enable the generate flag. At the end of the file add this line:
flutter:
generate: true # Add this line
Finally create into de lib folder a subfolder called l10n and create a localization file with name intl_en.arb o intl_es.arb with this content:
In Spanish
{
"@@locale": "es",
"helloWorld": "Hola Mundo",
"@helloWorld": {
"description": "El tradicional mensaje de Hola Mundo"
}
}
In English
{
"@@locale": "en",
"helloWorld": "Hello World",
"@helloWorld": {
"description": "The traditional Hello World message"
}
}
Add configuration file called l10n.yaml in root directory near pubspec.yaml and fill with
arb-dir: lib/l10n
template-arb-file: intl_en.arb
output-localization-file: app_localizations.dart
untranslated-messages-file: desiredFileName.txt
Finally run
flutter pub get
and run the application.
That's all
Upvotes: 0
Reputation: 1702
I have a trick solution: delay a bit for the AppLocalizations to be loaded
Future<bool> getDelay() async {
await Future.delayed(const Duration(milliseconds: 100));
// fix AppLocalizations.of(context) return null
// delay a bit for the AppLocalizations to be loaded
return true;
}
Then, use it in builder
@override
Widget build(BuildContext context) {
return MaterialApp(
locale: Locale(widget.defaultLanguage),
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
home: Scaffold(
extendBodyBehindAppBar: false,
backgroundColor: Colors.red,
appBar: AppBar(
backgroundColor: Colors.yellow,
elevation: 0,
// >>>>>> Solution here <<<<<<
title: FutureBuilder(
future: getDelay(),
builder: (context, snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
return const Text("Loading...");
}
final _ = AppLocalizations.of(context);
return Text(_?.app_title ?? "NULL TITLE");
},
)),
body: ...
),
);
}
Upvotes: 0
Reputation: 31
In my case, I added AppLocalizations in MaterialApp of my main dart file. The localisation became null if I called MaterialApp again on any other page.
return MaterialApp(
debugShowCheckedModeBanner: false,
locale: const Locale('ja'),
supportedLocales: L10n.all,
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
So, I had to find MaterialApp everywhere except the main dart file and comment out those lines, like below.
return
// MaterialApp(
// debugShowCheckedModeBanner: false,
// home:
Scaffold(
...
)
// )
;
Upvotes: 1
Reputation: 8701
Irrelevant to what the op was asking for, but:
If you find yourself needing to set a localized title like so:
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context);
final title = l10n.myTitle;
return MaterialApp(
title: title,
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
...
);
}
That won't work, as you're trying to find an instance of AppLocalization
that isn't included yet.
However, you can use the onGenerateTitle
callback, which includes a context
that CAN find AppLocalization
.
@override
Widget build(BuildContext context) {
return MaterialApp(
onGenerateTitle: (context) {
final l10n = AppLocalizations.of(context);
return l10n.myTitle;
},
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
...
);
}
Upvotes: 6
Reputation: 49
It's possible that you followed a tutorial/course like the one from Fireship (I had the same problem because of this). There, he used a FutureBuilder where he builds another MaterialApp. You'd need to assign the same localization parameters as in the first one. Otherwise, the context object doesn't know about the AppLocalization object.
Upvotes: 0
Reputation: 4007
On my case, using the Scaffold()
as home:
of MaterialApp()
for testing purpose caused the issue.
Once I created a Separate HomePage()
widget and used that as
home: HomePage()
the problem is gone.
When I put the Scaffold(), as a direct child to MaterialApp, that treats as there were no parent contexts available with AppLocalizationDelegate, as the MaterialApp is the main context builder for all the underlying widgets.
Bad code:
return MaterialApp(
home: Scaffold(
body: Txt(text: AppLocalizations.of(context)?.helloWorld)
),
locale: Locale('ar'),
supportedLocales: [Locale('en'),Locale('ar')],
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
]);
},
));
Good code:
return MaterialApp(
home: HomePag(),
locale: Locale('ar'),
supportedLocales: [Locale('en'),Locale('ar')],
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
]);
},
));
class HomePag extends StatefulWidget {
const HomePag({Key? key}) : super(key: key);
@override
State<HomePag> createState() => _HomePagState();
}
class _HomePagState extends State<HomePag> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: [
Txt(text: AppLocalizations.of(context)?.helloWorld),
// Txt(text: AppLocalizations.of(context)?.translate('help'))
],
),
),
);
}
}
Upvotes: 25
Reputation: 723
Thats helped me. I had a CupertinoApp above MaterielApp, this override the MaterielApp and my AppLocalization.of(content) was null
https://github.com/flutter/flutter/issues/26365#issuecomment-523536339
Upvotes: 2
Reputation: 5743
You should add the AppLocalizations
in your MaterialApp:
MaterialApp(
...
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
],
supportedLocales: AppLocalizations.supportedLocales,
...
Upvotes: 24