flutterfire icon indicating copy to clipboard operation
flutterfire copied to clipboard

[firebase_messaging] Localization of notifications does not work

Open bscottsmith opened this issue 5 years ago • 27 comments

The FCM fields used for localizing (I18N) the notification title and body are not working. For example:

{
  "android" : {
    "priority" : "normal",
    "notification" : {
      "title_loc_key": "notify_title",
      "body_loc_key": "notify_body"
    }
  }
}

The FCM documentation states that these fields are used to localize the text in the "app's string resources", but Flutter does not have a res/values/strings.xml file. I am using the flutter_localizations library, and maintain res/values/strings_<lang>.arb files as required by Flutter for internationalization, but there is no way for me to tell firebase_messaging to use these resources.

bscottsmith avatar Apr 25 '20 17:04 bscottsmith

hI @bscottsmith This platform is not meant for assistance on personal code. Please see https://flutter.dev/community for resources and asking questions like this, you may also get some help if you post it on Stack Overflow. Closing, as this isn't an issue with Flutter itself, if you disagree please write in the comments and I will reopen it Thank you

TahaTesser avatar Apr 27 '20 14:04 TahaTesser

I don't understand. How is the fact that firebase_messaging doesn't support localization of FCM notifications an issue with "personal code"? Are you saying that the title_loc_key and body_loc_key FCM fields are, in fact, supported by firebase_messaging, and therefore I may have a coding issue on my end?

bscottsmith avatar Apr 27 '20 16:04 bscottsmith

@TahaTesser, I see that you assigned a type of "documentation" to this issue. Are you saying that the title_loc_key and body_loc_key FCM fields are, in fact, supported by firebase_messaging, and that it is simply not documented correctly? I would appreciate your input on this, as I can not find any way to support localization of the FCM notifications with the firebase_messaging plugin.

bscottsmith avatar May 04 '20 03:05 bscottsmith

Hi @bscottsmith I assigned documentation label so we can have examples of localized notifications

TahaTesser avatar May 04 '20 14:05 TahaTesser

@bscottsmith Hi, did you manage to have messages localized? I'm hitting the same wall here. https://github.com/FirebaseExtended/flutterfire/issues/2759

vinnytwice avatar Jun 15 '20 09:06 vinnytwice

@vinnytwice: Nope. And unfortunately, it still isn't even assigned. @TahaTesser assigned this issue a type "documentation", which implies localization is supported and simply needs to be documented, so I worry this will never be assigned to a developer, even though I don't believe this plugin supports it at all (how do you document something that isn't supported?)...

bscottsmith avatar Jun 15 '20 17:06 bscottsmith

@bscottsmith I see that @TahaTesser hasn't really answered that localization is supported, but it's fair to assume that. This is how I sent the notification, do you do anything different?

void sendBookingReceived(Booking booking) async {
    print('sendBookingReceived() started');
    var customerName = booking.customerName;
    var bookingStart = booking.bookingStart;
    var customerFCMToken = booking.customerFCMToken;

    await post('https://fcm.googleapis.com/fcm/send',
        headers: <String, String>{
          'Content-Type': 'application/json',
          'Authorization': 'key=$firebaseServerKey'
        },
        body: jsonEncode({
          'notification': <String, dynamic>{
            'title_loc_key': 'BOOKING_RECEIVED_PUSH_SUBTITLE',
            'title_loc_args': [booking.shopName],
            'body_loc_key': 'BOOKING_RECEIVED_PUSH_BODY',
            'body_loc_args': [
              customerName,
              '',
              bookingStart
            ], //, bookingDate, bookingStart]),
            'sound': 'true',
            'mutable_content': 'true',
            'content_available': 'true'
},
          'priority': 'high',
          'data': <String, dynamic>{
            'click_action': 'FLUTTER_NOTIFICATION_CLICK',
            'id': '1',
            'status': 'done'
          },
          'to': customerFCMToken
        })).whenComplete(() {
      print('sendBookingReceived(): message sent');
    }).catchError((e) {
      print('sendBookingReceived() error: $e');
    });
  }

Also I had a look at the plugin code but I couldn't really see if it supports localization. So @TahaTesser I know that you guys are pretty busy but can you please make clear if it's supported or not? Really appreciate all the efforts.

Cheers

vinnytwice avatar Jun 15 '20 19:06 vinnytwice

@bscottsmith It's fair to say there is no documentation for this, i couldn't find any but attempting to try it has some issues so i am assigning bug label too

TahaTesser avatar Jun 16 '20 12:06 TahaTesser

@TahaTesser nice one, hope it gets fixed soon. Thanks for the clarification on the subject.

vinnytwice avatar Jun 17 '20 06:06 vinnytwice

yes i hope to found this feature working soon and it has to be localized according to Localizations.localeOf(context) => material app locale

mu-dawood avatar Jun 28 '20 04:06 mu-dawood

I havent found any documentation for these fields but they are present in the firebase sdks. The following code is taken from the firebase admin nodejs sdk:

 // admin.messaging.NotificationMessagePayload

  /**
   * Interface representing an FCM legacy API notification message payload.
   * Notification messages let developers send up to 4KB of predefined
   * key-value pairs. Accepted keys are outlined below.
   *
   * See [Build send requests](/docs/cloud-messaging/send-message)
   * for code samples and detailed documentation.
   */
  interface NotificationMessagePayload {
    
    /**
     * Identifier used to replace existing notifications in the notification drawer.
     *
     * If not specified, each request creates a new notification.
     *
     * If specified and a notification with the same tag is already being shown,
     * the new notification replaces the existing one in the notification drawer.
     *
     * **Platforms:** Android
     */
    tag?: string;

    /**
     * The notification's body text.
     *
     * **Platforms:** iOS, Android, Web
     */
    body?: string;

    /**
     * The notification's icon.
     *
     * **Android:** Sets the notification icon to `myicon` for drawable resource
     * `myicon`. If you don't send this key in the request, FCM displays the
     * launcher icon specified in your app manifest.
     *
     * **Web:** The URL to use for the notification's icon.
     *
     * **Platforms:** Android, Web
     */
    icon?: string;

    /**
     * The value of the badge on the home screen app icon.
     *
     * If not specified, the badge is not changed.
     *
     * If set to `0`, the badge is removed.
     *
     * **Platforms:** iOS
     */
    badge?: string;

    /**
     * The notification icon's color, expressed in `#rrggbb` format.
     *
     * **Platforms:** Android
     */
    color?: string;

    /**
     * The sound to be played when the device receives a notification. Supports
     * "default" for the default notification sound of the device or the filename of a 
     * sound resource bundled in the app. 
     * Sound files must reside in `/res/raw/`.
     * 
     * **Platforms:** Android
     */
    sound?: string;

    /**
     * The notification's title.
     *
     * **Platforms:** iOS, Android, Web
     */
    title?: string;

    /**
     * The key to the body string in the app's string resources to use to localize
     * the body text to the user's current localization.
     *
     * **iOS:** Corresponds to `loc-key` in the APNs payload. See
     * [Payload Key Reference](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/PayloadKeyReference.html)
     * and
     * [Localizing the Content of Your Remote Notifications](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CreatingtheNotificationPayload.html#//apple_ref/doc/uid/TP40008194-CH10-SW9)
     * for more information.
     *
     * **Android:** See
     * [String Resources](http://developer.android.com/guide/topics/resources/string-resource.html)      * for more information.
     *
     * **Platforms:** iOS, Android
     */
    bodyLocKey?: string;

    /**
     * Variable string values to be used in place of the format specifiers in
     * `body_loc_key` to use to localize the body text to the user's current
     * localization.
     *
     * The value should be a stringified JSON array.
     *
     * **iOS:** Corresponds to `loc-args` in the APNs payload. See
     * [Payload Key Reference](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/PayloadKeyReference.html)
     * and
     * [Localizing the Content of Your Remote Notifications](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CreatingtheNotificationPayload.html#//apple_ref/doc/uid/TP40008194-CH10-SW9)
     * for more information.
     *
     * **Android:** See
     * [Formatting and Styling](http://developer.android.com/guide/topics/resources/string-resource.html#FormattingAndStyling)
     * for more information.
     *
     * **Platforms:** iOS, Android
     */
    bodyLocArgs?: string;

    /**
     * Action associated with a user click on the notification. If specified, an
     * activity with a matching Intent Filter is launched when a user clicks on the
     * notification.
     *
     *   * **Platforms:** Android
     */
    clickAction?: string;

    /**
     * The key to the title string in the app's string resources to use to localize
     * the title text to the user's current localization.
     *
     * **iOS:** Corresponds to `title-loc-key` in the APNs payload. See
     * [Payload Key Reference](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/PayloadKeyReference.html)
     * and
     * [Localizing the Content of Your Remote Notifications](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CreatingtheNotificationPayload.html#//apple_ref/doc/uid/TP40008194-CH10-SW9)
     * for more information.
     *
     * **Android:** See
     * [String Resources](http://developer.android.com/guide/topics/resources/string-resource.html)
     * for more information.
     *
     * **Platforms:** iOS, Android
     */
    titleLocKey?: string;

    /**
     * Variable string values to be used in place of the format specifiers in
     * `title_loc_key` to use to localize the title text to the user's current
     * localization.
     *
     * The value should be a stringified JSON array.
     *
     * **iOS:** Corresponds to `title-loc-args` in the APNs payload. See
     * [Payload Key Reference](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/PayloadKeyReference.html)
     * and
     * [Localizing the Content of Your Remote Notifications](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CreatingtheNotificationPayload.html#//apple_ref/doc/uid/TP40008194-CH10-SW9)
     * for more information.
     *
     * **Android:** See
     * [Formatting and Styling](http://developer.android.com/guide/topics/resources/string-resource.html#FormattingAndStyling)
     * for more information.
     *
     * **Platforms:** iOS, Android
     */
    titleLocArgs?: string;
    [key: string]: string | undefined;
  }

crtl avatar Oct 15 '20 14:10 crtl

any update here

mu-dawood avatar Nov 07 '20 22:11 mu-dawood

I'm waiting for it too

Dn-a avatar Nov 17 '20 18:11 Dn-a

This would be awesome if we can find a solution for this!

pumuckelo avatar Nov 17 '20 20:11 pumuckelo

Meanwhile, for a quick & dirty solution you could save the locale of the device (Platform.localeName) to the device token in your database and then send the correct message in your cloud function depending on the locale of the token.

pumuckelo avatar Nov 17 '20 20:11 pumuckelo

As a workaround for android: we can create a file under the path: ../android/app/src/main/res/values/strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="your_string_key">Your string</string>
</resources>

define all the default strings there and create separate files for localized countries (as usually native android works)

spiderion avatar Nov 22 '20 20:11 spiderion

I suggest anyone who encounters this issue for now to use flutter_local_notifications together with intl_translation

nt4f04uNd avatar Dec 14 '20 15:12 nt4f04uNd

I made a workaround for that if any one interested i created this package that allow me to display notification in foreground using locale notification and this one https://pub.dev/packages/fcm_config

so to translate notification i have to display it my self as next first from postman i send data only message

{
    "priority": "high",
    "to":"/topics/test_fcm_topic",
    "data": {
        "title_key": "New_Order_Title",
        "body_key": "New_Order_Body",
        "body_args": "150"
    }
}

Next in my dart code

Map<String, Map<String, String>> translations = {
  "ar": {
    "New_Order_Title": "طلب جديد",
    "New_Order_Body": "لديك طلب جديد برقم{args}",
  },
  "en": {
    "New_Order_Title": "New order",
    "New_Order_Body": "You has new order with number {args}",
  }
};
Future<void> _firebaseMessagingBackgroundHandler(
    RemoteMessage _notification) async {
  var strings = translations[(await getSavedLocale()).languageCode];
  if (strings == null) strings = translations["en"];
  String title = strings[_notification.data["title_key"]];
  String body = strings[_notification.data["body_key"]]
      .replaceAll("{args}", _notification.data["body_args"]);
  FCMConfig.displayNotification(title: title, body: body);
}

Future<Locale> getSavedLocale() async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  await prefs.reload();
  var locale = prefs.containsKey("locale") ? prefs.getString("locale") : null;
  return Locale(locale ?? Platform.localeName);
}


  void main() async {
    FCMConfig.init(onBackgroundMessage: _firebaseMessagingBackgroundHandler)
      .then((value) {
        FCMConfig.subscribeToTopic("test_fcm_topic");
     });
    runApp(MaterialApp(
      home: MyHomePage(),
    ));
  }

so what i do is saving my locale in shared preferences and retrieve it on background

on foreground i did this

//This how my plugin handle onMessage so don't be confused  
@override
  void onNotify(RemoteMessage notification) {
    _firebaseMessagingBackgroundHandler(notification);
    setState(() {
      _notification = notification;
    });
  }

Hope this help any one

mu-dawood avatar Jan 06 '21 22:01 mu-dawood

Any updates on this ?

tzvc avatar Jan 15 '21 10:01 tzvc

as i see no progress on this i created a package to help localize notification if any one interested fcm_localization

mu-dawood avatar Mar 22 '21 15:03 mu-dawood

Any updates on this ?

FatimaCha avatar Jun 10 '21 09:06 FatimaCha

To use those loc_key fields in Android and IOS I've been using the native resource localization files:

On Android: strings.xml (/android/app/src/main/res/values/strings.xml)

on IOS: Localizable.strings (/ios/Runner/Base.lproj/Localizable.strings)

But I've got all these strings in a Flutter ARB as well. I just figured it's not possible to access the Flutter ARB for the loc_keys because of a native internal OS routine on Android and IOS that handles the localization of the strings based on only know about the native resource files. I think the handling of the loc_keys is out of the hands of the Flutter engine.

I use firebase_messaging for everything else.

assemblethis avatar Jun 29 '21 17:06 assemblethis

@assemblethis I did the same thing , but when the app in foreground I get notification tile and body null , (just in android) do you have any adea ?

FatimaCha avatar Jul 15 '21 17:07 FatimaCha

This is a useful feature to have as much can be localized for a flutter and firebase app with good documentation, hopefully some clear documentation or solution can come for localization in relation to FCM too!

sohaibnoman avatar Sep 12 '21 15:09 sohaibnoman

Any updates on this? Are we supposed to create native string files just for cloud_messaging?

ciriousjoker avatar Feb 22 '22 01:02 ciriousjoker

This problem stems from differences between old http api and new v1 api, in old api (like here, with fcm.googleapis.com/fcm/send) you need to use body_loc_key and title_loc_key inside notification object. But in v1 api you need to use bodyLocKey inside message.android.notification object. Like you see in documentation, it uses bodyLocKey inside notification object which will not work. You need to change field names to lowercase with underscores. I've just discovered this in my totally unrelated closed project, but want to share what is wrong.

k-marciniak avatar Mar 04 '22 12:03 k-marciniak

Hi, any update here?

1057437122 avatar Apr 03 '22 20:04 1057437122

As per #9502 there is now documentation on how to do this :)

Lyokone avatar Sep 27 '22 06:09 Lyokone

As per #9502 there is now documentation on how to do this :)

This isn't really a proper solution when the Flutter framework suggests to handle localization differently: https://docs.flutter.dev/development/accessibility-and-localization/internationalization

The proper solution likely involves either transpiling the .arb files to their respective platforms, or investigating/collaborating with the managers of the flutter_localizations package as it may already transpile to some degree and could be a more efficient route to complete this task.

AdamBridges avatar Sep 27 '22 18:09 AdamBridges