8

Question

I am using AppLocalizations.of(context).myString to internationalize strings in my null safe flutter app.

My IDE tells me that AppLocalizations.of(context) can return null. What's the best approach to handle this? Is there a way to ensure AppLocalizations.of(context) never returns null?

Currently, I am resorting to the following approach:

AppLocalizations.of(context)?.myString ?? 'Fallback string'

Full Project Code

Pubspec.yaml

name: Sample Intl Project
description: A sample project
publish_to: 'none'
version: 1.0.0+1

environment:
  sdk: ">=2.12.0-133.2.beta <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  intl: ^0.17.0-nullsafety.2

dev_dependencies:
  flutter_test:
    sdk: flutter

flutter:
  uses-material-design: true
  generate: true

l10n.yaml

arb-dir: lib/l10n
template-arb-file: app_en_US.arb
output-localization-file: app_localizations.dart

l10n/app_en_US.arb

{
  "helloWorld": "Hello World!",
  "@helloWorld": {
    "description": "Greeting"
}

l10n/app_en.arb

{
  "helloWorld": "Hello World!"
}

main.dart

import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

void main() {
  runApp(App());
}

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Sample App',
      localizationsDelegates: AppLocalizations.localizationsDelegates,
      supportedLocales: AppLocalizations.supportedLocales,
      home: Home()
    );
  }
}

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text(
        AppLocalizations.of(context)?.helloWorld ?? 'Hello World!'
      ),
    );
  }
}
Adam Griffiths
  • 680
  • 6
  • 26
  • 60
  • Where package does `AppLocalizations` comes from? – julemand101 Jan 10 '21 at 19:35
  • It's auto generated when you add internationalization configuration to a Flutter app. See the [docs](https://flutter.dev/docs/development/accessibility-and-localization/internationalization#adding-your-own-localized-messages), specifically steps 6 and 7. – Adam Griffiths Jan 11 '21 at 01:13
  • Could you pleade provide more Code, this message does not occur to me – m123 Jan 15 '21 at 10:03
  • Try just `AppLocalizations.of(context).myString`. You need to opt into null safety first by executing the following commands: `flutter channel beta; flutter upgrade` in a terminal. – Adam Griffiths Jan 15 '21 at 10:15

5 Answers5

17

add this line in l10n.yaml:

nullable-getter: false
6

If you are sure, that AppLocalizations.of(context) will always return a valid AppLocalizations instance (which is true for your sample application), you can use:

AppLocalizations.of(context)!.myString

The ! operator tells Dart, that AppLocalizations.of(context) will never return null and acts like a cast from the nullable AppLocalizations? to the non-nullable AppLocalizations.

Note: If AppLocalizations.of(context) returns null at runtime, then AppLocalizations.of(context)! will throw an exception.

Michael Tamm
  • 883
  • 8
  • 13
4

(I'm not allowed to comment so I am answering)

Add key/value

nullable-getter: false

to l10n.yaml (located at the root of the project).

This will automatically do a null check on AppLocalizations.of(context), allowing the programmer to just write AppLocalizations.of(context).<key> instead of AppLocalizations.of(context)!.<key>.

From Flutter's documentation:

[no-]nullable-getter

Specifies whether the localizations class getter is nullable.

By default, this value is true so that Localizations.of(context) returns a nullable value for backwards compatibility. If this value is false, then a null check is performed on the returned value of Localizations.of(context), removing the need for null checking in user code.

santos
  • 79
  • 3
1

As also said in a comment, I would ask you to share more of your code, your pubpsec your l10n.yaml and anything else relevant as far as you can.

My suggestion until then is to update intl in your dependencies from the latest to:

intl: ^0.17.0-nullsafety.2

I assume that nullsafety will not be left to the end devs and it will be standard very soon without having to think about it.

m123
  • 2,824
  • 1
  • 11
  • 29
0

As it seems, your app always expects string value from AppLocalizations texts.
I suggest ensuring string is null safe, and that should solve your problem.
Here is snippets that you can use.

  1. Define a string extension
// a string extension
extension MyStringExtentions on String {
  String nullSafeStr() =>
      (this == null || this.isEmpty || this == "null") ? "" : this;
}

// OR a static method
//static String nullSafeStr(String source) => (source == null || source.isEmpty || source == "null") ? "" : source;

now you can use either of them, see example using the new extension

// .nullSafeStr() becomes available wherever you import the extension method 
AppLocalizations.of(context).helloWorld.nullSafeStr()

// the alternative way is to call the static method  
.nullSafeStr(AppLocalizations.of(context).helloWorld);  
Yilmaz Guleryuz
  • 9,313
  • 3
  • 32
  • 43
  • Where is the documentation that says using `.translate('key')` is required? In the [official internationalizing Flutter guide](https://flutter.dev/docs/development/accessibility-and-localization/internationalization#adding-your-own-localized-messages). It does not use `.translate('key')` – Adam Griffiths Jan 18 '21 at 17:25
  • apologies, that was my bad, I copied the snippet from my apps. I have a utility which abstracts `AppLocalizations` usage and I use `.translate('key')` method for all keys. I'll update my answer – Yilmaz Guleryuz Jan 19 '21 at 10:02
  • @AdamGriffiths have already tried my suggestion? – Yilmaz Guleryuz Jan 21 '21 at 11:08
  • Yes but it's not a great suggestion. Firstly `AppLocalizations.of(context).helloWorld.nullSafeStr()` has to be turned to `AppLocalizations.of(context)?.helloWorld.nullSafeStr()`. Secondly in the case it is actually null we would return an empty string which would make the UI look weird. – Adam Griffiths Jan 21 '21 at 13:33