[polari] cleanup: Stop monkey-patching String.prototype
- From: Florian Müllner <fmuellner src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [polari] cleanup: Stop monkey-patching String.prototype
- Date: Fri, 13 Aug 2021 02:56:22 +0000 (UTC)
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]