From 688a270c1751881aa8fc1675905f487314aaea3e Mon Sep 17 00:00:00 2001 From: Michael Hudson-Doyle Date: Thu, 19 Apr 2018 10:16:07 +1200 Subject: [PATCH 1/3] a round of marking strings as translatable and ensuring translations are actually displayed in the UI --- subiquity/controllers/keyboard.py | 6 +++--- subiquity/models/filesystem.py | 4 ++-- subiquity/ui/views/filesystem/filesystem.py | 23 +++++++++++---------- subiquity/ui/views/filesystem/guided.py | 4 ++-- subiquity/ui/views/identity.py | 12 +++++------ subiquity/ui/views/installprogress.py | 2 +- subiquity/ui/views/keyboard.py | 11 ++++++---- subiquitycore/controllers/network.py | 11 ++++------ subiquitycore/ui/form.py | 2 +- 9 files changed, 38 insertions(+), 37 deletions(-) diff --git a/subiquity/controllers/keyboard.py b/subiquity/controllers/keyboard.py index f7838642..a44cc91f 100644 --- a/subiquity/controllers/keyboard.py +++ b/subiquity/controllers/keyboard.py @@ -45,11 +45,11 @@ class KeyboardController(BaseController): def default(self): if self.model.current_lang is None: self.model.load_language('C') - title = "Keyboard configuration" + title = _("Keyboard configuration") if self.opts.run_on_serial: - excerpt = 'Please select the layout of the keyboard directly attached to the system, if any.' + excerpt = _('Please select the layout of the keyboard directly attached to the system, if any.') else: - excerpt = 'Please select your keyboard layout below, or select "Identify keyboard" to detect your layout automatically.' + excerpt = _('Please select your keyboard layout below, or select "Identify keyboard" to detect your layout automatically.') footer = _("Use UP, DOWN and ENTER keys to select your keyboard.") self.ui.set_header(title, excerpt) self.ui.set_footer(footer) diff --git a/subiquity/models/filesystem.py b/subiquity/models/filesystem.py index f98caf66..874a00fa 100644 --- a/subiquity/models/filesystem.py +++ b/subiquity/models/filesystem.py @@ -161,7 +161,7 @@ class Disk: return align_down(self._info.size) - (2<<20) # The first and last megabyte of the disk are not usable. def desc(self): - return "local disk" + return _("local disk") @property def label(self): @@ -199,7 +199,7 @@ class Partition: return self._fs def desc(self): - return "partition of {}".format(self.device.desc()) + return _("partition of {}").format(self.device.desc()) @property def available(self): diff --git a/subiquity/ui/views/filesystem/filesystem.py b/subiquity/ui/views/filesystem/filesystem.py index c0c67d5e..ce68a9f7 100644 --- a/subiquity/ui/views/filesystem/filesystem.py +++ b/subiquity/ui/views/filesystem/filesystem.py @@ -55,7 +55,7 @@ class FilesystemConfirmation(Stretchy): self.parent = parent self.controller = controller widgets = [ - Text(confirmation_text), + Text(_(confirmation_text)), Text(""), button_pile([ cancel_btn(_("No"), on_press=self.cancel), @@ -120,25 +120,26 @@ class FilesystemView(BaseView): def _build_filesystem_list(self): log.debug('FileSystemView: building part list') cols = [] - longest_path = len("MOUNT POINT") + mount_point_text = _("MOUNT POINT") + longest_path = len(mount_point_text) for m in sorted(self.model._mounts, key=lambda m:m.path): path = m.path longest_path = max(longest_path, len(path)) - for p, *_ in reversed(cols): + for p, *dummy in reversed(cols): if path.startswith(p): path = [('info_minor', p), path[len(p):]] break cols.append((m.path, path, humanize_size(m.device.volume.size), m.device.fstype, m.device.volume.desc())) for fs in self.model._filesystems: if fs.fstype == 'swap': - cols.append((None, 'SWAP', humanize_size(fs.volume.size), fs.fstype, fs.volume.desc())) + cols.append((None, _('SWAP'), humanize_size(fs.volume.size), fs.fstype, fs.volume.desc())) if len(cols) == 0: return Pile([Color.info_minor( - Text("No disks or partitions mounted."))]) - cols.insert(0, (None, "MOUNT POINT", "SIZE", "TYPE", "DEVICE TYPE")) + Text(_("No disks or partitions mounted.")))]) + cols.insert(0, (None, mount_point_text, _("SIZE"), _("TYPE"), _("DEVICE TYPE"))) pl = [] - for _, a, b, c, d in cols: + for dummy, a, b, c, d in cols: if b == "SIZE": b = Text(b, align='center') else: @@ -172,7 +173,7 @@ class FilesystemView(BaseView): inputs.append(Columns([(40, col1)], 1)) inputs = [] - col3(Text("DEVICE"), Text("SIZE", align="center"), Text("TYPE")) + col3(Text(_("DEVICE")), Text(_("SIZE"), align="center"), Text(_("TYPE"))) r.append(Pile(inputs)) for disk in self.model.all_disks(): @@ -183,7 +184,7 @@ class FilesystemView(BaseView): col3(disk_label, size, typ) fs = disk.fs() if fs is not None: - label = "entire device, " + label = _("entire device, ") fs_obj = self.model.fs_by_name[fs.fstype] if fs.mount(): label += "%-*s"%(self.model.longest_fs_name+2, fs.fstype+',') + fs.mount().path @@ -196,7 +197,7 @@ class FilesystemView(BaseView): disk_btn = Color.info_minor(Text(" " + label)) col1(disk_btn) for partition in disk.partitions(): - label = "partition {}, ".format(partition._number) + label = _("partition {}, ").format(partition._number) fs = partition.fs() if fs is not None: if fs.mount(): @@ -206,7 +207,7 @@ class FilesystemView(BaseView): elif partition.flag == "bios_grub": label += "bios_grub" else: - label += "unformatted" + label += _("unformatted") size = Text("{:>9} ({}%)".format(humanize_size(partition.size), int(100*partition.size/disk.size))) if partition.available: part_btn = menu_btn(label=label, on_press=self.click_partition, user_arg=partition) diff --git a/subiquity/ui/views/filesystem/guided.py b/subiquity/ui/views/filesystem/guided.py index ec14fe92..5be56d5b 100644 --- a/subiquity/ui/views/filesystem/guided.py +++ b/subiquity/ui/views/filesystem/guided.py @@ -46,7 +46,7 @@ class GuidedFilesystemView(BaseView): back = back_btn(_("Back"), on_press=self.cancel) lb = ListBox([ Padding.center_70(Text("")), - Padding.center_70(Text(text)), + Padding.center_70(Text(_(text))), Padding.center_70(Text("")), button_pile([guided, manual, back]), ]) @@ -67,7 +67,7 @@ class GuidedDiskSelectionView(BaseView): def __init__(self, model, controller): self.model = model self.controller = controller - cancel = cancel_btn("Cancel", on_press=self.cancel) + cancel = cancel_btn(_("Cancel"), on_press=self.cancel) disks = [] for disk in self.model.all_disks(): disk_btn = forward_btn( diff --git a/subiquity/ui/views/identity.py b/subiquity/ui/views/identity.py index 8b79b686..e730d1df 100644 --- a/subiquity/ui/views/identity.py +++ b/subiquity/ui/views/identity.py @@ -48,7 +48,7 @@ class RealnameEditor(StringEditor, WantsToKnowFormField): def valid_char(self, ch): if len(ch) == 1 and ch in ':,=': self.bff.in_error = True - self.bff.show_extra(("info_error", "The characters : , and = are not permitted in this field")) + self.bff.show_extra(("info_error", _("The characters : , and = are not permitted in this field"))) return False else: return super().valid_char(ch) @@ -56,7 +56,7 @@ class RealnameEditor(StringEditor, WantsToKnowFormField): class UsernameEditor(StringEditor, WantsToKnowFormField): def __init__(self): self.valid_char_pat = r'[-a-z0-9_]' - self.error_invalid_char = "The only characters permitted in this field are a-z, 0-9, _ and -" + self.error_invalid_char = _("The only characters permitted in this field are a-z, 0-9, _ and -") super().__init__() def valid_char(self, ch): @@ -202,17 +202,17 @@ class IdentityView(BaseView): def _check_password(self, sender, new_text): password = self.form.password.value if not password.startswith(new_text): - self.form.confirm_password.show_extra(("info_error", "Passwords do not match")) + self.form.confirm_password.show_extra(("info_error", _("Passwords do not match"))) else: self.form.confirm_password.show_extra('') def _select_ssh_import_id(self, sender, val): iu = self.form.import_username data = _ssh_import_data[val] - iu.help = data['help'] - iu.caption = data['caption'] + iu.help = _(data['help']) + iu.caption = _(data['caption']) iu.widget.valid_char_pat = data['valid_char'] - iu.widget.error_invalid_char = data['error_invalid_char'] + iu.widget.error_invalid_char = _(data['error_invalid_char']) iu.enabled = val is not None if val is not None: self.form_rows.body.focus += 2 diff --git a/subiquity/ui/views/installprogress.py b/subiquity/ui/views/installprogress.py index 61b2ae1b..7e2fe263 100644 --- a/subiquity/ui/views/installprogress.py +++ b/subiquity/ui/views/installprogress.py @@ -45,7 +45,7 @@ class ProgressView(BaseView): self.event_listwalker = SimpleFocusListWalker([]) self.event_listbox = ListBox(self.event_listwalker) self.event_linebox = MyLineBox(self.event_listbox) - self.event_buttons = button_pile([other_btn("View full log", on_press=self.view_log)]) + self.event_buttons = button_pile([other_btn(_("View full log"), on_press=self.view_log)]) event_body = [ ('pack', Text("")), ('weight', 1, Padding.center_79(self.event_linebox)), diff --git a/subiquity/ui/views/keyboard.py b/subiquity/ui/views/keyboard.py index dfc596e4..0cb08e96 100644 --- a/subiquity/ui/views/keyboard.py +++ b/subiquity/ui/views/keyboard.py @@ -119,13 +119,16 @@ another layout or run the automated detection again. model = self.keyboard_detector.keyboard_view.model layout, variant = model.lookup(self.step.result) var_desc = [] + layout_text = _("Layout") + var_text = _("Variant") + width = max(len(layout_text), len(var_text), 12) if variant is not None: - var_desc = [Text(_(" Variant: ") + variant)] + var_desc = [Text("%*s: %s"%(width, var_text, variant))] return Pile([ - Text(self.preamble), - Text(_(" Layout: ") + layout), + Text(_(self.preamble)), + Text("%*s: %s"%(width, layout_text, layout)), ] + var_desc + [ - Text(self.postamble), + Text(_(self.postamble)), button_pile([ok_btn(label=_("OK"), on_press=self.ok)]), ]) diff --git a/subiquitycore/controllers/network.py b/subiquitycore/controllers/network.py index 5616585a..8d98df5a 100644 --- a/subiquitycore/controllers/network.py +++ b/subiquitycore/controllers/network.py @@ -420,25 +420,22 @@ class NetworkController(BaseController): self.ui.set_body(NetworkBondInterfacesView(self.model, self)) def network_configure_interface(self, iface): - self.ui.set_header("Network interface {}".format(iface)) + self.ui.set_header(_("Network interface {}").format(iface)) self.ui.set_footer("") self.ui.set_body(NetworkConfigureInterfaceView(self.model, self, iface)) def network_configure_ipv4_interface(self, iface): - self.ui.set_header("Network interface {} manual IPv4 " - "configuration".format(iface)) + self.ui.set_header(_("Network interface {} manual IPv4 configuration").format(iface)) self.ui.set_footer("") self.ui.set_body(NetworkConfigureIPv4InterfaceView(self.model, self, iface)) def network_configure_wlan_interface(self, iface): - self.ui.set_header("Network interface {} WIFI " - "configuration".format(iface)) + self.ui.set_header(_("Network interface {} WIFI configuration").format(iface)) self.ui.set_footer("") self.ui.set_body(NetworkConfigureWLANView(self.model, self, iface)) def network_configure_ipv6_interface(self, iface): - self.ui.set_header("Network interface {} manual IPv6 " - "configuration".format(iface)) + self.ui.set_header(_("Network interface {} manual IPv6 configuration").format(iface)) self.ui.set_footer("") self.ui.set_body(NetworkConfigureIPv6InterfaceView(self.model, self, iface)) diff --git a/subiquitycore/ui/form.py b/subiquitycore/ui/form.py index d221fa02..585ad0a8 100644 --- a/subiquitycore/ui/form.py +++ b/subiquitycore/ui/form.py @@ -184,7 +184,7 @@ class BoundFormField(object): if self._help is not None: return self._help elif self.field.help is not None: - return self.field.help + return _(self.field.help) else: return "" From 78e6fea854db08bfabc7c8349f4bc998ace5bcac Mon Sep 17 00:00:00 2001 From: Michael Hudson-Doyle Date: Thu, 19 Apr 2018 10:26:59 +1200 Subject: [PATCH 2/3] work around strange behaviour of _("") --- subiquitycore/i18n.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/subiquitycore/i18n.py b/subiquitycore/i18n.py index 8c925a6b..245d36e0 100644 --- a/subiquitycore/i18n.py +++ b/subiquitycore/i18n.py @@ -29,11 +29,16 @@ syslog.syslog('Final localedir is ' + localedir) def switch_language(code='en_US'): if code != 'en_US' and 'FAKE_TRANSLATE' in os.environ: - import builtins - builtins.__dict__['_'] = lambda a: '_(%s)' % a + def my_gettext(message): + return "_(%s)" % message elif code: translation = gettext.translation('subiquity', localedir=localedir, languages=[code]) - translation.install() + def my_gettext(message): + if not message: + return message + return translation.gettext(message) + import builtins + builtins.__dict__['_'] = my_gettext switch_language() From baf408dbf2477e208bcbff5644ec3912a9e4d4cb Mon Sep 17 00:00:00 2001 From: Michael Hudson-Doyle Date: Thu, 19 Apr 2018 11:21:10 +1200 Subject: [PATCH 3/3] update POTFILES.in --- po/POTFILES.in | 1 + 1 file changed, 1 insertion(+) diff --git a/po/POTFILES.in b/po/POTFILES.in index 14c11f48..83c29f28 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -14,6 +14,7 @@ subiquitycore/ui/views/network_configure_interface.py subiquitycore/ui/views/network_configure_manual_interface.py subiquitycore/ui/views/network_configure_wlan_interface.py subiquitycore/ui/views/network.py +subiquity/models/filesystem.py subiquity/models/installpath.py subiquity/ui/mount.py subiquity/ui/views/filesystem/disk_info.py