diff --git a/.gitignore b/.gitignore index 113fdca04d..60fbd34427 100644 --- a/.gitignore +++ b/.gitignore @@ -94,8 +94,8 @@ coverage.xml .hypothesis/ .mypy_cache/ -# Translations -*.mo +# Translations compiled during packaging: +securedrop/translations/**/*.mo # Flask stuff: instance/ diff --git a/install_files/ansible-base/roles/tails-config/defaults/main.yml b/install_files/ansible-base/roles/tails-config/defaults/main.yml index 3d468feecb..4c37d1f5c4 100644 --- a/install_files/ansible-base/roles/tails-config/defaults/main.yml +++ b/install_files/ansible-base/roles/tails-config/defaults/main.yml @@ -24,6 +24,10 @@ tails_config_desktop_icon_directories: - "{{ tails_config_amnesia_home }}/.local/share/applications" - "{{ tails_config_live_dotfiles }}/.local/share/applications" +# Destination directories for storing the SecureDrop GNOME Shell extension +tails_config_extension_directories: + - "{{ tails_config_live_dotfiles }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/" + # Path for storing site-specific ATHS info for connecting to Journalist Interface. tails_config_torrc_additions: "{{ tails_config_securedrop_dotfiles }}/torrc_additions" diff --git a/install_files/ansible-base/roles/tails-config/files/securedrop-symbolic.png b/install_files/ansible-base/roles/tails-config/files/securedrop-symbolic.png new file mode 100644 index 0000000000..3c78d8ec5a Binary files /dev/null and b/install_files/ansible-base/roles/tails-config/files/securedrop-symbolic.png differ diff --git a/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/metadata.json b/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/metadata.json new file mode 100644 index 0000000000..385bd7c82b --- /dev/null +++ b/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/metadata.json @@ -0,0 +1,12 @@ +{ + "name": "SecureDrop", + "description": "SecureDrop Utility Menu", + "uuid": "securedrop@securedrop.freedom.press", + "shell-version": [ + "3.38", + "40", + "41", + "42", + "43" + ] +} diff --git a/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/stylesheet.css b/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/stylesheet.css new file mode 100644 index 0000000000..37b93f2191 --- /dev/null +++ b/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/stylesheet.css @@ -0,0 +1 @@ +/* Add your custom extension styling here */ diff --git a/install_files/ansible-base/roles/tails-config/files/securedrop_init.py b/install_files/ansible-base/roles/tails-config/files/securedrop_init.py index b78577837c..b8dcd9911b 100644 --- a/install_files/ansible-base/roles/tails-config/files/securedrop_init.py +++ b/install_files/ansible-base/roles/tails-config/files/securedrop_init.py @@ -128,6 +128,9 @@ if is_tails: subprocess.call(["gnome-shell-extension-tool", "-r", "desktop-icons@csoriano"], env=env) +# enable the GNOME Shell Extension +subprocess.call(["gnome-extensions", "enable", "securedrop@securedrop.freedom.press"], env=env) + # reacquire uid0 and notify the user os.setresuid(0, 0, -1) os.setresgid(0, 0, -1) diff --git a/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml b/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml new file mode 100644 index 0000000000..fb5327bf5b --- /dev/null +++ b/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml @@ -0,0 +1,123 @@ +--- +- name: Check for v3 Source Interface file + stat: + path: app-sourcev3-ths + register: v3_source_file + +- name: Check for v3 Journalist Interface file + stat: + path: app-journalist.auth_private + register: v3_journalist_file + +- name: Check for site specific file + stat: + path: group_vars/all/site-specific + register: site_specific_file + +- name: Look up v3 Source Interface URL. + command: grep -Po '.{56}\.onion' app-sourcev3-ths + changed_when: false + register: sourcev3_interface_lookup_result + when: v3_source_file.stat.exists == true + +- name: Look up v3 Journalist Interface URL. + command: awk -F ':' '{print $1 ".onion"}' app-journalist.auth_private + changed_when: false + register: journalistv3_interface_lookup_result + when: v3_source_file.stat.exists == true + +- name: Look up app server hostname + command: "awk -v FS='app_hostname: ' 'NF>1{print $2}' group_vars/all/site-specific" + changed_when: false + register: app_server_lookup_result + when: site_specific_file.stat.exists == true + +- name: Look up mon server hostname + command: "awk -v FS='monitor_hostname: ' 'NF>1{print $2}' /home/amnesia/Persistent/securedrop/install_files/ansible-base/group_vars/all/site-specific" + changed_when: false + register: mon_server_lookup_result + when: site_specific_file.stat.exists == true + +- name: Create the SecureDrop GNOME Shell Extension directories + file: + state: directory + path: "{{ item }}" + with_items: "{{ tails_config_extension_directories }}" + +- name: Set normal user ownership on subset of directories. + become: yes + file: + state: directory + path: "{{ item }}" + owner: amnesia + group: amnesia + # Only set normal user ownership for files in ~amnesia. + when: item.startswith(tails_config_amnesia_home) + with_items: "{{ tails_config_extension_directories }}" + +- name: Copy the extension metadata to the extension directory in Persistent Storage + become: yes + copy: + src: securedrop@securedrop.freedom.press/metadata.json + dest: "{{ tails_config_live_dotfiles }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/" + owner: amnesia + group: amnesia + +- name: Copy the extension CSS to the extension directory in Persistent Storage + become: yes + copy: + src: securedrop@securedrop.freedom.press/stylesheet.css + dest: "{{ tails_config_live_dotfiles }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/" + owner: amnesia + group: amnesia + +- name: Copy the symbolic icon used for the shell extension in Persistent Storage + become: yes + copy: + src: securedrop-symbolic.png + dest: "{{ tails_config_live_dotfiles }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/icons/" + owner: amnesia + group: amnesia + +- name: Set the right variable for source + set_fact: + source_iface: "{{ sourcev3_interface_lookup_result }}" + +- name: Set the right variable for journalist + set_fact: + journalist_iface: "{{ journalistv3_interface_lookup_result }}" + +- name: Set the right variable for app server hostname + set_fact: + app_hostname: "{{ app_server_lookup_result }}" + +- name: Set the right variable for app server hostname + set_fact: + mon_hostname: "{{ mon_server_lookup_result }}" + +- name: Assemble interface information for extension + set_fact: + _securedrop_extension_info: + - src: extension.js.in + filename: extension.js + source_interface_address: "{{ source_iface.stdout }}" + journalist_interface_address: "{{ journalist_iface.stdout }}" + app_hostname: "{{ app_hostname.stdout }}" + mon_hostname: "{{ mon_hostname.stdout }}" + +- name: Create SecureDrop extension + become: yes + template: + src: "{{ item.0.src }}" + dest: "{{ item.1 }}/{{ item.0.filename }}" + owner: amnesia + group: amnesia + mode: "0700" + with_nested: + - "{{ _securedrop_extension_info }}" + - "{{ tails_config_extension_directories }}" + +- name: Add extension translations in Persistent Storage + synchronize: + src: roles/tails-config/templates/locale/ + dest: "{{ tails_config_live_dotfiles }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/locale/" diff --git a/install_files/ansible-base/roles/tails-config/tasks/main.yml b/install_files/ansible-base/roles/tails-config/tasks/main.yml index c4508a68ae..542ca910e3 100644 --- a/install_files/ansible-base/roles/tails-config/tasks/main.yml +++ b/install_files/ansible-base/roles/tails-config/tasks/main.yml @@ -8,6 +8,8 @@ - include: create_desktop_shortcuts.yml +- include: install_shell_extension.yml + - include: configure_network_hook.yml - name: Check that we are on an admin workstation diff --git a/install_files/ansible-base/roles/tails-config/templates/ar.po b/install_files/ansible-base/roles/tails-config/templates/ar.po index 2899a36cfc..ded47b45d4 100644 --- a/install_files/ansible-base/roles/tails-config/templates/ar.po +++ b/install_files/ansible-base/roles/tails-config/templates/ar.po @@ -19,6 +19,27 @@ msgstr "" "&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n" "X-Generator: Weblate 2.20\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "واجهة SecureDrop للصحفيين" diff --git a/install_files/ansible-base/roles/tails-config/templates/ca.po b/install_files/ansible-base/roles/tails-config/templates/ca.po index 85a9bfb564..9bbf8fcf4c 100644 --- a/install_files/ansible-base/roles/tails-config/templates/ca.po +++ b/install_files/ansible-base/roles/tails-config/templates/ca.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 3.4\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "Interfície de periodista del SecureDrop" diff --git a/install_files/ansible-base/roles/tails-config/templates/cs.po b/install_files/ansible-base/roles/tails-config/templates/cs.po index 537171104d..c4ccca05c1 100644 --- a/install_files/ansible-base/roles/tails-config/templates/cs.po +++ b/install_files/ansible-base/roles/tails-config/templates/cs.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" "X-Generator: Weblate 3.7.1\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "SecureDrop rozhraní novináře" diff --git a/install_files/ansible-base/roles/tails-config/templates/de_DE.po b/install_files/ansible-base/roles/tails-config/templates/de_DE.po index afc5fb2ebb..df4f87deb9 100644 --- a/install_files/ansible-base/roles/tails-config/templates/de_DE.po +++ b/install_files/ansible-base/roles/tails-config/templates/de_DE.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 2.17.1\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "Journalistenschnittstelle für SecureDrop" diff --git a/install_files/ansible-base/roles/tails-config/templates/desktop.pot b/install_files/ansible-base/roles/tails-config/templates/desktop.pot index 524987d447..c1ee0f43fe 100644 --- a/install_files/ansible-base/roles/tails-config/templates/desktop.pot +++ b/install_files/ansible-base/roles/tails-config/templates/desktop.pot @@ -13,9 +13,30 @@ msgstr "" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=CHARSET\n" +"Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "" diff --git a/install_files/ansible-base/roles/tails-config/templates/el.po b/install_files/ansible-base/roles/tails-config/templates/el.po index 2e90927a9e..0fb7fce83e 100644 --- a/install_files/ansible-base/roles/tails-config/templates/el.po +++ b/install_files/ansible-base/roles/tails-config/templates/el.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 2.20\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "Διεπαφή δημοσιογράφου του SecureDrop" diff --git a/install_files/ansible-base/roles/tails-config/templates/es_ES.po b/install_files/ansible-base/roles/tails-config/templates/es_ES.po index ccb841eb22..accdb186a9 100644 --- a/install_files/ansible-base/roles/tails-config/templates/es_ES.po +++ b/install_files/ansible-base/roles/tails-config/templates/es_ES.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 2.20\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "Interfaz de periodista de SecureDrop" diff --git a/install_files/ansible-base/roles/tails-config/templates/extension.js.in b/install_files/ansible-base/roles/tails-config/templates/extension.js.in new file mode 100644 index 0000000000..91253dd426 --- /dev/null +++ b/install_files/ansible-base/roles/tails-config/templates/extension.js.in @@ -0,0 +1,143 @@ +/* exported init */ + +const GETTEXT_DOMAIN = 'messages'; + +const {Clutter, GObject, GLib } = imports.gi; + +const Util = imports.misc.util; +const ExtensionUtils = imports.misc.extensionUtils; +const Main = imports.ui.main; +const PanelMenu = imports.ui.panelMenu; +const PopupMenu = imports.ui.popupMenu; + +const St = imports.gi.St; +const Gettext = imports.gettext; +const CurrentExtension = imports.misc.extensionUtils.getCurrentExtension(); +const Gio = imports.gi.Gio; + +const Domain = Gettext.domain(GETTEXT_DOMAIN) + +const source_interface_address = "{{ item.0.source_interface_address }}"; +const journalist_interface_address = "{{ item.0.journalist_interface_address }}"; +const app_server_hostname = "{{ item.0.app_hostname }}"; +const mon_server_hostname = "{{ item.0.mon_hostname }}"; + +const _ = Domain.gettext; + +const Indicator = GObject.registerClass( +class Indicator extends PanelMenu.Button { + _init() { + super._init(0.0, 'SecureDrop'); + + // Check for SSH onion service client authentication keys - + // if they don't exist, this is a Journalist workstation + // (and therefore the admin options should remain hidden) + let is_admin = false; + let [ok, out, err, exit] = GLib.spawn_command_line_sync('/bin/bash -c "test -f ~/Persistent/securedrop/install_files/ansible-base/tor_v3_keys.json"'); + if (exit == 0) { + is_admin = true; + } + + let gicon = Gio.icon_new_for_string(CurrentExtension.path + "/icons/securedrop-symbolic.png"); + let icon = new St.Icon({ gicon }); + icon.icon_size = 18; + icon.height = 18; + icon.width = 18; + + let label = new St.Label({ + text: 'SecureDrop', + y_expand: false, + y_align: Clutter.ActorAlign.CENTER, + }); + + let topBox = new St.BoxLayout({ + style_class: 'panel-status-menu-box' + }); + + topBox.add_child(icon); + topBox.add_child(label); + this.add_child(topBox); + + let source = new PopupMenu.PopupMenuItem(_('Launch Source Interface')); + source.connect('activate', () => { + Util.spawn(['tor-browser', source_interface_address]); + }); + + let journalist = new PopupMenu.PopupMenuItem(_('Launch Journalist Interface')); + journalist.connect('activate', () => { + Util.spawn(['tor-browser', journalist_interface_address]); + }); + + let admin_label = new St.Label({ + text: 'Admin Actions', + y_expand: true, + y_align: Clutter.ActorAlign.START, + }); + + let updates = new PopupMenu.PopupMenuItem(_('Check for SecureDrop Updates')); + updates.connect('activate', () => { + Util.spawn(['python3', '/home/amnesia/Persistent/securedrop/journalist_gui/SecureDropUpdater']); + }); + + let app_server_ssh = new PopupMenu.PopupMenuItem(_('SSH into the App Server')); + app_server_ssh.connect('activate', () => { + Util.trySpawnCommandLine(`gnome-terminal -- ssh ` + app_server_hostname); + }); + + let mon_server_ssh = new PopupMenu.PopupMenuItem(_('SSH into the Monitor Server')); + mon_server_ssh.connect('activate', () => { + Util.trySpawnCommandLine(`gnome-terminal -- ssh ` + mon_server_hostname); + }); + + let keypass = new PopupMenu.PopupMenuItem(_('Open KeePassXC Password Vault')); + keypass.connect('activate', () => { + Util.trySpawnCommandLine(`keepassxc`); + }); + + let filebrowser = new PopupMenu.PopupMenuItem(_('Open File Browser')); + filebrowser.connect('activate', () => { + Util.trySpawnCommandLine(`xdg-open /home/amnesia/Persistent`); + }); + + this.menu.addMenuItem(source); + this.menu.addMenuItem(journalist); + this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + this.menu.addMenuItem(updates); + if (is_admin) { + this.menu.addMenuItem(app_server_ssh); + this.menu.addMenuItem(mon_server_ssh); + } + this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + this.menu.addMenuItem(keypass); + this.menu.addMenuItem(filebrowser); + } +}); + +class Extension { + constructor(uuid) { + this._uuid = uuid; + + ExtensionUtils.initTranslations(GETTEXT_DOMAIN); + } + + enable() { + this._indicator = new Indicator(); + + // Position is a zero-based index of where to put the extension + // in the status bar. Index 3, in Tails, would be to the right + // of the 'Places' Menu (Activites, Applicatons, Places, SD) + let pos = 3; + if ('apps-menu' in Main.panel.statusArea) + pos++; + Main.panel.addToStatusArea(this._uuid, this._indicator, pos, 'left'); + } + + disable() { + this._indicator.destroy(); + this._indicator = null; + } +} + +function init(meta) { + return new Extension(meta.uuid); +} diff --git a/install_files/ansible-base/roles/tails-config/templates/fr.po b/install_files/ansible-base/roles/tails-config/templates/fr.po index 6aad8d6935..8589fb1f38 100644 --- a/install_files/ansible-base/roles/tails-config/templates/fr.po +++ b/install_files/ansible-base/roles/tails-config/templates/fr.po @@ -19,6 +19,27 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n > 1;\n" "X-Generator: Weblate 2.14.1\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "SecureDrop - Interface des journalistes" diff --git a/install_files/ansible-base/roles/tails-config/templates/hi.po b/install_files/ansible-base/roles/tails-config/templates/hi.po index 8697f96d74..142c2c407b 100644 --- a/install_files/ansible-base/roles/tails-config/templates/hi.po +++ b/install_files/ansible-base/roles/tails-config/templates/hi.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 2.18\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "SecureDrop पत्रकार अंतराफलक" diff --git a/install_files/ansible-base/roles/tails-config/templates/is.po b/install_files/ansible-base/roles/tails-config/templates/is.po index c60c0b84ee..1124bd35a8 100644 --- a/install_files/ansible-base/roles/tails-config/templates/is.po +++ b/install_files/ansible-base/roles/tails-config/templates/is.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n % 10 != 1 || n % 100 == 11;\n" "X-Generator: Weblate 3.4\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "Blaðamannaviðmót SecureDrop" diff --git a/install_files/ansible-base/roles/tails-config/templates/it.po b/install_files/ansible-base/roles/tails-config/templates/it.po index c186161961..bca9c254cb 100644 --- a/install_files/ansible-base/roles/tails-config/templates/it.po +++ b/install_files/ansible-base/roles/tails-config/templates/it.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 2.18\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "Interfaccia Giornalista di SecureDrop" diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/ar/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/ar/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000..93d1746894 Binary files /dev/null and b/install_files/ansible-base/roles/tails-config/templates/locale/ar/LC_MESSAGES/messages.mo differ diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/ca/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/ca/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000..bba4100cec Binary files /dev/null and b/install_files/ansible-base/roles/tails-config/templates/locale/ca/LC_MESSAGES/messages.mo differ diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/cs/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/cs/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000..483611a9c5 Binary files /dev/null and b/install_files/ansible-base/roles/tails-config/templates/locale/cs/LC_MESSAGES/messages.mo differ diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/de_DE/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/de_DE/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000..52bb5575aa Binary files /dev/null and b/install_files/ansible-base/roles/tails-config/templates/locale/de_DE/LC_MESSAGES/messages.mo differ diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/el/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/el/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000..817e383de6 Binary files /dev/null and b/install_files/ansible-base/roles/tails-config/templates/locale/el/LC_MESSAGES/messages.mo differ diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/es_ES/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/es_ES/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000..d1f26c7c80 Binary files /dev/null and b/install_files/ansible-base/roles/tails-config/templates/locale/es_ES/LC_MESSAGES/messages.mo differ diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/fr/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/fr/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000..0ab3f8158b Binary files /dev/null and b/install_files/ansible-base/roles/tails-config/templates/locale/fr/LC_MESSAGES/messages.mo differ diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/hi/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/hi/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000..94f32a8a36 Binary files /dev/null and b/install_files/ansible-base/roles/tails-config/templates/locale/hi/LC_MESSAGES/messages.mo differ diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/is/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/is/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000..15ba8a0c7b Binary files /dev/null and b/install_files/ansible-base/roles/tails-config/templates/locale/is/LC_MESSAGES/messages.mo differ diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/it/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/it/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000..877c79831b Binary files /dev/null and b/install_files/ansible-base/roles/tails-config/templates/locale/it/LC_MESSAGES/messages.mo differ diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/nb_NO/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/nb_NO/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000..3d5cee314a Binary files /dev/null and b/install_files/ansible-base/roles/tails-config/templates/locale/nb_NO/LC_MESSAGES/messages.mo differ diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/nl/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/nl/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000..1e9218e991 Binary files /dev/null and b/install_files/ansible-base/roles/tails-config/templates/locale/nl/LC_MESSAGES/messages.mo differ diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/pt_BR/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/pt_BR/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000..56130695b4 Binary files /dev/null and b/install_files/ansible-base/roles/tails-config/templates/locale/pt_BR/LC_MESSAGES/messages.mo differ diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/pt_PT/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/pt_PT/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000..6b4c48d737 Binary files /dev/null and b/install_files/ansible-base/roles/tails-config/templates/locale/pt_PT/LC_MESSAGES/messages.mo differ diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/ro/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/ro/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000..b8afb7a50f Binary files /dev/null and b/install_files/ansible-base/roles/tails-config/templates/locale/ro/LC_MESSAGES/messages.mo differ diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/ru/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/ru/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000..71cbbd05b2 Binary files /dev/null and b/install_files/ansible-base/roles/tails-config/templates/locale/ru/LC_MESSAGES/messages.mo differ diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/sk/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/sk/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000..e0fb30b2ec Binary files /dev/null and b/install_files/ansible-base/roles/tails-config/templates/locale/sk/LC_MESSAGES/messages.mo differ diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/sv/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/sv/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000..8d780725d8 Binary files /dev/null and b/install_files/ansible-base/roles/tails-config/templates/locale/sv/LC_MESSAGES/messages.mo differ diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/tr/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/tr/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000..6c097ca793 Binary files /dev/null and b/install_files/ansible-base/roles/tails-config/templates/locale/tr/LC_MESSAGES/messages.mo differ diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/zh_Hans/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/zh_Hans/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000..faae4bbad1 Binary files /dev/null and b/install_files/ansible-base/roles/tails-config/templates/locale/zh_Hans/LC_MESSAGES/messages.mo differ diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/zh_Hant/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/zh_Hant/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000..0272019ce3 Binary files /dev/null and b/install_files/ansible-base/roles/tails-config/templates/locale/zh_Hant/LC_MESSAGES/messages.mo differ diff --git a/install_files/ansible-base/roles/tails-config/templates/nb_NO.po b/install_files/ansible-base/roles/tails-config/templates/nb_NO.po index c7b6140082..11d48151a5 100644 --- a/install_files/ansible-base/roles/tails-config/templates/nb_NO.po +++ b/install_files/ansible-base/roles/tails-config/templates/nb_NO.po @@ -19,6 +19,27 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 2.14.1\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "Journalistgrensesnitt for SecureDrop" diff --git a/install_files/ansible-base/roles/tails-config/templates/nl.po b/install_files/ansible-base/roles/tails-config/templates/nl.po index 9f01083cc4..e99ade9c8c 100644 --- a/install_files/ansible-base/roles/tails-config/templates/nl.po +++ b/install_files/ansible-base/roles/tails-config/templates/nl.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 2.17.1\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "SecureDrop - interface voor journalisten" diff --git a/install_files/ansible-base/roles/tails-config/templates/pt_BR.po b/install_files/ansible-base/roles/tails-config/templates/pt_BR.po index 2cc4e9c8a0..4e340fdc1b 100644 --- a/install_files/ansible-base/roles/tails-config/templates/pt_BR.po +++ b/install_files/ansible-base/roles/tails-config/templates/pt_BR.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n > 1;\n" "X-Generator: Weblate 2.20\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "Interface de Jornalista do SecureDrop" diff --git a/install_files/ansible-base/roles/tails-config/templates/pt_PT.po b/install_files/ansible-base/roles/tails-config/templates/pt_PT.po index 8b07b30124..0ccfd71404 100644 --- a/install_files/ansible-base/roles/tails-config/templates/pt_PT.po +++ b/install_files/ansible-base/roles/tails-config/templates/pt_PT.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n > 1;\n" "X-Generator: Weblate 4.11.2\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "Interface de Jornalista do SecureDrop" diff --git a/install_files/ansible-base/roles/tails-config/templates/ro.po b/install_files/ansible-base/roles/tails-config/templates/ro.po index 5d1abfc90e..ac3fde426d 100644 --- a/install_files/ansible-base/roles/tails-config/templates/ro.po +++ b/install_files/ansible-base/roles/tails-config/templates/ro.po @@ -19,6 +19,27 @@ msgstr "" "20)) ? 1 : 2;\n" "X-Generator: Weblate 2.18\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "SecureDrop - interfața pentru jurnaliști" diff --git a/install_files/ansible-base/roles/tails-config/templates/ru.po b/install_files/ansible-base/roles/tails-config/templates/ru.po index 0dce7c4e61..5a56d97909 100644 --- a/install_files/ansible-base/roles/tails-config/templates/ru.po +++ b/install_files/ansible-base/roles/tails-config/templates/ru.po @@ -19,6 +19,27 @@ msgstr "" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" "X-Generator: Weblate 4.6\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "SecureDrop — интерфейс журналиста" diff --git a/install_files/ansible-base/roles/tails-config/templates/sk.po b/install_files/ansible-base/roles/tails-config/templates/sk.po index 727d50f238..74a084dd08 100644 --- a/install_files/ansible-base/roles/tails-config/templates/sk.po +++ b/install_files/ansible-base/roles/tails-config/templates/sk.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" "X-Generator: Weblate 3.7.1\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "SecureDrop rozhranie novinára" diff --git a/install_files/ansible-base/roles/tails-config/templates/sv.po b/install_files/ansible-base/roles/tails-config/templates/sv.po index 2747a26c64..032c670ab6 100644 --- a/install_files/ansible-base/roles/tails-config/templates/sv.po +++ b/install_files/ansible-base/roles/tails-config/templates/sv.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 2.18\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "SecureDrop journalistgränssnitt" diff --git a/install_files/ansible-base/roles/tails-config/templates/tr.po b/install_files/ansible-base/roles/tails-config/templates/tr.po index dd37bde8ae..f7755086a4 100644 --- a/install_files/ansible-base/roles/tails-config/templates/tr.po +++ b/install_files/ansible-base/roles/tails-config/templates/tr.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 2.18\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "SecureDrop Gazeteci Arayüzü" diff --git a/install_files/ansible-base/roles/tails-config/templates/zh_Hans.po b/install_files/ansible-base/roles/tails-config/templates/zh_Hans.po index ea1f4694fb..be26afcf85 100644 --- a/install_files/ansible-base/roles/tails-config/templates/zh_Hans.po +++ b/install_files/ansible-base/roles/tails-config/templates/zh_Hans.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Weblate 3.10.3\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "SecureDrop 记者界面" diff --git a/install_files/ansible-base/roles/tails-config/templates/zh_Hant.po b/install_files/ansible-base/roles/tails-config/templates/zh_Hant.po index 8dec7ce973..c9d7bfcd29 100644 --- a/install_files/ansible-base/roles/tails-config/templates/zh_Hant.po +++ b/install_files/ansible-base/roles/tails-config/templates/zh_Hant.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Weblate 2.18\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "SecureDrop 記者使用介面" diff --git a/install_files/ansible-base/securedrop-tails.yml b/install_files/ansible-base/securedrop-tails.yml index 07909a939f..6f192c3199 100755 --- a/install_files/ansible-base/securedrop-tails.yml +++ b/install_files/ansible-base/securedrop-tails.yml @@ -19,6 +19,7 @@ msg: >- Successfully configured Tor and set up desktop bookmarks for SecureDrop! You will see a notification appear on your screen when Tor is ready. + Please reboot your Workstation to take advantage of the SecureDrop Menu. The Journalist Interface's Tor onion URL is: http://{{ journalist_iface.stdout }} The Source Interfaces's Tor onion URL is: http://{{ source_iface.stdout }} diff --git a/securedrop/babel.cfg b/securedrop/babel.cfg index 52ae100b04..061374b5b6 100644 --- a/securedrop/babel.cfg +++ b/securedrop/babel.cfg @@ -10,3 +10,6 @@ silent=False [jinja2: */*.html] silent=False extensions=jinja2.ext.autoescape,jinja2.ext.with_,jinja2.ext.do + +[javascript: **.js.in] +extract_messages = $._, jQuery._ diff --git a/securedrop/i18n_tool.py b/securedrop/i18n_tool.py index 95a4b46b73..89e5bed536 100755 --- a/securedrop/i18n_tool.py +++ b/securedrop/i18n_tool.py @@ -141,9 +141,44 @@ def translate_desktop(self, args: argparse.Namespace) -> None: if args.extract_update: sources = args.sources.split(",") + xgettext_flags = [] + + # First extract from JavaScript sources via Babel ("xgettext + # --language=JavaScript" can't parse gettext as exposed by GNOME + # JavaScript): + js_sources = [source for source in sources if ".js" in source] + if js_sources: + xgettext_flags.append("--join-existing") + subprocess.check_call( + [ + "pybabel", + "extract", + "--charset=utf-8", + "--mapping", + args.mapping, + "--output", + "desktop.pot", + "--project=SecureDrop", + "--version", + args.version, + "--msgid-bugs-address=securedrop@freedom.press", + "--copyright-holder=Freedom of the Press Foundation", + "--add-comments=Translators:", + "--strip-comments", + "--add-location=never", + "--no-wrap", + *js_sources, + ], + cwd=args.translations_dir, + ) + + # Then extract from desktop templates via xgettext in appending + # "--join-existing" mode: + desktop_sources = [source for source in sources if ".js" not in source] subprocess.check_call( [ "xgettext", + *xgettext_flags, "--output=desktop.pot", "--language=Desktop", "--keyword", @@ -152,7 +187,7 @@ def translate_desktop(self, args: argparse.Namespace) -> None: args.version, "--msgid-bugs-address=securedrop@freedom.press", "--copyright-holder=Freedom of the Press Foundation", - *sources, + *desktop_sources, ], cwd=args.translations_dir, ) @@ -167,7 +202,9 @@ def translate_desktop(self, args: argparse.Namespace) -> None: if not f.endswith(".po"): continue po_file = os.path.join(args.translations_dir, f) - subprocess.check_call(["msgmerge", "--update", po_file, messages_file]) + subprocess.check_call( + ["msgmerge", "--no-fuzzy-matching", "--update", po_file, messages_file] + ) log.warning(f"messages translations updated in {messages_file}") else: log.warning("desktop translations are already up to date") @@ -180,7 +217,34 @@ def translate_desktop(self, args: argparse.Namespace) -> None: try: open(linguas_file, "w").write(content) - for source in args.sources.split(","): + # First, compile each message catalog for normal gettext use. + # We have to iterate over them, rather than using "pybabel + # compile --directory", in order to replicate gettext's + # standard "{locale}/LC_MESSAGES/{domain}.mo" structure (like + # "securedrop/translations"). + locale_dir = os.path.join(args.translations_dir, "locale") + for po in pos: + locale = po.replace(".po", "") + output_dir = os.path.join(locale_dir, locale, "LC_MESSAGES") + subprocess.run(["mkdir", "--parents", output_dir], check=True) + subprocess.run( + [ + "msgfmt", + "--output-file", + os.path.join(output_dir, "messages.mo"), + po, + ], + check=True, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + cwd=args.translations_dir, + ) + + # Then use msgfmt to update the desktop files as usual. + desktop_sources = [ + source for source in args.sources.split(",") if ".js" not in source + ] + for source in desktop_sources: target = source.rstrip(".in") subprocess.check_call( [ @@ -265,7 +329,19 @@ def set_translate_desktop_parser(self, subps: _SubParsersAction) -> None: "..", LOCALE_DIR["desktop"], ) - sources = "desktop-journalist-icon.j2.in,desktop-source-icon.j2.in" + sources = ",".join( + [ + "desktop-journalist-icon.j2.in", + "desktop-source-icon.j2.in", + "extension.js.in", + ] + ) + mapping = join(dirname(realpath(__file__)), "babel.cfg") + parser.add_argument( + "--mapping", + default=mapping, + help=f"Mapping of files to consider (default {mapping})", + ) self.set_translate_parser(parser, translations_dir, sources) parser.set_defaults(func=self.translate_desktop)