iosswiftfirebase-cloud-messagingunusernotificationcenter

Localise notifications sent from Firebase


Is there a way to translate / localise notifications sent from Firebase?

I have my app setup to receive notifications successfully:

extension AppDelegate: UNUserNotificationCenterDelegate {

    func setupNotifications() {
        registerForRemoteNotifications()
        setupNotificationTokenRefresh()
    }

    func registerForRemoteNotifications() {
        let application = UIApplication.shared
        UNUserNotificationCenter.current().delegate = self

        application.registerForRemoteNotifications()
    }

    func setupNotificationTokenRefresh() {
        storeNotificationToken()
    
        _ = NotificationCenter.default.addObserver(
            forName: .MessagingRegistrationTokenRefreshed,
            object: nil,
            queue: .current
        ) { [weak self] _ in
            self?.storeNotificationToken()
        }
    }

    private func storeNotificationToken() {
        Messaging.messaging().token { [weak self] token, error in
            if let error = error {
                Log.error("Error fetching FCM registration token: \(error)")
            } else if let token = token {
                // save token
        }
    }
}

}

A payload is sent from a Firebase cloud function with a data object and I would like to access this data object and translate/localize the message sent.

I looked into several methods provided, but they seem to be about intercepting notifications only when the app is in the foreground, which is not what I am interested in.

The payload sent from the server:

const payload = {
    notification: {
        title: 'Friend request',
        body: senderName + ' wants to add you as a friend'
    },
    data: {
        senderUserId: friendRequestFrom,
        type: 'friendRequest'
    }
}

Solution

  • Because you are already using cloud functions, one way to accomplish that is to do the translation server-side with the Google Cloud Translation API. There is a good sample demonstrating how to do so with Node.js.

    Say for example you are sending the notifications when new objects get added to the /notifications path in your real-time database. You can do something like this:

    const Translate = require('@google-cloud/translate')
    const functions = require('firebase-functions')
    const projectId = 'YOUR_PROJECT_ID'
    const translate = new Translate({
      projectId: projectId,
    });
    const admin = require('firebase-admin')
    admin.initializeApp(functions.config().firebase)
    
    exports.sendNotification = functions.database.ref(`/notifications/{notif_id}`)
      .onWrite(event => {
        const notification = event.data.val()
        // Don't send when this isn't a new notification.
        if (event.data.previous.exists()) {
          return null
        }
        const user_id = notification.user_id
        getLocalLanguageOfUser(user_id).then(language => {
          if (language != 'en')
            translateTo(language, notification).then(localised => {
              return send(localised)
            }).catch(err => {
              return console.log(err)
            })
          } else { // it's English - no need to translate
            return send(notification)
          }
        })
    })
    
    function getLocalLanguageOfUser(user_id) {
      return new Promise((resolve, reject) => {
        // default will be 'en' for English
        firebase.database().ref(`users/${user_id}/language`)
          .once('value').then(snapshot => {
            resolve(snapshot.val() || 'en')
          })
          .catch(err => reject(err))
      })
    }
    
    function translateTo(language, notification) {
      return new Promise((resolve, reject) => {
        const text = notification.text;
        translate.translate(text, language).then(results => {
          const translation = results[0];
          resolve({
            ...notification,
            text: translation
          })
        }).catch(err => reject(err))
      })
    }
    
    function send(notification) {
      // use your current setup to send the notification.
      // 'text' key will already be localised.
    }