From 1deb13e1aaabfd04b2641976a224b6fc2be3b9ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Sun, 12 Apr 2020 02:45:55 +0200 Subject: [PATCH] extensionUtils: Add gettext convenience helpers We have initTranslations() for binding an extension's gettext domain, but nothing to help with using gettext from an extension. Such help would be useful though, as an extension that calls textdomain() like a normal application would inadvertently changes the default domain for the whole gnome-shell process. Instead, extensions have to use domain-specific versions of the gettext functions: ```js const Gettext = imports.gettext.domain('my-extension'); const _ = Gettext.gettext; ``` Make this a bit easier by adding those functions directly to the extensions object when initTranslations() is called, then expose helper functions for calling them. https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2594 Part-of: --- js/misc/extensionUtils.js | 63 ++++++++++++++++++- lint/eslintrc-shell.yml | 1 + .../src/templates/indicator/extension.js | 5 +- 3 files changed, 64 insertions(+), 5 deletions(-) diff --git a/js/misc/extensionUtils.js b/js/misc/extensionUtils.js index a8133d8a2..c86468e4b 100644 --- a/js/misc/extensionUtils.js +++ b/js/misc/extensionUtils.js @@ -1,7 +1,8 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- /* exported ExtensionState, ExtensionType, getCurrentExtension, - getSettings, initTranslations, openPrefs, isOutOfDate, - installImporter, serializeExtension, deserializeExtension */ + getSettings, initTranslations, gettext, ngettext, pgettext, + openPrefs, isOutOfDate, installImporter, serializeExtension, + deserializeExtension */ // Common utils for the extension system and the extension // preferences tool @@ -112,6 +113,64 @@ function initTranslations(domain) { Gettext.bindtextdomain(domain, localeDir.get_path()); else Gettext.bindtextdomain(domain, Config.LOCALEDIR); + + Object.assign(extension, Gettext.domain(domain)); +} + +/** + * gettext: + * @param {string} str - the string to translate + * + * Translate @str using the extension's gettext domain + * + * @returns {string} - the translated string + * + */ +function gettext(str) { + return callExtensionGettextFunc('gettext', str); +} + +/** + * ngettext: + * @param {string} str - the string to translate + * @param {string} strPlural - the plural form of the string + * @param {number} n - the quantity for which translation is needed + * + * Translate @str and choose plural form using the extension's + * gettext domain + * + * @returns {string} - the translated string + * + */ +function ngettext(str, strPlural, n) { + return callExtensionGettextFunc('ngettext', str, strPlural, n); +} + +/** + * pgettext: + * @param {string} context - context to disambiguate @str + * @param {string} str - the string to translate + * + * Translate @str in the context of @context using the extension's + * gettext domain + * + * @returns {string} - the translated string + * + */ +function pgettext(context, str) { + return callExtensionGettextFunc('pgettext', context, str); +} + +function callExtensionGettextFunc(func, ...args) { + const extension = getCurrentExtension(); + + if (!extension) + throw new Error(`${func}() can only be called from extensions`); + + if (!extension[func]) + throw new Error(`${func}() is used without calling initTranslations() first`); + + return extension[func](...args); } /** diff --git a/lint/eslintrc-shell.yml b/lint/eslintrc-shell.yml index bb0636f02..42a829a63 100644 --- a/lint/eslintrc-shell.yml +++ b/lint/eslintrc-shell.yml @@ -18,6 +18,7 @@ overrides: - files: js/** excludedFiles: - js/portalHelper/* + - js/misc/extensionUtils.js globals: global: readonly _: readonly diff --git a/subprojects/extensions-tool/src/templates/indicator/extension.js b/subprojects/extensions-tool/src/templates/indicator/extension.js index 5d9753efc..9ed2c385c 100644 --- a/subprojects/extensions-tool/src/templates/indicator/extension.js +++ b/subprojects/extensions-tool/src/templates/indicator/extension.js @@ -22,14 +22,13 @@ const GETTEXT_DOMAIN = 'my-indicator-extension'; const { GObject, St } = imports.gi; -const Gettext = imports.gettext.domain(GETTEXT_DOMAIN); -const _ = Gettext.gettext; - const ExtensionUtils = imports.misc.extensionUtils; const Main = imports.ui.main; const PanelMenu = imports.ui.panelMenu; const PopupMenu = imports.ui.popupMenu; +const _ = ExtensionUtils.gettext; + const Indicator = GObject.registerClass( class Indicator extends PanelMenu.Button { _init() {