[polari] cleanup: Stop monkey-patching String.prototype



commit 07edc92510aa901fd614024714a34a3ae4ebb7c0
Author: Florian Müllner <fmuellner gnome org>
Date:   Fri Aug 13 01:19:03 2021 +0200

    cleanup: Stop monkey-patching String.prototype
    
    Extending the standard type with a printf-style format() function
    is convenient, but dodgy. gjs now rightfully discourages that
    practice, so switch to using the vprintf() function from the
    Format module instead.
    
    https://gitlab.gnome.org/GNOME/polari/-/merge_requests/211

 lint/eslintrc-polari.yml |  1 +
 src/application.js       |  2 +-
 src/chatView.js          | 28 ++++++++++++++--------------
 src/connections.js       |  2 +-
 src/entryArea.js         | 26 ++++++++++++++------------
 src/ircParser.js         |  6 +++---
 src/main.js              |  4 +++-
 src/mainWindow.js        |  4 ++--
 src/roomList.js          | 12 ++++++------
 src/roomStack.js         |  6 +++---
 src/telepathyClient.js   |  9 +++++----
 src/userTracker.js       |  2 +-
 src/utils.js             | 28 ++++++++++++++--------------
 13 files changed, 68 insertions(+), 62 deletions(-)
---
diff --git a/lint/eslintrc-polari.yml b/lint/eslintrc-polari.yml
index a7ff1fcc..8698bf24 100644
--- a/lint/eslintrc-polari.yml
+++ b/lint/eslintrc-polari.yml
@@ -18,5 +18,6 @@ globals:
   C_: readonly
   N_: readonly
   ngettext: readonly
+  vprintf: readonly
 parserOptions:
   sourceType: module
diff --git a/src/application.js b/src/application.js
index 50b98fc3..296b6439 100644
--- a/src/application.js
+++ b/src/application.js
@@ -761,7 +761,7 @@ export default GObject.registerClass({
         await account.set_enabled_async(false);
         account.visible = false;
 
-        const label = _('%s removed.').format(account.display_name);
+        const label = vprintf(_('%s removed.'), account.display_name);
         const n = new AppNotifications.UndoNotification(label);
         this.notificationQueue.addNotification(n);
 
diff --git a/src/chatView.js b/src/chatView.js
index c06a75c4..eaeac07b 100644
--- a/src/chatView.js
+++ b/src/chatView.js
@@ -987,12 +987,12 @@ export default GObject.registerClass({
     }
 
     _onMemberRenamed(room, oldMember, newMember) {
-        let text = _('%s is now known as %s').format(oldMember.alias, newMember.alias);
+        let text = vprintf(_('%s is now known as %s'), oldMember.alias, newMember.alias);
         this._insertStatus(text, oldMember.alias, 'renamed');
     }
 
     _onMemberDisconnected(room, member, message) {
-        let text = _('%s has disconnected').format(member.alias);
+        let text = vprintf(_('%s has disconnected'), member.alias);
         if (message)
             text += ` (${message})`;
         this._insertStatus(text, member.alias, 'left');
@@ -1001,26 +1001,26 @@ export default GObject.registerClass({
     _onMemberKicked(room, member, actor) {
         let [kicked, kicker] = [member.alias, actor ? actor.alias : null];
         let msg = kicker
-            ? _('%s has been kicked by %s').format(kicked, kicker)
-            : _('%s has been kicked').format(kicked);
+            ? vprintf(_('%s has been kicked by %s'), kicked, kicker)
+            : vprintf(_('%s has been kicked'), kicked);
         this._insertStatus(msg, kicked, 'left');
     }
 
     _onMemberBanned(room, member, actor) {
         let [banned, banner] = [member.alias, actor ? actor.alias : null];
         let msg = banner
-            ? _('%s has been banned by %s').format(banned, banner)
-            : _('%s has been banned').format(banned);
+            ? vprintf(_('%s has been banned by %s'), banned, banner)
+            : vprintf(_('%s has been banned'), banned);
         this._insertStatus(msg, banned, 'left');
     }
 
     _onMemberJoined(room, member) {
-        let text = _('%s joined').format(member.alias);
+        let text = vprintf(_('%s joined'), member.alias);
         this._insertStatus(text, member.alias, 'joined');
     }
 
     _onMemberLeft(room, member, message) {
-        let text = _('%s left').format(member.alias);
+        let text = vprintf(_('%s left'), member.alias);
 
         if (message)
             text += ` (${message})`;
@@ -1115,18 +1115,18 @@ export default GObject.registerClass({
 
         let stats = [];
         if (this._statusCount.joined > 0) {
-            stats.push(
+            stats.push(vprintf(
                 ngettext(
                     '%d user joined',
-                    '%d users joined', this._statusCount.joined)
-                .format(this._statusCount.joined));
+                    '%d users joined', this._statusCount.joined),
+                this._statusCount.joined));
         }
         if (this._statusCount.left > 0) {
-            stats.push(
+            stats.push(vprintf(
                 ngettext(
                     '%d user left',
-                    '%d users left', this._statusCount.left)
-                .format(this._statusCount.left));
+                    '%d users left', this._statusCount.left),
+                this._statusCount.left));
         }
         // TODO: How do we update the arrow direction when text direction change?
         let iter = buffer.get_iter_at_mark(headerMark);
diff --git a/src/connections.js b/src/connections.js
index 45ee74ec..d921e4d4 100644
--- a/src/connections.js
+++ b/src/connections.js
@@ -513,7 +513,7 @@ export const ConnectionProperties = GObject.registerClass({
     _init(account) {
         /* Translators: %s is a connection name */
         super._init({
-            title: _('“%s” Properties').format(account.display_name),
+            title: vprintf(_('“%s” Properties'), account.display_name),
             use_header_bar: 1,
         });
 
diff --git a/src/entryArea.js b/src/entryArea.js
index d9042587..083dca9e 100644
--- a/src/entryArea.js
+++ b/src/entryArea.js
@@ -371,14 +371,16 @@ export default GObject.registerClass({
     }
 
     pasteText(text, nLines) {
-        this._confirmLabel.label = ngettext(
-            'Paste %s line of text to public paste service?',
-            'Paste %s lines of text to public paste service?', nLines)
-        .format(nLines);
-        this._uploadLabel.label = ngettext(
-            'Uploading %s line of text to public paste service…',
-            'Uploading %s lines of text to public paste service…', nLines)
-        .format(nLines);
+        this._confirmLabel.label = vprintf(
+            ngettext(
+                'Paste %s line of text to public paste service?',
+                'Paste %s lines of text to public paste service?', nLines),
+            nLines);
+        this._uploadLabel.label = vprintf(
+            ngettext(
+                'Uploading %s line of text to public paste service…',
+                'Uploading %s lines of text to public paste service…', nLines),
+            nLines);
         this._setPasteContent(text);
     }
 
@@ -401,9 +403,9 @@ export default GObject.registerClass({
 
         let name = fileInfo.get_display_name();
         /* Translators: %s is a filename */
-        this._confirmLabel.label = _('Upload “%s” to public paste service?').format(name);
+        this._confirmLabel.label = vprintf(_('Upload “%s” to public paste service?'), name);
         /* Translators: %s is a filename */
-        this._uploadLabel.label = _('Uploading “%s” to public paste service…').format(name);
+        this._uploadLabel.label = vprintf(_('Uploading “%s” to public paste service…'), name);
         this._setPasteContent(file);
     }
 
@@ -412,9 +414,9 @@ export default GObject.registerClass({
         let nick = this._room.channel.connection.self_contact.alias;
         if (this._room.type === Tp.HandleType.ROOM)
             /* translators: %s is a nick, #%s a channel */
-            title = _('%s in #%s').format(nick, this._room.display_name);
+            title = vprintf(_('%s in #%s'), nick, this._room.display_name);
         else
-            title = _('Paste from %s').format(nick);
+            title = vprintf(_('Paste from %s'), nick);
         this._confirmLabel.hide();
 
         this._confirmLabel.hide();
diff --git a/src/ircParser.js b/src/ircParser.js
index 1f4df73e..d2e60860 100644
--- a/src/ircParser.js
+++ b/src/ircParser.js
@@ -60,7 +60,7 @@ export default class IrcParser {
     }
 
     _createFeedbackUsage(cmd) {
-        return this._createFeedbackLabel(_('Usage: %s').format(_(knownCommands[cmd])));
+        return vprintf(this._createFeedbackLabel(_('Usage: %s'), _(knownCommands[cmd])));
     }
 
     _createFeedbackGrid(header, items) {
@@ -194,7 +194,7 @@ export default class IrcParser {
             let { channel } = this._room;
             let members = channel.group_dup_members_contacts().map(m => m.alias);
             output = this._createFeedbackGrid(
-                _('Users on %s:').format(channel.identifier), members);
+                vprintf(_('Users on %s:'), channel.identifier), members);
             break;
         }
         case 'NICK': {
@@ -310,7 +310,7 @@ export default class IrcParser {
                     [last] = info[i].field_value;
             }
         }
-        return _('User: %s - Last activity: %s').format(fn ? fn : user.alias, Utils.formatTimePassed(last));
+        return vprintf(_('User: %s - Last activity: %s'), fn ? fn : user.alias, 
Utils.formatTimePassed(last));
     }
 
     _sendText(text) {
diff --git a/src/main.js b/src/main.js
index 7cf26a3f..4d59ed4f 100755
--- a/src/main.js
+++ b/src/main.js
@@ -12,10 +12,12 @@ imports.package.init({
     libdir: Config.LIBDIR,
 });
 
-pkg.initFormat();
 pkg.initGettext();
 globalThis.ngettext = ngettext;
 
+// eslint-disable-next-line no-restricted-properties
+globalThis.vprintf = (fmt, ...args) => imports.format.vprintf(fmt, args);
+
 pkg.require({
     'GdkPixbuf': '2.0',
     'GObject': '2.0',
diff --git a/src/mainWindow.js b/src/mainWindow.js
index a9831b1b..a7c3d539 100644
--- a/src/mainWindow.js
+++ b/src/mainWindow.js
@@ -397,9 +397,9 @@ export default GObject.registerClass({
             this._room.channel.has_interface(Tp.IFACE_CHANNEL_INTERFACE_GROUP))
             numMembers = this._room.channel.group_dup_members_contacts().length;
 
-        let accessibleName = ngettext(
+        let accessibleName = vprintf(ngettext(
             '%d user',
-            '%d users', numMembers).format(numMembers);
+            '%d users', numMembers), numMembers);
         this._showUserListButton.get_accessible().set_name(accessibleName);
         this._showUserListButton.label = `${numMembers}`;
     }
diff --git a/src/roomList.js b/src/roomList.js
index 6b9274e8..d2081c0e 100644
--- a/src/roomList.js
+++ b/src/roomList.js
@@ -375,7 +375,7 @@ const RoomListHeader = GObject.registerClass({
         if (parent)
             parent.invalidate_sort();
 
-        let accessibleName = _('Network %s has an error').format(this._account.display_name);
+        let accessibleName = vprintf(_('Network %s has an error'), this._account.display_name);
         this.get_accessible().set_name(accessibleName);
     }
 
@@ -446,7 +446,7 @@ const RoomListHeader = GObject.registerClass({
 
             /* Translators: This is an account name followed by a
                server address, e.g. "GNOME (irc.gnome.org)" */
-            let fullTitle = _('%s (%s)').format(accountName, server);
+            let fullTitle = vprintf(_('%s (%s)'), accountName, server);
             this._popoverTitle.label = accountName === server ? accountName : fullTitle;
             this._popoverStatus.label = `<sup>${this._getStatusLabel()}<${'/'}sup>`;
         } else {
@@ -495,19 +495,19 @@ const RoomListHeader = GObject.registerClass({
         case Tp.error_get_dbus_name(Tp.Error.CERT_HOSTNAME_MISMATCH):
         case Tp.error_get_dbus_name(Tp.Error.CERT_FINGERPRINT_MISMATCH):
         case Tp.error_get_dbus_name(Tp.Error.CERT_SELF_SIGNED):
-            return _('Could not connect to %s in a safe way.').format(this._account.display_name);
+            return vprintf(_('Could not connect to %s in a safe way.'), this._account.display_name);
 
         case Tp.error_get_dbus_name(Tp.Error.AUTHENTICATION_FAILED):
-            return _('%s requires a password.').format(this._account.display_name);
+            return vprintf(_('%s requires a password.'), this._account.display_name);
 
         case Tp.error_get_dbus_name(Tp.Error.CONNECTION_FAILED):
         case Tp.error_get_dbus_name(Tp.Error.CONNECTION_LOST):
         case Tp.error_get_dbus_name(Tp.Error.CONNECTION_REPLACED):
         case Tp.error_get_dbus_name(Tp.Error.SERVICE_BUSY):
-            return _('Could not connect to %s. The server is busy.').format(this._account.display_name);
+            return vprintf(_('Could not connect to %s. The server is busy.'), this._account.display_name);
 
         default:
-            return _('Could not connect to %s.').format(this._account.display_name);
+            return vprintf(_('Could not connect to %s.'), this._account.display_name);
         }
     }
 });
diff --git a/src/roomStack.js b/src/roomStack.js
index cc00fa93..3106c401 100644
--- a/src/roomStack.js
+++ b/src/roomStack.js
@@ -100,9 +100,9 @@ class SavePasswordConfirmationBar extends MessageInfoBar {
         this._room = room;
 
         let title = _('Should the password be saved?');
-        let subtitle =
-            _('Identification will happen automatically the next time you connect to %s')
-            .format(this._room.account.display_name);
+        let subtitle = vprintf(
+            _('Identification will happen automatically the next time you connect to %s'),
+            this._room.account.display_name);
         super._init({ title, subtitle });
 
         this.connect('destroy', this._onDestroy.bind(this));
diff --git a/src/telepathyClient.js b/src/telepathyClient.js
index 155d1e8d..333f93d1 100644
--- a/src/telepathyClient.js
+++ b/src/telepathyClient.js
@@ -680,8 +680,9 @@ class TelepathyClient extends Tp.BaseClient {
         let accountName = room.account.display_name;
         /* Translators: Those are a botname and an accountName, e.g.
            "Save NickServ password for GNOME" */
-        let summary = _('Save %s password for %s?').format(data.botname, accountName);
-        let text = _('Identification will happen automatically the next time you connect to 
%s').format(accountName);
+        let summary = vprintf(_('Save %s password for %s?'), data.botname, accountName);
+        let text = vprintf(
+            _('Identification will happen automatically the next time you connect to %s'), accountName);
         let notification = this._createNotification(room, summary, text);
 
         notification.add_button_with_target(_('Save'),
@@ -716,11 +717,11 @@ class TelepathyClient extends Tp.BaseClient {
         let summary;
 
         if (room.type === Tp.HandleType.CONTACT) {
-            summary = '%s'.format(nick);
+            summary = vprintf('%s', nick);
         } else {
             /* Translators: This is the title of the notification announcing a newly
                received message, in the form "user-nickname in room-display-name" */
-            summary = _('%s in %s').format(nick, room.display_name);
+            summary = vprintf(_('%s in %s'), nick, room.display_name);
         }
 
         let notification = this._createNotification(room, summary, text);
diff --git a/src/userTracker.js b/src/userTracker.js
index 1881138a..ec4a25fa 100644
--- a/src/userTracker.js
+++ b/src/userTracker.js
@@ -369,7 +369,7 @@ const UserTracker = GObject.registerClass({
     _notifyNickAvailable(member, room) {
         let notification = new Gio.Notification();
         notification.set_title(_('User is online'));
-        notification.set_body(_('User %s is now online.').format(member.alias));
+        vprintf(notification.set_body(_('User %s is now online.'), member.alias));
 
         let param = GLib.Variant.new('(ssu)', [
             this._account.get_object_path(),
diff --git a/src/utils.js b/src/utils.js
index 0796c55c..cbfea169 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -170,12 +170,12 @@ export function getTpEventTime() {
 }
 
 export function storeAccountPassword(account, password) {
-    let label = _('Polari server password for %s').format(account.display_name);
+    let label = vprintf(_('Polari server password for %s'), account.display_name);
     _storePassword(SECRET_SCHEMA_ACCOUNT, label, account, password);
 }
 
 export function storeIdentifyPassword(account, password) {
-    let label = _('Polari NickServ password for %s').format(account.display_name);
+    let label = vprintf(_('Polari NickServ password for %s'), account.display_name);
     _storePassword(SECRET_SCHEMA_IDENTIFY, label, account, password);
 }
 
@@ -389,41 +389,41 @@ export function formatTimePassed(seconds) {
         return _('Unavailable');
 
     if (seconds < 60) {
-        return ngettext(
+        return vprintf(ngettext(
             '%d second ago',
-            '%d seconds ago', seconds).format(seconds);
+            '%d seconds ago', seconds), seconds);
     }
 
     let minutes = seconds / 60;
     if (minutes < 60) {
-        return ngettext(
+        return vprintf(ngettext(
             '%d minute ago',
-            '%d minutes ago', minutes).format(minutes);
+            '%d minutes ago', minutes), minutes);
     }
 
     let hours = minutes / 60;
     if (hours < 24) {
-        return ngettext(
+        return vprintf(ngettext(
             '%d hour ago',
-            '%d hours ago', hours).format(hours);
+            '%d hours ago', hours), hours);
     }
 
     let days = hours / 24;
     if (days < 7) {
-        return ngettext(
+        return vprintf(ngettext(
             '%d day ago',
-            '%d days ago', days).format(days);
+            '%d days ago', days), days);
     }
 
     let weeks = days / 7;
     if (days < 30) {
-        return ngettext(
+        return vprintf(ngettext(
             '%d week ago',
-            '%d weeks ago', weeks).format(weeks);
+            '%d weeks ago', weeks), weeks);
     }
 
     let months = days / 30;
-    return ngettext(
+    return vprintf(ngettext(
         '%d month ago',
-        '%d months ago', months).format(months);
+        '%d months ago', months), months);
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]