Merge branch 'master' into mwhudson/reporting-2

This commit is contained in:
Michael Hudson-Doyle 2017-09-20 13:20:27 +12:00
commit 14c8b473c4
43 changed files with 1444 additions and 255 deletions

View File

@ -19,6 +19,7 @@ import sys
import logging import logging
import signal import signal
from subiquitycore.i18n import *
from subiquitycore.log import setup_logger from subiquitycore.log import setup_logger
from subiquitycore import __version__ as VERSION from subiquitycore import __version__ as VERSION
from subiquitycore.core import ApplicationError from subiquitycore.core import ApplicationError

View File

@ -91,12 +91,9 @@ class IdentityView(BaseView):
return Pile(sl) return Pile(sl)
def _build_buttons(self): def _build_buttons(self):
cancel = cancel_btn(on_press=self.cancel)
done = done_btn(on_press=self.done)
buttons = [ buttons = [
Color.button(done), done_btn(on_press=self.done),
Color.button(cancel), cancel_btn(on_press=self.cancel),
] ]
return Pile(buttons) return Pile(buttons)

View File

@ -22,9 +22,9 @@ import logging
from urwid import Text from urwid import Text
from subiquitycore.ui.buttons import finish_btn from subiquitycore.ui.buttons import done_btn
from subiquitycore.ui.container import ListBox, Pile from subiquitycore.ui.container import ListBox, Pile
from subiquitycore.ui.utils import Padding, Color from subiquitycore.ui.utils import Padding
from subiquitycore.view import BaseView from subiquitycore.view import BaseView
log = logging.getLogger("subiquitycore.views.login") log = logging.getLogger("subiquitycore.views.login")
@ -46,7 +46,7 @@ class LoginView(BaseView):
def _build_buttons(self): def _build_buttons(self):
self.buttons = [ self.buttons = [
Color.button(finish_btn(on_press=self.done)), done_btn(on_press=self.done),
] ]
return Pile(self.buttons) return Pile(self.buttons)

View File

@ -21,7 +21,7 @@ Welcome provides user with language selection
import logging import logging
from subiquitycore.ui.buttons import ok_btn from subiquitycore.ui.buttons import ok_btn
from subiquitycore.ui.container import ListBox, Pile from subiquitycore.ui.container import ListBox, Pile
from subiquitycore.ui.utils import Padding, Color from subiquitycore.ui.utils import Padding
from subiquitycore.view import BaseView from subiquitycore.view import BaseView
log = logging.getLogger("console_conf.views.welcome") log = logging.getLogger("console_conf.views.welcome")
@ -37,7 +37,7 @@ class WelcomeView(BaseView):
def _build_buttons(self): def _build_buttons(self):
self.buttons = [ self.buttons = [
Color.button(ok_btn(on_press=self.confirm)), ok_btn(on_press=self.confirm),
] ]
return Pile(self.buttons) return Pile(self.buttons)

3
debian/control vendored
View File

@ -6,9 +6,11 @@ Build-Depends: bzr,
debhelper (>= 9), debhelper (>= 9),
dh-python, dh-python,
dh-systemd, dh-systemd,
iso-codes,
git, git,
python3, python3,
python3-setuptools, python3-setuptools,
python3-distutils-extra,
python3-yaml, python3-yaml,
python3-attr python3-attr
Standards-Version: 3.9.5 Standards-Version: 3.9.5
@ -23,6 +25,7 @@ Depends: curtin,
python3, python3,
python3-attr, python3-attr,
subiquitycore, subiquitycore,
iso-codes,
${misc:Depends}, ${misc:Depends},
${python3:Depends} ${python3:Depends}
Description: Ubuntu Server Installer Description: Ubuntu Server Installer

View File

@ -1 +0,0 @@
installer usr/share/subiquity/

View File

@ -1 +1,2 @@
usr/share/subiquity/subiquitycore usr/share/subiquity/subiquitycore
usr/share/locale

19
po/POTFILES.in Normal file
View File

@ -0,0 +1,19 @@
[encoding: UTF-8]
subiquity/controllers/filesystem.py
subiquity/controllers/identity.py
subiquity/controllers/installpath.py
subiquity/controllers/installprogress.py
subiquity/controllers/welcome.py
subiquitycore/controllers/network.py
subiquitycore/ui/buttons.py
subiquitycore/ui/interactive.py
subiquitycore/ui/views/network_configure_interface.py
subiquitycore/ui/views/network_configure_manual_interface.py
subiquitycore/ui/views/network.py
subiquity/models/installpath.py
subiquity/ui/mount.py
subiquity/ui/views/filesystem/filesystem.py
subiquity/ui/views/filesystem/guided.py
subiquity/ui/views/identity.py
subiquity/ui/views/installprogress.py
subiquity/ui/views/welcome.py

558
po/en_US.po Normal file
View File

@ -0,0 +1,558 @@
# English translation for subiquity
# Copyright (C) 2017 Canonical Ltd, and Rosetta Contributors 2017
# This file is distributed under the same license as the subiquity package.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: subiquity\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-09-15 18:29+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: en_US\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: ../subiquity/controllers/filesystem.py:67
#: ../subiquity/controllers/filesystem.py:74
#: ../subiquity/controllers/filesystem.py:81
msgid "Filesystem setup"
msgstr ""
#: ../subiquity/controllers/filesystem.py:68
msgid "Choose guided or manual partitioning"
msgstr ""
#: ../subiquity/controllers/filesystem.py:75
msgid "Select available disks to format and mount"
msgstr ""
#: ../subiquity/controllers/filesystem.py:82
msgid "Choose the installation target"
msgstr ""
#: ../subiquity/controllers/filesystem.py:96
msgid "Filesystem error"
msgstr ""
#: ../subiquity/controllers/filesystem.py:97
msgid "Error while installing Ubuntu"
msgstr ""
#: ../subiquity/controllers/filesystem.py:98
msgid "Failed to obtain write permissions to /tmp"
msgstr ""
#: ../subiquity/controllers/filesystem.py:140
msgid "Partition, format, and mount {}"
msgstr ""
#: ../subiquity/controllers/filesystem.py:141
msgid "Partition the disk, or format the entire device without partitions"
msgstr ""
#: ../subiquity/controllers/filesystem.py:151
msgid "Select whole disk, or partition, to format and mount."
msgstr ""
#: ../subiquity/controllers/filesystem.py:158
msgid "Edit partition details format and mount."
msgstr ""
#: ../subiquity/controllers/filesystem.py:265
msgid "Create Logical Volume Group (\"LVM2\") disk"
msgstr ""
#: ../subiquity/controllers/filesystem.py:266
#: ../subiquity/controllers/filesystem.py:276
#: ../subiquity/controllers/filesystem.py:289
msgid "ENTER on a disk will show detailed information for that disk"
msgstr ""
#: ../subiquity/controllers/filesystem.py:268
msgid ""
"Use SPACE to select disks to form your LVM2 volume group, and then specify "
"the Volume Group name. "
msgstr ""
#: ../subiquity/controllers/filesystem.py:275
msgid "Create software RAID (\"MD\") disk"
msgstr ""
#: ../subiquity/controllers/filesystem.py:278
msgid ""
"Use SPACE to select disks to form your RAID array, and then specify the RAID "
"parameters. Multiple-disk arrays work best when all the disks in an array "
"are the same size and speed."
msgstr ""
#: ../subiquity/controllers/filesystem.py:288
msgid "Create hierarchical storage (\"bcache\") disk"
msgstr ""
#: ../subiquity/controllers/filesystem.py:291
msgid ""
"Use SPACE to select a cache disk and a backing disk to form your bcache "
"device."
msgstr ""
#: ../subiquity/controllers/filesystem.py:306
msgid "Format and/or mount {}"
msgstr ""
#: ../subiquity/controllers/filesystem.py:307
msgid "Format or mount whole disk."
msgstr ""
#: ../subiquity/controllers/filesystem.py:316
msgid "Mount partition {} of {}"
msgstr ""
#: ../subiquity/controllers/filesystem.py:317
msgid "Mount partition."
msgstr ""
#: ../subiquity/controllers/filesystem.py:319
msgid "Format and mount partition {} of {}"
msgstr ""
#: ../subiquity/controllers/filesystem.py:320
msgid "Format and mount partition."
msgstr ""
#: ../subiquity/controllers/filesystem.py:385
msgid "Select next or previous disks with n and p"
msgstr ""
#: ../subiquity/controllers/identity.py:36
msgid "Profile setup"
msgstr ""
#: ../subiquity/controllers/identity.py:37
msgid ""
"Enter the username and password (or ssh identity) you will use to log in to "
"the system."
msgstr ""
#: ../subiquity/controllers/installpath.py:45
msgid ""
"Welcome to Ubuntu! The world's favorite platform for clouds, clusters, and "
"amazing internet things. This is the installer for Ubuntu on servers and "
"internet devices."
msgstr ""
#: ../subiquity/controllers/installpath.py:49
msgid "Use UP, DOWN arrow keys, and ENTER, to navigate options"
msgstr ""
#: ../subiquity/controllers/installprogress.py:74
msgid "An error occurred during installation"
msgstr ""
#: ../subiquity/controllers/installprogress.py:75
msgid "Please report this error in Launchpad"
msgstr ""
#: ../subiquity/controllers/installprogress.py:76
msgid "An error has occurred."
msgstr ""
#: ../subiquity/controllers/installprogress.py:137
#: ../subiquity/controllers/installprogress.py:228
msgid "Running postinstall step"
msgstr ""
#: ../subiquity/controllers/installprogress.py:165
msgid "Installation complete!"
msgstr ""
#: ../subiquity/controllers/installprogress.py:167
msgid "Finished install!"
msgstr ""
#: ../subiquity/controllers/installprogress.py:215
msgid "Installing system"
msgstr ""
#: ../subiquity/controllers/installprogress.py:216
msgid "Please wait for the installation to finish."
msgstr ""
#: ../subiquity/controllers/installprogress.py:217
msgid "Thank you for using Ubuntu!"
msgstr ""
#: ../subiquity/controllers/installprogress.py:226
msgid "Running install step"
msgstr ""
#: ../subiquity/controllers/welcome.py:31
msgid "Please choose your preferred language"
msgstr ""
#: ../subiquity/controllers/welcome.py:32
msgid "Use UP, DOWN and ENTER keys to select your language."
msgstr ""
#: ../subiquitycore/controllers/network.py:347
msgid "Network connections"
msgstr ""
#: ../subiquitycore/controllers/network.py:348
msgid ""
"Configure at least one interface this server can use to talk to other "
"machines, and which preferably provides sufficient access for updates."
msgstr ""
#: ../subiquitycore/controllers/network.py:351
msgid "Select an interface to configure it or select Done to continue"
msgstr ""
#: ../subiquitycore/ui/buttons.py:37
msgid "Start"
msgstr ""
#: ../subiquitycore/ui/buttons.py:38
msgid "Save"
msgstr ""
#: ../subiquitycore/ui/buttons.py:39
msgid "Finish"
msgstr ""
#: ../subiquitycore/ui/buttons.py:40
msgid "OK"
msgstr ""
#: ../subiquitycore/ui/buttons.py:41
msgid "Confirm"
msgstr ""
#: ../subiquitycore/ui/buttons.py:42
msgid "Done"
msgstr ""
#: ../subiquitycore/ui/buttons.py:43
#: ../subiquity/ui/views/filesystem/filesystem.py:60
msgid "Continue"
msgstr ""
#: ../subiquitycore/ui/buttons.py:45
msgid "Reset"
msgstr ""
#: ../subiquitycore/ui/buttons.py:47
msgid "Cancel"
msgstr ""
#: ../subiquitycore/ui/buttons.py:48
msgid "Back"
msgstr ""
#: ../subiquitycore/ui/interactive.py:114
msgid "Yes"
msgstr ""
#: ../subiquitycore/ui/interactive.py:114
#: ../subiquity/ui/views/filesystem/filesystem.py:59
msgid "No"
msgstr ""
#: ../subiquitycore/ui/interactive.py:121
msgid "Close"
msgstr ""
#: ../subiquitycore/ui/interactive.py:122
msgid "Help"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_interface.py:66
msgid "Use a static IPv4 configuration"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_interface.py:69
msgid "Use DHCPv4 on this interface"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_interface.py:72
#: ../subiquitycore/ui/views/network_configure_interface.py:91
msgid "Do not use"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_interface.py:85
msgid "Use a static IPv6 configuration"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_interface.py:88
msgid "Use DHCPv6 on this interface"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_interface.py:102
msgid "Configure WIFI settings"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_manual_interface.py:67
msgid "Subnet:"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_manual_interface.py:68
msgid "Address:"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_manual_interface.py:69
msgid "Gateway:"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_manual_interface.py:70
msgid "Name servers:"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_manual_interface.py:70
msgid "IP addresses, comma separated"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_manual_interface.py:71
msgid "Search domains:"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_manual_interface.py:71
msgid "Domains, comma separated"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_manual_interface.py:122
#, python-format
msgid "CIDR e.g. %s"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_manual_interface.py:158
msgid "Set this as default gateway"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_manual_interface.py:161
msgid "This will be your default gateway"
msgstr ""
#: ../subiquitycore/ui/views/network.py:51
msgid "Applying network config"
msgstr ""
#: ../subiquitycore/ui/views/network.py:65
#, python-format
msgid "Associated to '%s', will associate to '%s'"
msgstr ""
#: ../subiquitycore/ui/views/network.py:67
#, python-format
msgid "Associated to '%s'"
msgstr ""
#: ../subiquitycore/ui/views/network.py:69
#, python-format
msgid "No access point configured, but associated to '%s'"
msgstr ""
#: ../subiquitycore/ui/views/network.py:72
#, python-format
msgid "Will associate to '%s'"
msgstr ""
#: ../subiquitycore/ui/views/network.py:74
msgid "No access point configured"
msgstr ""
#: ../subiquitycore/ui/views/network.py:94
#, python-format
msgid "Will use DHCP for IPv%s, currently has address%%s:"
msgstr ""
#: ../subiquitycore/ui/views/network.py:95
#, python-format
msgid "Will use DHCP for IPv%s"
msgstr ""
#: ../subiquitycore/ui/views/network.py:98
#, python-format
msgid "Using static address%%s for IPv%s:"
msgstr ""
#: ../subiquitycore/ui/views/network.py:99
#, python-format
msgid "Will use static address%%s for IPv%s:"
msgstr ""
#: ../subiquitycore/ui/views/network.py:101
#, python-format
msgid "Currently has address%s:"
msgstr ""
#: ../subiquitycore/ui/views/network.py:104
#, python-format
msgid "Has no IPv%s configuration, currently has address%%s:"
msgstr ""
#: ../subiquitycore/ui/views/network.py:106
#, python-format
msgid "IPv%s is not configured"
msgstr ""
#: ../subiquitycore/ui/views/network.py:165
msgid "Not connected"
msgstr ""
#: ../subiquitycore/ui/views/network.py:204
#, python-format
msgid " IPv4 default route %s."
msgstr ""
#: ../subiquity/models/installpath.py:31
msgid "Install Ubuntu"
msgstr ""
#: ../subiquity/ui/mount.py:53
msgid "other"
msgstr ""
#: ../subiquity/ui/mount.py:55
msgid "leave unmounted"
msgstr ""
#: ../subiquity/ui/views/filesystem/filesystem.py:47
msgid ""
"\n"
"Selecting Continue below will result of the loss of data on the disks "
"selected to be formatted.\n"
"\n"
"Are you sure you want to continue?\n"
msgstr ""
#: ../subiquity/ui/views/filesystem/filesystem.py:63
msgid "Confirm destructive action"
msgstr ""
#: ../subiquity/ui/views/filesystem/filesystem.py:80
msgid "FILE SYSTEM SUMMARY"
msgstr ""
#: ../subiquity/ui/views/filesystem/filesystem.py:84
msgid "AVAILABLE DEVICES"
msgstr ""
#: ../subiquity/ui/views/filesystem/filesystem.py:208
msgid "ADD/EDIT PARTITIONS"
msgstr ""
#: ../subiquity/ui/views/filesystem/filesystem.py:211
msgid "ADD FIRST PARTITION"
msgstr ""
#: ../subiquity/ui/views/filesystem/filesystem.py:214
msgid "EDIT PARTITIONS"
msgstr ""
#: ../subiquity/ui/views/filesystem/filesystem.py:222
msgid "No disks available."
msgstr ""
#: ../subiquity/ui/views/filesystem/guided.py:33
msgid ""
"The installer can guide you through partitioning a disk or, if you prefer, "
"you can do it manually. If you choose guided partitioning you will still "
"have a chance to review and modify the results."
msgstr ""
#: ../subiquity/ui/views/filesystem/guided.py:42
msgid "Guided"
msgstr ""
#: ../subiquity/ui/views/filesystem/guided.py:43
msgid "Manual"
msgstr ""
#: ../subiquity/ui/views/filesystem/guided.py:78
msgid "Choose the disk to install to:"
msgstr ""
#: ../subiquity/ui/views/identity.py:49
msgid "Your name:"
msgstr ""
#: ../subiquity/ui/views/identity.py:51
msgid "Your server's name:"
msgstr ""
#: ../subiquity/ui/views/identity.py:52
msgid "The name it uses when it talks to other computers."
msgstr ""
#: ../subiquity/ui/views/identity.py:53
msgid "Pick a username:"
msgstr ""
#: ../subiquity/ui/views/identity.py:54
msgid "Choose a password:"
msgstr ""
#: ../subiquity/ui/views/identity.py:55
msgid "Confirm your password:"
msgstr ""
#: ../subiquity/ui/views/identity.py:57
msgid "Import SSH identity:"
msgstr ""
#: ../subiquity/ui/views/identity.py:58
msgid ""
"Input your SSH user id from Ubuntu SSO (sso:email), Launchpad (lp:username) "
"or Github (gh:username)."
msgstr ""
#: ../subiquity/ui/views/identity.py:63
msgid "Real name must not be empty."
msgstr ""
#: ../subiquity/ui/views/identity.py:65
msgid "Realname too long, must be < "
msgstr ""
#: ../subiquity/ui/views/identity.py:69
msgid "Server name must not be empty"
msgstr ""
#: ../subiquity/ui/views/identity.py:72
msgid "Server name too long, must be < "
msgstr ""
#: ../subiquity/ui/views/identity.py:76
msgid "Username missing"
msgstr ""
#: ../subiquity/ui/views/identity.py:79
msgid "Username too long, must be < "
msgstr ""
#: ../subiquity/ui/views/identity.py:85
msgid "Password must be set"
msgstr ""
#: ../subiquity/ui/views/identity.py:89
msgid "Passwords do not match"
msgstr ""
#: ../subiquity/ui/views/identity.py:94
msgid "SSH id too long, must be < "
msgstr ""
#: ../subiquity/ui/views/installprogress.py:65
msgid "Reboot Now"
msgstr ""
#: ../subiquity/ui/views/installprogress.py:68
msgid "Quit Installer"
msgstr ""
#: ../subiquity/ui/views/welcome.py:40
msgid "(More language choices will appear in time)"
msgstr ""

558
po/ru.po Normal file
View File

@ -0,0 +1,558 @@
# Russian translation for subiquity
# Copyright (C) 2017 Canonical Ltd, and Rosetta Contributors 2017
# This file is distributed under the same license as the subiquity package.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: subiquity\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-09-15 18:41+0100\n"
"PO-Revision-Date: 2017-09-04 14:44+0100\n"
"Last-Translator: Dimitri Ledkov <xnox@ubuntu.com>\n"
"Language-Team: Russian <ru@li.org>\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: ../subiquity/controllers/filesystem.py:67
#: ../subiquity/controllers/filesystem.py:74
#: ../subiquity/controllers/filesystem.py:81
msgid "Filesystem setup"
msgstr ""
#: ../subiquity/controllers/filesystem.py:68
msgid "Choose guided or manual partitioning"
msgstr ""
#: ../subiquity/controllers/filesystem.py:75
msgid "Select available disks to format and mount"
msgstr ""
#: ../subiquity/controllers/filesystem.py:82
msgid "Choose the installation target"
msgstr ""
#: ../subiquity/controllers/filesystem.py:96
msgid "Filesystem error"
msgstr ""
#: ../subiquity/controllers/filesystem.py:97
msgid "Error while installing Ubuntu"
msgstr ""
#: ../subiquity/controllers/filesystem.py:98
msgid "Failed to obtain write permissions to /tmp"
msgstr ""
#: ../subiquity/controllers/filesystem.py:140
msgid "Partition, format, and mount {}"
msgstr ""
#: ../subiquity/controllers/filesystem.py:141
msgid "Partition the disk, or format the entire device without partitions"
msgstr ""
#: ../subiquity/controllers/filesystem.py:151
msgid "Select whole disk, or partition, to format and mount."
msgstr ""
#: ../subiquity/controllers/filesystem.py:158
msgid "Edit partition details format and mount."
msgstr ""
#: ../subiquity/controllers/filesystem.py:265
msgid "Create Logical Volume Group (\"LVM2\") disk"
msgstr ""
#: ../subiquity/controllers/filesystem.py:266
#: ../subiquity/controllers/filesystem.py:276
#: ../subiquity/controllers/filesystem.py:289
msgid "ENTER on a disk will show detailed information for that disk"
msgstr ""
#: ../subiquity/controllers/filesystem.py:268
msgid ""
"Use SPACE to select disks to form your LVM2 volume group, and then specify "
"the Volume Group name. "
msgstr ""
#: ../subiquity/controllers/filesystem.py:275
msgid "Create software RAID (\"MD\") disk"
msgstr ""
#: ../subiquity/controllers/filesystem.py:278
msgid ""
"Use SPACE to select disks to form your RAID array, and then specify the RAID "
"parameters. Multiple-disk arrays work best when all the disks in an array "
"are the same size and speed."
msgstr ""
#: ../subiquity/controllers/filesystem.py:288
msgid "Create hierarchical storage (\"bcache\") disk"
msgstr ""
#: ../subiquity/controllers/filesystem.py:291
msgid ""
"Use SPACE to select a cache disk and a backing disk to form your bcache "
"device."
msgstr ""
#: ../subiquity/controllers/filesystem.py:306
msgid "Format and/or mount {}"
msgstr ""
#: ../subiquity/controllers/filesystem.py:307
msgid "Format or mount whole disk."
msgstr ""
#: ../subiquity/controllers/filesystem.py:316
msgid "Mount partition {} of {}"
msgstr ""
#: ../subiquity/controllers/filesystem.py:317
msgid "Mount partition."
msgstr ""
#: ../subiquity/controllers/filesystem.py:319
msgid "Format and mount partition {} of {}"
msgstr ""
#: ../subiquity/controllers/filesystem.py:320
msgid "Format and mount partition."
msgstr ""
#: ../subiquity/controllers/filesystem.py:385
msgid "Select next or previous disks with n and p"
msgstr ""
#: ../subiquity/controllers/identity.py:36
msgid "Profile setup"
msgstr ""
#: ../subiquity/controllers/identity.py:37
msgid ""
"Enter the username and password (or ssh identity) you will use to log in to "
"the system."
msgstr ""
#: ../subiquity/controllers/installpath.py:45
msgid ""
"Welcome to Ubuntu! The world's favorite platform for clouds, clusters, and "
"amazing internet things. This is the installer for Ubuntu on servers and "
"internet devices."
msgstr ""
#: ../subiquity/controllers/installpath.py:49
msgid "Use UP, DOWN arrow keys, and ENTER, to navigate options"
msgstr ""
#: ../subiquity/controllers/installprogress.py:74
msgid "An error occurred during installation"
msgstr ""
#: ../subiquity/controllers/installprogress.py:75
msgid "Please report this error in Launchpad"
msgstr ""
#: ../subiquity/controllers/installprogress.py:76
msgid "An error has occurred."
msgstr ""
#: ../subiquity/controllers/installprogress.py:137
#: ../subiquity/controllers/installprogress.py:228
msgid "Running postinstall step"
msgstr ""
#: ../subiquity/controllers/installprogress.py:165
msgid "Installation complete!"
msgstr ""
#: ../subiquity/controllers/installprogress.py:167
msgid "Finished install!"
msgstr ""
#: ../subiquity/controllers/installprogress.py:215
msgid "Installing system"
msgstr ""
#: ../subiquity/controllers/installprogress.py:216
msgid "Please wait for the installation to finish."
msgstr ""
#: ../subiquity/controllers/installprogress.py:217
msgid "Thank you for using Ubuntu!"
msgstr ""
#: ../subiquity/controllers/installprogress.py:226
msgid "Running install step"
msgstr ""
#: ../subiquity/controllers/welcome.py:31
msgid "Please choose your preferred language"
msgstr "Выберите предпочитаемый язык"
#: ../subiquity/controllers/welcome.py:32
msgid "Use UP, DOWN and ENTER keys to select your language."
msgstr ""
#: ../subiquitycore/controllers/network.py:347
msgid "Network connections"
msgstr ""
#: ../subiquitycore/controllers/network.py:348
msgid ""
"Configure at least one interface this server can use to talk to other "
"machines, and which preferably provides sufficient access for updates."
msgstr ""
#: ../subiquitycore/controllers/network.py:351
msgid "Select an interface to configure it or select Done to continue"
msgstr ""
#: ../subiquitycore/ui/buttons.py:37
msgid "Start"
msgstr ""
#: ../subiquitycore/ui/buttons.py:38
msgid "Save"
msgstr ""
#: ../subiquitycore/ui/buttons.py:39
msgid "Finish"
msgstr ""
#: ../subiquitycore/ui/buttons.py:40
msgid "OK"
msgstr ""
#: ../subiquitycore/ui/buttons.py:41
msgid "Confirm"
msgstr ""
#: ../subiquitycore/ui/buttons.py:42
msgid "Done"
msgstr ""
#: ../subiquitycore/ui/buttons.py:43
#: ../subiquity/ui/views/filesystem/filesystem.py:60
msgid "Continue"
msgstr "Продолжить"
#: ../subiquitycore/ui/buttons.py:45
msgid "Reset"
msgstr ""
#: ../subiquitycore/ui/buttons.py:47
msgid "Cancel"
msgstr "Отменить"
#: ../subiquitycore/ui/buttons.py:48
msgid "Back"
msgstr ""
#: ../subiquitycore/ui/interactive.py:114
msgid "Yes"
msgstr ""
#: ../subiquitycore/ui/interactive.py:114
#: ../subiquity/ui/views/filesystem/filesystem.py:59
msgid "No"
msgstr ""
#: ../subiquitycore/ui/interactive.py:121
msgid "Close"
msgstr ""
#: ../subiquitycore/ui/interactive.py:122
msgid "Help"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_interface.py:66
msgid "Use a static IPv4 configuration"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_interface.py:69
msgid "Use DHCPv4 on this interface"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_interface.py:72
#: ../subiquitycore/ui/views/network_configure_interface.py:91
msgid "Do not use"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_interface.py:85
msgid "Use a static IPv6 configuration"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_interface.py:88
msgid "Use DHCPv6 on this interface"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_interface.py:102
msgid "Configure WIFI settings"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_manual_interface.py:67
msgid "Subnet:"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_manual_interface.py:68
msgid "Address:"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_manual_interface.py:69
msgid "Gateway:"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_manual_interface.py:70
msgid "Name servers:"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_manual_interface.py:70
msgid "IP addresses, comma separated"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_manual_interface.py:71
msgid "Search domains:"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_manual_interface.py:71
msgid "Domains, comma separated"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_manual_interface.py:122
#, python-format
msgid "CIDR e.g. %s"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_manual_interface.py:158
msgid "Set this as default gateway"
msgstr ""
#: ../subiquitycore/ui/views/network_configure_manual_interface.py:161
msgid "This will be your default gateway"
msgstr ""
#: ../subiquitycore/ui/views/network.py:51
msgid "Applying network config"
msgstr ""
#: ../subiquitycore/ui/views/network.py:65
#, python-format
msgid "Associated to '%s', will associate to '%s'"
msgstr ""
#: ../subiquitycore/ui/views/network.py:67
#, python-format
msgid "Associated to '%s'"
msgstr ""
#: ../subiquitycore/ui/views/network.py:69
#, python-format
msgid "No access point configured, but associated to '%s'"
msgstr ""
#: ../subiquitycore/ui/views/network.py:72
#, python-format
msgid "Will associate to '%s'"
msgstr ""
#: ../subiquitycore/ui/views/network.py:74
msgid "No access point configured"
msgstr ""
#: ../subiquitycore/ui/views/network.py:94
#, python-format
msgid "Will use DHCP for IPv%s, currently has address%%s:"
msgstr ""
#: ../subiquitycore/ui/views/network.py:95
#, python-format
msgid "Will use DHCP for IPv%s"
msgstr ""
#: ../subiquitycore/ui/views/network.py:98
#, python-format
msgid "Using static address%%s for IPv%s:"
msgstr ""
#: ../subiquitycore/ui/views/network.py:99
#, python-format
msgid "Will use static address%%s for IPv%s:"
msgstr ""
#: ../subiquitycore/ui/views/network.py:101
#, python-format
msgid "Currently has address%s:"
msgstr ""
#: ../subiquitycore/ui/views/network.py:104
#, python-format
msgid "Has no IPv%s configuration, currently has address%%s:"
msgstr ""
#: ../subiquitycore/ui/views/network.py:106
#, python-format
msgid "IPv%s is not configured"
msgstr ""
#: ../subiquitycore/ui/views/network.py:165
msgid "Not connected"
msgstr ""
#: ../subiquitycore/ui/views/network.py:204
#, python-format
msgid " IPv4 default route %s."
msgstr ""
#: ../subiquity/models/installpath.py:31
msgid "Install Ubuntu"
msgstr ""
#: ../subiquity/ui/mount.py:53
msgid "other"
msgstr "другое"
#: ../subiquity/ui/mount.py:55
msgid "leave unmounted"
msgstr ""
#: ../subiquity/ui/views/filesystem/filesystem.py:47
msgid ""
"\n"
"Selecting Continue below will result of the loss of data on the disks "
"selected to be formatted.\n"
"\n"
"Are you sure you want to continue?\n"
msgstr ""
#: ../subiquity/ui/views/filesystem/filesystem.py:63
msgid "Confirm destructive action"
msgstr ""
#: ../subiquity/ui/views/filesystem/filesystem.py:80
msgid "FILE SYSTEM SUMMARY"
msgstr ""
#: ../subiquity/ui/views/filesystem/filesystem.py:84
msgid "AVAILABLE DEVICES"
msgstr ""
#: ../subiquity/ui/views/filesystem/filesystem.py:208
msgid "ADD/EDIT PARTITIONS"
msgstr ""
#: ../subiquity/ui/views/filesystem/filesystem.py:211
msgid "ADD FIRST PARTITION"
msgstr ""
#: ../subiquity/ui/views/filesystem/filesystem.py:214
msgid "EDIT PARTITIONS"
msgstr ""
#: ../subiquity/ui/views/filesystem/filesystem.py:222
msgid "No disks available."
msgstr ""
#: ../subiquity/ui/views/filesystem/guided.py:33
msgid ""
"The installer can guide you through partitioning a disk or, if you prefer, "
"you can do it manually. If you choose guided partitioning you will still "
"have a chance to review and modify the results."
msgstr ""
#: ../subiquity/ui/views/filesystem/guided.py:42
msgid "Guided"
msgstr ""
#: ../subiquity/ui/views/filesystem/guided.py:43
msgid "Manual"
msgstr ""
#: ../subiquity/ui/views/filesystem/guided.py:78
msgid "Choose the disk to install to:"
msgstr ""
#: ../subiquity/ui/views/identity.py:49
msgid "Your name:"
msgstr ""
#: ../subiquity/ui/views/identity.py:51
msgid "Your server's name:"
msgstr ""
#: ../subiquity/ui/views/identity.py:52
msgid "The name it uses when it talks to other computers."
msgstr ""
#: ../subiquity/ui/views/identity.py:53
msgid "Pick a username:"
msgstr ""
#: ../subiquity/ui/views/identity.py:54
msgid "Choose a password:"
msgstr ""
#: ../subiquity/ui/views/identity.py:55
msgid "Confirm your password:"
msgstr ""
#: ../subiquity/ui/views/identity.py:57
msgid "Import SSH identity:"
msgstr ""
#: ../subiquity/ui/views/identity.py:58
msgid ""
"Input your SSH user id from Ubuntu SSO (sso:email), Launchpad (lp:username) "
"or Github (gh:username)."
msgstr ""
#: ../subiquity/ui/views/identity.py:63
msgid "Real name must not be empty."
msgstr ""
#: ../subiquity/ui/views/identity.py:65
msgid "Realname too long, must be < "
msgstr ""
#: ../subiquity/ui/views/identity.py:69
msgid "Server name must not be empty"
msgstr ""
#: ../subiquity/ui/views/identity.py:72
msgid "Server name too long, must be < "
msgstr ""
#: ../subiquity/ui/views/identity.py:76
msgid "Username missing"
msgstr ""
#: ../subiquity/ui/views/identity.py:79
msgid "Username too long, must be < "
msgstr ""
#: ../subiquity/ui/views/identity.py:85
msgid "Password must be set"
msgstr ""
#: ../subiquity/ui/views/identity.py:89
msgid "Passwords do not match"
msgstr ""
#: ../subiquity/ui/views/identity.py:94
msgid "SSH id too long, must be < "
msgstr ""
#: ../subiquity/ui/views/installprogress.py:65
msgid "Reboot Now"
msgstr ""
#: ../subiquity/ui/views/installprogress.py:68
msgid "Quit Installer"
msgstr ""
#: ../subiquity/ui/views/welcome.py:40
msgid "(More language choices will appear in time)"
msgstr ""

2
setup.cfg Normal file
View File

@ -0,0 +1,2 @@
[build_i18n]
domain=subiquity

View File

@ -23,6 +23,8 @@ Ubuntu Server Installer
""" """
from setuptools import setup, find_packages from setuptools import setup, find_packages
from DistUtilsExtra.command import build_extra
from DistUtilsExtra.command import build_i18n
import os import os
import sys import sys
@ -43,4 +45,6 @@ setup(name='subiquity',
url='https://github.com/CanonicalLtd/subiquity', url='https://github.com/CanonicalLtd/subiquity',
license="AGPLv3+", license="AGPLv3+",
packages=find_packages(exclude=["tests"]), packages=find_packages(exclude=["tests"]),
cmdclass={'build': build_extra.build_extra,
'build_i18n': build_i18n.build_i18n, },
data_files=[]) data_files=[])

View File

@ -15,14 +15,22 @@ apps:
parts: parts:
subiquity: subiquity:
plugin: python plugin: python
build-packages: [python-setuptools, pkg-config, lsb-release, libsystemd-dev] build-packages:
stage-packages: [curtin, lsb-release] - libsystemd-dev
- lsb-release
- pkg-config
- python3-distutils-extra
stage-packages:
- curtin
- iso-codes
- lsb-release
- python3-distutils-extra
python-packages: python-packages:
- urwid
- pyyaml
- pyudev
- attrs - attrs
- pyudev
- pyyaml
- systemd-python - systemd-python
- urwid
source: . source: .
source-type: git source-type: git
wrappers: wrappers:

View File

@ -64,22 +64,22 @@ class FilesystemController(BaseController):
if self.model.any_configuration_done(): if self.model.any_configuration_done():
self.manual() self.manual()
else: else:
title = "Filesystem setup" title = _("Filesystem setup")
footer = ("Choose guided or manual partitioning") footer = (_("Choose guided or manual partitioning"))
self.ui.set_header(title) self.ui.set_header(title)
self.ui.set_footer(footer, 30) self.ui.set_footer(footer, 30)
self.ui.set_body(GuidedFilesystemView(self.model, self)) self.ui.set_body(GuidedFilesystemView(self.model, self))
def manual(self): def manual(self):
title = "Filesystem setup" title = _("Filesystem setup")
footer = ("Select available disks to format and mount") footer = (_("Select available disks to format and mount"))
self.ui.set_header(title) self.ui.set_header(title)
self.ui.set_footer(footer, 30) self.ui.set_footer(footer, 30)
self.ui.set_body(FilesystemView(self.model, self)) self.ui.set_body(FilesystemView(self.model, self))
def guided(self): def guided(self):
title = "Filesystem setup" title = _("Filesystem setup")
footer = ("Choose the installation target") footer = (_("Choose the installation target"))
self.ui.set_header(title) self.ui.set_header(title)
self.ui.set_footer(footer, 30) self.ui.set_footer(footer, 30)
self.ui.set_body(GuidedDiskSelectionView(self.model, self)) self.ui.set_body(GuidedDiskSelectionView(self.model, self))
@ -93,9 +93,9 @@ class FilesystemController(BaseController):
self.signal.emit_signal('prev-screen') self.signal.emit_signal('prev-screen')
def filesystem_error(self, error_fname): def filesystem_error(self, error_fname):
title = "Filesystem error" title = _("Filesystem error")
footer = ("Error while installing Ubuntu") footer = (_("Error while installing Ubuntu"))
error_msg = "Failed to obtain write permissions to /tmp" error_msg = _("Failed to obtain write permissions to /tmp")
self.ui.set_header(title) self.ui.set_header(title)
self.ui.set_footer(footer, 30) self.ui.set_footer(footer, 30)
self.ui.set_body(ErrorView(self.signal, error_msg)) self.ui.set_body(ErrorView(self.signal, error_msg))
@ -137,9 +137,9 @@ class FilesystemController(BaseController):
# Filesystem/Disk partition ----------------------------------------------- # Filesystem/Disk partition -----------------------------------------------
def partition_disk(self, disk): def partition_disk(self, disk):
log.debug("In disk partition view, using {} as the disk.".format(disk.serial)) log.debug("In disk partition view, using {} as the disk.".format(disk.serial))
title = ("Partition, format, and mount {}".format(disk.serial)) title = (_("Partition, format, and mount {}").format(disk.serial))
footer = ("Partition the disk, or format the entire device " footer = (_("Partition the disk, or format the entire device "
"without partitions") "without partitions"))
self.ui.set_header(title) self.ui.set_header(title)
self.ui.set_footer(footer) self.ui.set_footer(footer)
dp_view = DiskPartitionView(self.model, self, disk) dp_view = DiskPartitionView(self.model, self, disk)
@ -148,14 +148,14 @@ class FilesystemController(BaseController):
def add_disk_partition(self, disk): def add_disk_partition(self, disk):
log.debug("Adding partition to {}".format(disk)) log.debug("Adding partition to {}".format(disk))
footer = ("Select whole disk, or partition, to format and mount.") footer = _("Select whole disk, or partition, to format and mount.")
self.ui.set_footer(footer) self.ui.set_footer(footer)
adp_view = PartitionView(self.model, self, disk) adp_view = PartitionView(self.model, self, disk)
self.ui.set_body(adp_view) self.ui.set_body(adp_view)
def edit_partition(self, disk, partition): def edit_partition(self, disk, partition):
log.debug("Editing partition {}".format(partition)) log.debug("Editing partition {}".format(partition))
footer = ("Edit partition details format and mount.") footer = _("Edit partition details format and mount.")
self.ui.set_footer(footer) self.ui.set_footer(footer)
adp_view = PartitionView(self.model, self, disk, partition) adp_view = PartitionView(self.model, self, disk, partition)
self.ui.set_body(adp_view) self.ui.set_body(adp_view)
@ -303,8 +303,8 @@ class FilesystemController(BaseController):
def format_entire(self, disk): def format_entire(self, disk):
log.debug("format_entire {}".format(disk.serial)) log.debug("format_entire {}".format(disk.serial))
header = ("Format and/or mount {}".format(disk.serial)) header = (_("Format and/or mount {}").format(disk.serial))
footer = ("Format or mount whole disk.") footer = _("Format or mount whole disk.")
self.ui.set_header(header) self.ui.set_header(header)
self.ui.set_footer(footer) self.ui.set_footer(footer)
afv_view = FormatEntireView(self.model, self, disk, lambda : self.partition_disk(disk)) afv_view = FormatEntireView(self.model, self, disk, lambda : self.partition_disk(disk))
@ -313,11 +313,11 @@ class FilesystemController(BaseController):
def format_mount_partition(self, partition): def format_mount_partition(self, partition):
log.debug("format_entire {}".format(partition)) log.debug("format_entire {}".format(partition))
if partition.fs() is not None: if partition.fs() is not None:
header = ("Mount partition {} of {}".format(partition.number, partition.device.serial)) header = (_("Mount partition {} of {}").format(partition.number, partition.device.serial))
footer = ("Mount partition.") footer = _("Mount partition.")
else: else:
header = ("Format and mount partition {} of {}".format(partition.number, partition.device.serial)) header = (_("Format and mount partition {} of {}").format(partition.number, partition.device.serial))
footer = ("Format and mount partition.") footer = _("Format and mount partition.")
self.ui.set_header(header) self.ui.set_header(header)
self.ui.set_footer(footer) self.ui.set_footer(footer)
afv_view = FormatEntireView(self.model, self, partition, self.default) afv_view = FormatEntireView(self.model, self, partition, self.default)
@ -382,7 +382,7 @@ class FilesystemController(BaseController):
result = template.format(**dinfo) result = template.format(**dinfo)
log.debug('calling DiskInfoView()') log.debug('calling DiskInfoView()')
disk_info_view = DiskInfoView(self.model, self, disk, result) disk_info_view = DiskInfoView(self.model, self, disk, result)
footer = ('Select next or previous disks with n and p') footer = _('Select next or previous disks with n and p')
self.ui.set_footer(footer, 30) self.ui.set_footer(footer, 30)
self.ui.set_body(disk_info_view) self.ui.set_body(disk_info_view)

View File

@ -33,8 +33,8 @@ class IdentityController(BaseController):
self.model = IdentityModel(self.opts) self.model = IdentityModel(self.opts)
def default(self): def default(self):
title = "Profile setup" title = _("Profile setup")
excerpt = ("Enter the username and password (or ssh identity) you will use to log in to the system.") excerpt = _("Enter the username and password (or ssh identity) you will use to log in to the system.")
footer = "" footer = ""
self.ui.set_header(title, excerpt) self.ui.set_header(title, excerpt)
self.ui.set_footer(footer, 40) self.ui.set_footer(footer, 40)

View File

@ -42,11 +42,11 @@ class InstallpathController(BaseController):
def installpath(self): def installpath(self):
title = "Ubuntu %s"%(lsb_release.get_distro_information()['RELEASE'],) title = "Ubuntu %s"%(lsb_release.get_distro_information()['RELEASE'],)
excerpt = ("Welcome to Ubuntu! The world's favorite platform " excerpt = _("Welcome to Ubuntu! The world's favorite platform "
"for clouds, clusters, and amazing internet things. " "for clouds, clusters, and amazing internet things. "
"This is the installer for Ubuntu on servers and " "This is the installer for Ubuntu on servers and "
"internet devices.") "internet devices.")
footer = ("Use UP, DOWN arrow keys, and ENTER, to " footer = _("Use UP, DOWN arrow keys, and ENTER, to "
"navigate options") "navigate options")
self.ui.set_header(title, excerpt) self.ui.set_header(title, excerpt)

View File

@ -78,9 +78,9 @@ class InstallProgressController(BaseController):
def curtin_error(self): def curtin_error(self):
log.debug('curtin_error') log.debug('curtin_error')
title = ('An error occurred during installation') title = _('An error occurred during installation')
self.ui.set_header(title, 'Please report this error in Launchpad') self.ui.set_header(title, _('Please report this error in Launchpad'))
self.ui.set_footer("An error has occurred.", 100) self.ui.set_footer(_("An error has occurred."), 100)
if self.progress_view is not None: if self.progress_view is not None:
self.progress_view.set_status(('info_error', "An error has occurred")) self.progress_view.set_status(('info_error', "An error has occurred"))
self.progress_view.show_complete() self.progress_view.show_complete()
@ -180,7 +180,7 @@ class InstallProgressController(BaseController):
self.install_state = InstallState.RUNNING_POSTINSTALL self.install_state = InstallState.RUNNING_POSTINSTALL
if self.progress_view is not None: if self.progress_view is not None:
self.progress_view.clear_log_tail() self.progress_view.clear_log_tail()
self.progress_view.set_status("Running postinstall step") self.progress_view.set_status(_("Running postinstall step"))
self.start_tail_proc() self.start_tail_proc()
if self.opts.dry_run: if self.opts.dry_run:
log.debug("Installprogress: this is a dry-run") log.debug("Installprogress: this is a dry-run")
@ -210,9 +210,9 @@ class InstallProgressController(BaseController):
return return
log.debug('After curtin postinstall OK') log.debug('After curtin postinstall OK')
self.install_state = InstallState.DONE_POSTINSTALL self.install_state = InstallState.DONE_POSTINSTALL
self.ui.set_header("Installation complete!", "") self.ui.set_header(_("Installation complete!"), "")
self.ui.set_footer("", 100) self.ui.set_footer("", 100)
self.progress_view.set_status("Finished install!") self.progress_view.set_status(_("Finished install!"))
self.progress_view.show_complete() self.progress_view.show_complete()
def update_log_tail(self): def update_log_tail(self):
@ -270,9 +270,9 @@ class InstallProgressController(BaseController):
def default(self): def default(self):
log.debug('show_progress called') log.debug('show_progress called')
title = ("Installing system") title = _("Installing system")
excerpt = ("Please wait for the installation to finish.") excerpt = _("Please wait for the installation to finish.")
footer = ("Thank you for using Ubuntu!") footer = _("Thank you for using Ubuntu!")
self.ui.set_header(title, excerpt) self.ui.set_header(title, excerpt)
self.ui.set_footer(footer, 90) self.ui.set_footer(footer, 90)
self.progress_view = ProgressView(self.model, self) self.progress_view = ProgressView(self.model, self)
@ -281,9 +281,9 @@ class InstallProgressController(BaseController):
self.ui.set_body(self.progress_view) self.ui.set_body(self.progress_view)
return return
if self.install_state < InstallState.RUNNING_POSTINSTALL: if self.install_state < InstallState.RUNNING_POSTINSTALL:
self.progress_view.set_status("Running install step") self.progress_view.set_status(_("Running install step"))
else: else:
self.progress_view.set_status("Running postinstall step") self.progress_view.set_status(_("Running postinstall step"))
self.ui.set_body(self.progress_view) self.ui.set_body(self.progress_view)
self.start_tail_proc() self.start_tail_proc()

View File

@ -27,9 +27,9 @@ class WelcomeController(BaseController):
self.model = WelcomeModel() self.model = WelcomeModel()
def default(self): def default(self):
title = "Wilkommen! Bienvenue! Welcome! Zdrastvutie! Welkom!" title = "Willkommen! Bienvenue! Welcome! Добро пожаловать! Welkom!"
excerpt = "Please choose your preferred language" excerpt = _("Please choose your preferred language")
footer = ("Use UP, DOWN and ENTER keys to select your language.") footer = _("Use UP, DOWN and ENTER keys to select your language.")
self.ui.set_header(title, excerpt) self.ui.set_header(title, excerpt)
self.ui.set_footer(footer) self.ui.set_footer(footer)
view = WelcomeView(self.model, self) view = WelcomeView(self.model, self)

View File

@ -26,14 +26,16 @@ class InstallpathModel(object):
('UI Text seen by user', <signal name>, <callback function string>) ('UI Text seen by user', <signal name>, <callback function string>)
""" """
# TODO: Re-enable once available def _refresh_install_paths(self):
install_paths = [ # TODO: Re-enable once available
('Install Ubuntu', 'installpath:install-ubuntu'), self.install_paths = [
# ('Install MAAS Region Server', 'installpath:maas-region-server'), (_('Install Ubuntu'), 'installpath:install-ubuntu'),
# ('Install MAAS Cluster Server', 'installpath:maas-cluster-server'), # ('Install MAAS Region Server', 'installpath:maas-region-server'),
# ('Test installation media', 'installpath:test-media'), # ('Install MAAS Cluster Server', 'installpath:maas-cluster-server'),
# ('Test machine memory', 'installpath:test-memory') # ('Test installation media', 'installpath:test-media'),
] # ('Test machine memory', 'installpath:test-memory')
]
def get_menu(self): def get_menu(self):
self._refresh_install_paths()
return self.install_paths return self.install_paths

View File

@ -13,8 +13,9 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import gettext
import logging import logging
from subiquitycore import i18n
log = logging.getLogger('subiquity.models.welcome') log = logging.getLogger('subiquity.models.welcome')
@ -23,13 +24,26 @@ class WelcomeModel(object):
""" Model representing language selection """ Model representing language selection
""" """
supported_languages = [ supported_languages = [('en_US', 'English'), ('ru_RU', 'Russian')]
('English', 'en_US'),
]
selected_language = None selected_language = None
def get_languages(self): def get_languages(self):
return self.supported_languages languages = []
for code, name in self.supported_languages:
label = name
native = name
if gettext.find('iso_639_3'):
cur_lang = gettext.translation('iso_639_3')
label = cur_lang.gettext(name).capitalize()
if gettext.find('iso_639_3', languages=[code]):
native_lang = gettext.translation('iso_639_3', languages=[code])
native = native_lang.gettext(name).capitalize()
languages.append((code, label, native))
return languages
def switch_language(self, code):
self.selected_language = code
i18n.switch_language(code)
def __repr__(self): def __repr__(self):
return "<Selected: {}>".format(self.selected_language) return "<Selected: {}>".format(self.selected_language)

View File

@ -50,9 +50,9 @@ class MountSelector(WidgetWrap):
opts.append(("%-*s (%s)"%(max_len, mnt, devpath), False)) opts.append(("%-*s (%s)"%(max_len, mnt, devpath), False))
if first_opt is None: if first_opt is None:
first_opt = len(opts) first_opt = len(opts)
opts.append(('other', True, OTHER)) opts.append((_('other'), True, OTHER))
opts.append(('---', False)), opts.append(('---', False)),
opts.append(('leave unmounted', True, LEAVE_UNMOUNTED)) opts.append((_('leave unmounted'), True, LEAVE_UNMOUNTED))
self._selector = Selector(opts, first_opt) self._selector = Selector(opts, first_opt)
connect_signal(self._selector, 'select', self._select_mount) connect_signal(self._selector, 'select', self._select_mount)
self._other = _MountEditor(edit_text='/') self._other = _MountEditor(edit_text='/')

View File

@ -114,12 +114,9 @@ class BcacheView(BaseView):
def _build_buttons(self): def _build_buttons(self):
log.debug('bcache: _build_buttons') log.debug('bcache: _build_buttons')
cancel = cancel_btn(on_press=self.cancel)
done = done_btn(on_press=self.done)
buttons = [ buttons = [
Color.button(done), done_btn(on_press=self.done),
Color.button(cancel) cancel_btn(on_press=self.cancel),
] ]
return Pile(buttons) return Pile(buttons)

View File

@ -68,12 +68,9 @@ class CephDiskView(BaseView):
return Pile(items) return Pile(items)
def _build_buttons(self): def _build_buttons(self):
cancel = cancel_btn(on_press=self.cancel)
done = done_btn(on_press=self.done)
buttons = [ buttons = [
Color.button(done), done_btn(on_press=self.done),
Color.button(cancel) cancel_btn(on_press=self.cancel),
] ]
return Pile(buttons) return Pile(buttons)

View File

@ -28,6 +28,7 @@ from urwid import (
) )
from subiquitycore.ui.buttons import ( from subiquitycore.ui.buttons import (
back_btn,
cancel_btn, cancel_btn,
danger_btn, danger_btn,
done_btn, done_btn,
@ -44,11 +45,12 @@ from subiquity.models.filesystem import humanize_size
log = logging.getLogger('subiquity.ui.filesystem.filesystem') log = logging.getLogger('subiquity.ui.filesystem.filesystem')
confirmation_text = """ confirmation_text = _("""\
Selecting Continue below will result of the loss of data on the disks selected to be formatted. Selecting Continue below will begin the installation process and \
result in the loss of data on the disks selected to be formatted.
Are you sure you want to continue? Are you sure you want to continue?
""" """)
class FilesystemConfirmationView(WidgetWrap): class FilesystemConfirmationView(WidgetWrap):
def __init__(self, parent, controller): def __init__(self, parent, controller):
@ -56,11 +58,11 @@ class FilesystemConfirmationView(WidgetWrap):
self.controller = controller self.controller = controller
pile = Pile([ pile = Pile([
UrwidPadding(Text(confirmation_text), left=2, right=2), UrwidPadding(Text(confirmation_text), left=2, right=2),
Padding.fixed_15(cancel_btn(label="No", on_press=self.cancel)), Padding.fixed_15(cancel_btn(label=_("No"), on_press=self.cancel)),
Padding.fixed_15(danger_btn(label="Continue", on_press=self.ok)), Padding.fixed_15(danger_btn(on_press=self.ok)),
Text(""), Text(""),
]) ])
lb = LineBox(pile, title="Confirm destructive action") lb = LineBox(pile, title=_("Confirm destructive action"))
super().__init__(Padding.center_75(lb)) super().__init__(Padding.center_75(lb))
def ok(self, sender): def ok(self, sender):
@ -77,11 +79,11 @@ class FilesystemView(BaseView):
self.controller = controller self.controller = controller
self.items = [] self.items = []
self.body = [ self.body = [
Text("FILE SYSTEM SUMMARY"), Text(_("FILE SYSTEM SUMMARY")),
Text(""), Text(""),
Padding.push_4(self._build_filesystem_list()), Padding.push_4(self._build_filesystem_list()),
Text(""), Text(""),
Text("AVAILABLE DEVICES"), Text(_("AVAILABLE DEVICES")),
Text(""), Text(""),
Padding.push_4(self._build_available_inputs()), Padding.push_4(self._build_available_inputs()),
#self._build_menu(), #self._build_menu(),
@ -143,12 +145,13 @@ class FilesystemView(BaseView):
buttons = [] buttons = []
# don't enable done botton if we can't install # don't enable done botton if we can't install
# XXX should enable/disable button rather than having it appear/disappear I think
if self.model.can_install(): if self.model.can_install():
buttons.append( buttons.append(
done_btn(on_press=self.done)) done_btn(on_press=self.done))
buttons.append(reset_btn(on_press=self.reset)) buttons.append(reset_btn(on_press=self.reset))
buttons.append(cancel_btn(on_press=self.cancel)) buttons.append(back_btn(on_press=self.cancel))
return Pile(buttons) return Pile(buttons)
@ -205,13 +208,13 @@ class FilesystemView(BaseView):
free = disk.free free = disk.free
percent = int(100*free/size) percent = int(100*free/size)
if disk.available and disk.used > 0 and percent > 0: if disk.available and disk.used > 0 and percent > 0:
label = "ADD/EDIT PARTITIONS" label = _("ADD/EDIT PARTITIONS")
size = "{:>9} ({}%) free".format(humanize_size(free), percent) size = "{:>9} ({}%) free".format(humanize_size(free), percent)
elif disk.available and percent > 0: elif disk.available and percent > 0:
label = "ADD FIRST PARTITION" label = _("ADD FIRST PARTITION")
size = "" size = ""
else: else:
label = "EDIT PARTITIONS" label = _("EDIT PARTITIONS")
size = "" size = ""
col2( col2(
menu_btn(label=label, on_press=self.click_disk, user_arg=disk), menu_btn(label=label, on_press=self.click_disk, user_arg=disk),
@ -219,7 +222,7 @@ class FilesystemView(BaseView):
if len(inputs) == 1: if len(inputs) == 1:
return Pile([Color.info_minor( return Pile([Color.info_minor(
Text("No disks available."))]) Text(_("No disks available.")))])
return Pile(inputs) return Pile(inputs)

View File

@ -20,6 +20,7 @@ from urwid import (
from subiquitycore.ui.utils import Padding from subiquitycore.ui.utils import Padding
from subiquitycore.ui.buttons import ( from subiquitycore.ui.buttons import (
back_btn,
cancel_btn, cancel_btn,
menu_btn, menu_btn,
ok_btn, ok_btn,
@ -30,24 +31,24 @@ from subiquitycore.view import BaseView
from subiquity.models.filesystem import humanize_size from subiquity.models.filesystem import humanize_size
text = """The installer can guide you through partitioning a disk or, if \ text = _("""The installer can guide you through partitioning a disk or, if \
you prefer, you can do it manually. If you choose guided partitioning you \ you prefer, you can do it manually. If you choose guided partitioning you \
will still have a chance to review and modify the results.""" will still have a chance to review and modify the results.""")
class GuidedFilesystemView(BaseView): class GuidedFilesystemView(BaseView):
def __init__(self, model, controller): def __init__(self, model, controller):
self.controller = controller self.controller = controller
guided = ok_btn(label="Guided", on_press=self.guided) guided = ok_btn(label=_("Guided"), on_press=self.guided)
manual = ok_btn(label="Manual", on_press=self.manual) manual = ok_btn(label=_("Manual"), on_press=self.manual)
cancel = cancel_btn(on_press=self.cancel) back = back_btn(on_press=self.cancel)
lb = ListBox([ lb = ListBox([
Padding.center_70(Text(text)), Padding.center_70(Text(text)),
Padding.center_70(Text("")), Padding.center_70(Text("")),
Padding.fixed_10(guided), Padding.fixed_10(guided),
Padding.fixed_10(manual), Padding.fixed_10(manual),
Padding.fixed_10(cancel), Padding.fixed_10(back),
]) ])
super().__init__(lb) super().__init__(lb)
@ -75,7 +76,7 @@ class GuidedDiskSelectionView(BaseView):
on_press=self.choose_disk, user_arg=disk) on_press=self.choose_disk, user_arg=disk)
disks.append(disk_btn) disks.append(disk_btn)
lb = ListBox([ lb = ListBox([
Padding.center_70(Text("Choose the disk to install to:")), Padding.center_70(Text(_("Choose the disk to install to:"))),
Padding.center_70(Text("")), Padding.center_70(Text("")),
Padding.center_70(Pile(disks)), Padding.center_70(Pile(disks)),
Padding.center_70(Text("")), Padding.center_70(Text("")),

View File

@ -22,7 +22,7 @@ configuration.
import logging import logging
from urwid import connect_signal, Text from urwid import connect_signal, Text
from subiquitycore.ui.buttons import danger_btn from subiquitycore.ui.buttons import delete_btn
from subiquitycore.ui.container import ListBox from subiquitycore.ui.container import ListBox
from subiquitycore.ui.form import ( from subiquitycore.ui.form import (
Form, Form,
@ -107,6 +107,9 @@ class PartitionForm(Form):
class PartitionFormatView(BaseView): class PartitionFormatView(BaseView):
form_cls = PartitionForm
def __init__(self, size, existing, initial, back): def __init__(self, size, existing, initial, back):
mountpoint_to_devpath_mapping = self.model.get_mountpoint_to_devpath_mapping() mountpoint_to_devpath_mapping = self.model.get_mountpoint_to_devpath_mapping()
@ -119,7 +122,7 @@ class PartitionFormatView(BaseView):
initial['mount'] = mount.path initial['mount'] = mount.path
if mount.path in mountpoint_to_devpath_mapping: if mount.path in mountpoint_to_devpath_mapping:
del mountpoint_to_devpath_mapping[mount.path] del mountpoint_to_devpath_mapping[mount.path]
self.form = PartitionForm(mountpoint_to_devpath_mapping, size, initial) self.form = self.form_cls(mountpoint_to_devpath_mapping, size, initial)
self.back = back self.back = back
connect_signal(self.form, 'submit', self.done) connect_signal(self.form, 'submit', self.done)
@ -151,21 +154,24 @@ class PartitionView(PartitionFormatView):
max_size = disk.free max_size = disk.free
if partition is None: if partition is None:
initial = {'partnum': disk.next_partnum} initial = {'partnum': disk.next_partnum}
label = _("Create")
else: else:
max_size += partition.size max_size += partition.size
initial = { initial = {
'partnum': partition.number, 'partnum': partition.number,
'size': humanize_size(partition.size), 'size': humanize_size(partition.size),
} }
label = _("Save")
super().__init__(max_size, partition, initial, lambda : self.controller.partition_disk(disk)) super().__init__(max_size, partition, initial, lambda : self.controller.partition_disk(disk))
self.form.buttons[0].set_label(label)
def make_body(self): def make_body(self):
body = super().make_body() body = super().make_body()
if self.partition is not None: if self.partition is not None:
delete_btn = danger_btn("Delete", on_press=self.delete) btn = delete_btn(on_press=self.delete)
body[-2:-2] = [ body[-2:-2] = [
Text(""), Text(""),
Padding.fixed_10(Color.info_error(delete_btn)), Padding.fixed_10(btn),
] ]
pass pass
return body return body

View File

@ -46,52 +46,52 @@ PasswordField = simple_field(PasswordEditor)
class IdentityForm(Form): class IdentityForm(Form):
realname = RealnameField("Your name:") realname = RealnameField(_("Your name:"))
hostname = UsernameField( hostname = UsernameField(
"Your server's name:", _("Your server's name:"),
help="The name it uses when it talks to other computers.") help=_("The name it uses when it talks to other computers."))
username = UsernameField("Pick a username:") username = UsernameField(_("Pick a username:"))
password = PasswordField("Choose a password:") password = PasswordField(_("Choose a password:"))
confirm_password = PasswordField("Confirm your password:") confirm_password = PasswordField(_("Confirm your password:"))
ssh_import_id = StringField( ssh_import_id = StringField(
"Import SSH identity:", _("Import SSH identity:"),
help=("Input your SSH user id from Ubuntu SSO (sso:email), " help=(_("Input your SSH user id from Ubuntu SSO (sso:email), "
"Launchpad (lp:username) or Github (gh:username).")) "Launchpad (lp:username) or Github (gh:username).")))
def validate_realname(self): def validate_realname(self):
if len(self.realname.value) < 1: if len(self.realname.value) < 1:
return "Real name must not be empty." return _("Real name must not be empty.")
if len(self.realname.value) > REALNAME_MAXLEN: if len(self.realname.value) > REALNAME_MAXLEN:
return "Realname too long, must be < " + str(REALNAME_MAXLEN) return _("Realname too long, must be < ") + str(REALNAME_MAXLEN)
def validate_hostname(self): def validate_hostname(self):
if len(self.hostname.value) < 1: if len(self.hostname.value) < 1:
return "Server name must not be empty" return _("Server name must not be empty")
if len(self.hostname.value) > HOSTNAME_MAXLEN: if len(self.hostname.value) > HOSTNAME_MAXLEN:
return "Server name too long, must be < " + str(HOSTNAME_MAXLEN) return _("Server name too long, must be < ") + str(HOSTNAME_MAXLEN)
def validate_username(self): def validate_username(self):
if len(self.username.value) < 1: if len(self.username.value) < 1:
return "Username missing" return _("Username missing")
if len(self.username.value) > USERNAME_MAXLEN: if len(self.username.value) > USERNAME_MAXLEN:
return "Username too long, must be < " + str(USERNAME_MAXLEN) return _("Username too long, must be < ") + str(USERNAME_MAXLEN)
def validate_password(self): def validate_password(self):
# XXX we should not require a password if an ssh identity is provided # XXX we should not require a password if an ssh identity is provided
# Form doesn't support form-wide validation yet though, oops. # Form doesn't support form-wide validation yet though, oops.
if len(self.password.value) < 1: if len(self.password.value) < 1:
return "Password must be set" return _("Password must be set")
def validate_confirm_password(self): def validate_confirm_password(self):
if self.password.value != self.confirm_password.value: if self.password.value != self.confirm_password.value:
return "Passwords do not match" return _("Passwords do not match")
self.password.validate() self.password.validate()
def validate_ssh_import_id(self): def validate_ssh_import_id(self):
if len(self.ssh_import_id.value) > SSH_IMPORT_MAXLEN: if len(self.ssh_import_id.value) > SSH_IMPORT_MAXLEN:
return "SSH id too long, must be < " + str(SSH_IMPORT_MAXLEN) return _("SSH id too long, must be < ") + str(SSH_IMPORT_MAXLEN)
class IdentityView(BaseView): class IdentityView(BaseView):

View File

@ -22,8 +22,8 @@ import logging
from urwid import BoxAdapter from urwid import BoxAdapter
from subiquitycore.ui.lists import SimpleList from subiquitycore.ui.lists import SimpleList
from subiquitycore.ui.buttons import menu_btn, cancel_btn from subiquitycore.ui.buttons import back_btn, menu_btn
from subiquitycore.ui.utils import Padding, Color from subiquitycore.ui.utils import Padding
from subiquitycore.ui.container import ListBox, Pile from subiquitycore.ui.container import ListBox, Pile
from subiquitycore.view import BaseView from subiquitycore.view import BaseView
@ -44,7 +44,7 @@ class InstallpathView(BaseView):
def _build_buttons(self): def _build_buttons(self):
self.buttons = [ self.buttons = [
cancel_btn(on_press=self.cancel), back_btn(on_press=self.cancel),
] ]
return Pile(self.buttons) return Pile(self.buttons)

View File

@ -21,7 +21,7 @@ from urwid import (
) )
from subiquitycore.view import BaseView from subiquitycore.view import BaseView
from subiquitycore.ui.buttons import cancel_btn, confirm_btn from subiquitycore.ui.buttons import cancel_btn, ok_btn
from subiquitycore.ui.container import ListBox, Pile from subiquitycore.ui.container import ListBox, Pile
from subiquitycore.ui.utils import Padding from subiquitycore.ui.utils import Padding
@ -62,10 +62,10 @@ class ProgressView(BaseView):
def show_complete(self): def show_complete(self):
w = Padding.fixed_20( w = Padding.fixed_20(
confirm_btn(label="Reboot Now", on_press=self.reboot)) ok_btn(label=_("Reboot Now"), on_press=self.reboot))
z = Padding.fixed_20( z = Padding.fixed_20(
cancel_btn(label="Quit Installer", on_press=self.quit)) cancel_btn(label=_("Quit Installer"), on_press=self.quit))
new_focus = len(self.pile.contents) new_focus = len(self.pile.contents)
self.pile.contents.append((w, self.pile.options('pack'))) self.pile.contents.append((w, self.pile.options('pack')))

View File

@ -19,7 +19,7 @@ Welcome provides user with language selection
""" """
import logging import logging
from urwid import BoxAdapter, Text from urwid import BoxAdapter, Text, connect_signal
from subiquitycore.ui.lists import SimpleList from subiquitycore.ui.lists import SimpleList
from subiquitycore.ui.buttons import menu_btn from subiquitycore.ui.buttons import menu_btn
from subiquitycore.ui.container import ListBox from subiquitycore.ui.container import ListBox
@ -37,16 +37,16 @@ class WelcomeView(BaseView):
super().__init__(ListBox([ super().__init__(ListBox([
Padding.center_50(self._build_model_inputs()), Padding.center_50(self._build_model_inputs()),
Text(""), Text(""),
Padding.center_79(Text("(More language choices will appear in time)"))])) Padding.center_79(Text(_("(More language choices will appear in time)")))]))
def _build_model_inputs(self): def _build_model_inputs(self):
sl = [] sl = []
for lang, code in self.model.get_languages(): for code, label, native in self.model.get_languages():
sl.append(menu_btn(label=lang, on_press=self.confirm, user_arg=code)) sl.append(menu_btn(label=native, on_press=self.confirm, user_arg=code))
return BoxAdapter(SimpleList(sl), height=len(sl)) return BoxAdapter(SimpleList(sl), height=len(sl))
def confirm(self, sender, code): def confirm(self, sender, code):
self.model.selected_language = code self.model.switch_language(code)
log.debug('calling installpath') log.debug('calling installpath')
self.controller.done() self.controller.done()

View File

@ -344,11 +344,11 @@ class NetworkController(BaseController):
self.signal.emit_signal('prev-screen') self.signal.emit_signal('prev-screen')
def default(self): def default(self):
title = "Network connections" title = _("Network connections")
excerpt = ("Configure at least one interface this server can use to talk to " excerpt = _("Configure at least one interface this server can use to talk to "
"other machines, and which preferably provides sufficient access for " "other machines, and which preferably provides sufficient access for "
"updates.") "updates.")
footer = ("Select an interface to configure it or select Done to continue") footer = _("Select an interface to configure it or select Done to continue")
self.ui.set_header(title, excerpt) self.ui.set_header(title, excerpt)
self.ui.set_footer(footer, 20) self.ui.set_footer(footer, 20)
self.ui.set_body(NetworkView(self.model, self)) self.ui.set_body(NetworkView(self.model, self))

40
subiquitycore/i18n.py Normal file
View File

@ -0,0 +1,40 @@
# Copyright 2017 Canonical, Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import gettext
import os
import syslog
syslog.syslog('i18n file is ' + __file__)
localedir = '/usr/share/locale'
if __file__.startswith('/snap/'):
localedir = os.path.realpath(__file__ + '/../../../../../share/locale')
build_mo = os.path.realpath(__file__ + '/../../build/mo/')
if os.path.isdir(build_mo):
localedir = build_mo
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
elif code:
translation = gettext.translation('subiquity', localedir=localedir, languages=[code])
translation.install()
switch_language()
__all__ = ['switch_language']

View File

@ -1,4 +1,4 @@
# Copyright 2015 Canonical, Ltd. # Copyright 2017 Canonical, Ltd.
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as # it under the terms of the GNU Affero General Public License as
@ -13,44 +13,35 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from functools import partial from urwid import AttrMap, Button, Text
from urwid import AttrWrap, Button, connect_signal, Text def _stylized_button(left, right, stocklabel, style):
class Btn(Button):
button_left = Text(left)
button_right = Text(right)
class PlainButton(Button): class StyleAttrMap(AttrMap):
button_left = Text("[") def __init__(self, *args, **kwargs):
button_right = Text("]") label = kwargs.pop('label', _(stocklabel))
btn = Btn(label, *args, **kwargs)
super().__init__(btn, style + '_button', style + '_button focus')
return StyleAttrMap
def stylized_button(stocklabel, style):
class MenuSelectButton(Button): return _stylized_button('[', ']', stocklabel, style)
button_left = Text("")
button_right = Text(">")
def plain_btn(label, color, on_press=None, user_arg=None):
button = PlainButton(label=label)
if on_press is not None:
connect_signal(button, 'click', on_press, user_arg)
return AttrWrap(button, color, color + ' focus')
start_btn = partial(plain_btn, label="Start", color="save_button")
save_btn = partial(plain_btn, label="Save", color="save_button")
finish_btn = partial(plain_btn, label="Finish", color="save_button")
ok_btn = partial(plain_btn, label="OK", color="save_button")
confirm_btn = partial(plain_btn, label="Confirm", color="save_button")
done_btn = partial(plain_btn, label="Done", color="save_button")
continue_btn = partial(plain_btn, label="Continue", color="save_button")
reset_btn = partial(plain_btn, label="Reset", color="reset_button")
cancel_btn = partial(plain_btn, label="Cancel", color="cancel_button")
back_btn = partial(plain_btn, label="Back", color="cancel_button")
danger_btn = partial(plain_btn, color="danger_button")
def menu_btn(label, on_press=None, user_arg=None): def menu_btn(label, on_press=None, user_arg=None):
button = MenuSelectButton(label=label) MenuBtn=_stylized_button('', '>', label, 'menu')
if on_press is not None: return MenuBtn(on_press=on_press, user_data=user_arg)
connect_signal(button, 'click', on_press, user_arg)
return AttrWrap(button, 'menu_button', 'menu_button focus') ok_btn = stylized_button("OK", "save")
done_btn = stylized_button("Done", "save")
reset_btn = stylized_button("Reset", "reset")
back_btn = stylized_button("Back", "cancel")
cancel_btn = stylized_button("Cancel", "cancel")
close_btn = stylized_button("Close", "cancel")
danger_btn = stylized_button("Continue", "danger")
delete_btn = stylized_button("Delete", "danger")

View File

@ -35,8 +35,7 @@ class DummyView(WidgetWrap):
def _build_buttons(self): def _build_buttons(self):
buttons = [ buttons = [
Color.button(cancel_btn(label="Back to Start", cancel_btn(label="Back to Start", on_press=self.cancel),
on_press=self.cancel)),
] ]
return Pile(buttons) return Pile(buttons)

View File

@ -40,8 +40,7 @@ class ErrorView(WidgetWrap):
def _build_buttons(self): def _build_buttons(self):
buttons = [ buttons = [
Color.button(cancel_btn(label="Back to Start", cancel_btn(label="Back to Start", on_press=self.cancel),
on_press=self.cancel)),
] ]
return Pile(buttons) return Pile(buttons)

View File

@ -258,10 +258,10 @@ class Form(object, metaclass=MetaForm):
signals = ['submit', 'cancel'] signals = ['submit', 'cancel']
opts = {} ok_label = _("Done")
def __init__(self, initial={}): def __init__(self, initial={}):
self.done_btn = Toggleable(done_btn(on_press=self._click_done)) self.done_btn = Toggleable(done_btn(label=self.ok_label, on_press=self._click_done))
self.cancel_btn = Toggleable(cancel_btn(on_press=self._click_cancel)) self.cancel_btn = Toggleable(cancel_btn(on_press=self._click_cancel))
self.buttons = Pile([self.done_btn, self.cancel_btn]) self.buttons = Pile([self.done_btn, self.cancel_btn])
self._fields = [] self._fields = []

View File

@ -30,7 +30,7 @@ from urwid import (
WidgetWrap, WidgetWrap,
) )
from subiquitycore.ui.buttons import PlainButton from subiquitycore.ui.buttons import close_btn
from subiquitycore.ui.container import Pile from subiquitycore.ui.container import Pile
from subiquitycore.ui.selector import Selector from subiquitycore.ui.selector import Selector
from subiquitycore.ui.utils import Color, Padding from subiquitycore.ui.utils import Color, Padding
@ -111,15 +111,15 @@ class YesNo(Selector):
""" Yes/No selector """ Yes/No selector
""" """
def __init__(self): def __init__(self):
opts = ['Yes', 'No'] opts = [_('Yes'), _('No')]
super().__init__(opts) super().__init__(opts)
class _HelpDisplay(WidgetWrap): class _HelpDisplay(WidgetWrap):
def __init__(self, closer, help_text): def __init__(self, closer, help_text):
self._closer = closer self._closer = closer
button = Color.button(PlainButton(label="Close", on_press=lambda btn:self._closer())) button = close_btn(on_press=lambda btn:self._closer())
super().__init__(LineBox(Pile([Text(help_text), Padding.fixed_10(button)]), title="Help")) super().__init__(LineBox(Pile([Text(help_text), Padding.fixed_10(button)]), title=_("Help")))
class Help(WidgetWrap): class Help(WidgetWrap):

View File

@ -20,7 +20,7 @@ Login provides user with language selection
""" """
import logging import logging
from urwid import Text from urwid import Text
from subiquitycore.ui.buttons import finish_btn from subiquitycore.ui.buttons import done_btn
from subiquitycore.ui.container import Pile, ListBox from subiquitycore.ui.container import Pile, ListBox
from subiquitycore.ui.utils import Padding, Color from subiquitycore.ui.utils import Padding, Color
from subiquitycore.view import BaseView from subiquitycore.view import BaseView
@ -46,7 +46,7 @@ class LoginView(BaseView):
def _build_buttons(self): def _build_buttons(self):
self.buttons = [ self.buttons = [
Color.button(finish_btn(on_press=self.done)), done_btn(on_press=self.done),
] ]
return Pile(self.buttons) return Pile(self.buttons)

View File

@ -29,7 +29,7 @@ from urwid import (
WidgetWrap, WidgetWrap,
) )
from subiquitycore.ui.buttons import cancel_btn, menu_btn, done_btn from subiquitycore.ui.buttons import back_btn, cancel_btn, done_btn, menu_btn
from subiquitycore.ui.container import Columns, ListBox, Pile from subiquitycore.ui.container import Columns, ListBox, Pile
from subiquitycore.ui.utils import Padding, Color from subiquitycore.ui.utils import Padding, Color
from subiquitycore.view import BaseView from subiquitycore.view import BaseView
@ -48,7 +48,7 @@ class ApplyingConfigWidget(WidgetWrap):
current=0, done=step_count) current=0, done=step_count)
box = LineBox(Pile([self.bar, box = LineBox(Pile([self.bar,
Padding.fixed_10(button)]), Padding.fixed_10(button)]),
title="Applying network config") title=_("Applying network config"))
super().__init__(box) super().__init__(box)
def advance(self): def advance(self):
@ -62,16 +62,16 @@ def _build_wifi_info(dev):
if dev.actual_ssid is not None: if dev.actual_ssid is not None:
if dev.configured_ssid is not None: if dev.configured_ssid is not None:
if dev.actual_ssid != dev.configured_ssid: if dev.actual_ssid != dev.configured_ssid:
r.append(Text("Associated to '%s', will associate to '%s'"%(dev.actual_ssid, dev.configured_ssid))) r.append(Text(_("Associated to '%s', will associate to '%s'" % (dev.actual_ssid, dev.configured_ssid))))
else: else:
r.append(Text("Associated to '" + dev.actual_ssid + "'")) r.append(Text(_("Associated to '%s'" % dev.actual_ssid)))
else: else:
r.append(Text("No access point configured, but associated to '%s'"%(dev.actual_ssid,))) r.append(Text(_("No access point configured, but associated to '%s'" % dev.actual_ssid)))
else: else:
if dev.configured_ssid is not None: if dev.configured_ssid is not None:
r.append(Text("Will associate to '" + dev.configured_ssid + "'")) r.append(Text(_("Will associate to '%s'" % dev.configured_ssid)))
else: else:
r.append(Text("No access point configured")) r.append(Text(_("No access point configured")))
return r return r
def _format_address_list(label, addresses): def _format_address_list(label, addresses):
@ -91,19 +91,19 @@ def _build_gateway_ip_info_for_version(dev, version):
configured_ip_addresses = dev.configured_ip_addresses_for_version(version) configured_ip_addresses = dev.configured_ip_addresses_for_version(version)
if dev.dhcp_for_version(version): if dev.dhcp_for_version(version):
if dev.actual_ip_addresses: if dev.actual_ip_addresses:
return _format_address_list("Will use DHCP for IPv%s, currently has address%%s:"%(version,), actual_ip_addresses) return _format_address_list(_("Will use DHCP for IPv%s, currently has address%%s:" % version), actual_ip_addresses)
return [Text("Will use DHCP for IPv%s"%(version,))] return [Text(_("Will use DHCP for IPv%s" % version))]
elif configured_ip_addresses: elif configured_ip_addresses:
if sorted(actual_ip_addresses) == sorted(configured_ip_addresses): if sorted(actual_ip_addresses) == sorted(configured_ip_addresses):
return _format_address_list("Using static address%%s for IPv%s:"%(version,), actual_ip_addresses) return _format_address_list(_("Using static address%%s for IPv%s:" % version), actual_ip_addresses)
p = _format_address_list("Will use static address%%s for IPv%s:"%(version,), configured_ip_addresses) p = _format_address_list(_("Will use static address%%s for IPv%s:" % version), configured_ip_addresses)
if actual_ip_addresses: if actual_ip_addresses:
p.extend(_format_address_list("Currently has address%s:", actual_ip_addresses)) p.extend(_format_address_list(_("Currently has address%s:"), actual_ip_addresses))
return p return p
elif actual_ip_addresses: elif actual_ip_addresses:
return _format_address_list("Has no IPv%s configuration, currently has address%%s:"%(version,), actual_ip_addresses) return _format_address_list(_("Has no IPv%s configuration, currently has address%%s:" % version), actual_ip_addresses)
else: else:
return [Text("IPv%s is not configured"%(version,))] return [Text(_("IPv%s is not configured" % version))]
class NetworkView(BaseView): class NetworkView(BaseView):
@ -132,11 +132,11 @@ class NetworkView(BaseView):
super().__init__(self.frame) super().__init__(self.frame)
def _build_buttons(self): def _build_buttons(self):
cancel = cancel_btn(on_press=self.cancel) back = back_btn(on_press=self.cancel)
done = done_btn(on_press=self.done) done = done_btn(on_press=self.done)
self.default_focus = done self.default_focus = done
buttons = [done, cancel] buttons = [done, back]
return Pile(buttons, focus_item=done) return Pile(buttons, focus_item=done)
def _build_model_inputs(self): def _build_model_inputs(self):
@ -162,7 +162,7 @@ class NetworkView(BaseView):
if dev.type == 'wlan': if dev.type == 'wlan':
col_2.extend(_build_wifi_info(dev)) col_2.extend(_build_wifi_info(dev))
if len(dev.actual_ip_addresses) == 0 and dev.type == 'eth' and not dev.is_connected: if len(dev.actual_ip_addresses) == 0 and dev.type == 'eth' and not dev.is_connected:
col_2.append(Color.info_primary(Text("Not connected"))) col_2.append(Color.info_primary(Text(_("Not connected"))))
col_2.extend(_build_gateway_ip_info_for_version(dev, 4)) col_2.extend(_build_gateway_ip_info_for_version(dev, 4))
col_2.extend(_build_gateway_ip_info_for_version(dev, 6)) col_2.extend(_build_gateway_ip_info_for_version(dev, 6))
@ -170,8 +170,10 @@ class NetworkView(BaseView):
template = '' template = ''
if dev.hwaddr: if dev.hwaddr:
template += '{} '.format(dev.hwaddr) template += '{} '.format(dev.hwaddr)
## TODO is this to translate?
if dev.is_bond_slave: if dev.is_bond_slave:
template += '(Bonded) ' template += '(Bonded) '
## TODO to check if this is affected by translations
if not dev.vendor.lower().startswith('unknown'): if not dev.vendor.lower().startswith('unknown'):
vendor = textwrap.wrap(dev.vendor, 15)[0] vendor = textwrap.wrap(dev.vendor, 15)[0]
template += '{} '.format(vendor) template += '{} '.format(vendor)
@ -199,7 +201,7 @@ class NetworkView(BaseView):
v4_route_source = "via " + self.model.default_v4_gateway v4_route_source = "via " + self.model.default_v4_gateway
default_v4_route_w = Color.info_minor( default_v4_route_w = Color.info_minor(
Text(" IPv4 default route " + v4_route_source + ".")) Text(_(" IPv4 default route %s." % v4_route_source)))
labels.append(default_v4_route_w) labels.append(default_v4_route_w)
if self.model.default_v6_gateway is not None: if self.model.default_v6_gateway is not None:

View File

@ -62,16 +62,14 @@ class NetworkConfigureInterfaceView(BaseView):
def _build_ipv4_method_buttons(self): def _build_ipv4_method_buttons(self):
button_padding = 70 button_padding = 70
buttons = [] buttons = [
btn = menu_btn(label="Use a static IPv4 configuration", menu_btn(label=_("Use a static IPv4 configuration"),
on_press=self.show_ipv4_configuration) on_press=self.show_ipv4_configuration),
buttons.append(Color.menu_button(btn)) menu_btn(label=_("Use DHCPv4 on this interface"),
btn = menu_btn(label="Use DHCPv4 on this interface", on_press=self.enable_dhcp4),
on_press=self.enable_dhcp4) menu_btn(label=_("Do not use"),
buttons.append(Color.menu_button(btn)) on_press=self.clear_ipv4),
btn = menu_btn(label="Do not use", ]
on_press=self.clear_ipv4)
buttons.append(Color.menu_button(btn))
padding = getattr(Padding, 'left_{}'.format(button_padding)) padding = getattr(Padding, 'left_{}'.format(button_padding))
buttons = [ padding(button) for button in buttons ] buttons = [ padding(button) for button in buttons ]
@ -81,16 +79,14 @@ class NetworkConfigureInterfaceView(BaseView):
def _build_ipv6_method_buttons(self): def _build_ipv6_method_buttons(self):
button_padding = 70 button_padding = 70
buttons = [] buttons = [
btn = menu_btn(label="Use a static IPv6 configuration", menu_btn(label=_("Use a static IPv6 configuration"),
on_press=self.show_ipv6_configuration) on_press=self.show_ipv6_configuration),
buttons.append(Color.menu_button(btn)) menu_btn(label=_("Use DHCPv6 on this interface"),
btn = menu_btn(label="Use DHCPv6 on this interface", on_press=self.enable_dhcp6),
on_press=self.enable_dhcp6) menu_btn(label=_("Do not use"),
buttons.append(Color.menu_button(btn)) on_press=self.clear_ipv6),
btn = menu_btn(label="Do not use", ]
on_press=self.clear_ipv6)
buttons.append(Color.menu_button(btn))
padding = getattr(Padding, 'left_{}'.format(button_padding)) padding = getattr(Padding, 'left_{}'.format(button_padding))
buttons = [ padding(button) for button in buttons ] buttons = [ padding(button) for button in buttons ]
@ -99,14 +95,12 @@ class NetworkConfigureInterfaceView(BaseView):
def _build_wifi_config(self): def _build_wifi_config(self):
btn = menu_btn(label="Configure WIFI settings", on_press=self.show_wlan_configuration) btn = menu_btn(label=_("Configure WIFI settings"), on_press=self.show_wlan_configuration)
return [Padding.left_70(Color.menu_button(btn))] return [Padding.left_70(btn)]
def _build_buttons(self): def _build_buttons(self):
done = done_btn(on_press=self.done)
buttons = [ buttons = [
Color.button(done), done_btn(on_press=self.done)
] ]
return Pile(buttons) return Pile(buttons)

View File

@ -64,11 +64,12 @@ class NetworkConfigForm(Form):
self.ip_address_cls = fam['address_cls'] self.ip_address_cls = fam['address_cls']
self.ip_network_cls = fam['network_cls'] self.ip_network_cls = fam['network_cls']
subnet = IPField("Subnet:", has_mask=True) ok_label = _("Save")
address = IPField("Address:") subnet = IPField(_("Subnet:"), has_mask=True)
gateway = IPField("Gateway:") address = IPField(_("Address:"))
nameservers = StringField("Name servers:", help="IP addresses, comma separated") gateway = IPField(_("Gateway:"))
searchdomains = StringField("Search domains:", help="Domains, comma separated") nameservers = StringField(_("Name servers:"), help=_("IP addresses, comma separated"))
searchdomains = StringField(_("Search domains:"), help=_("Domains, comma separated"))
def clean_subnet(self, subnet): def clean_subnet(self, subnet):
log.debug("clean_subnet %r", subnet) log.debug("clean_subnet %r", subnet)
@ -119,7 +120,7 @@ class BaseNetworkConfigureManualView(BaseView):
connect_signal(self.form, 'submit', self.done) connect_signal(self.form, 'submit', self.done)
connect_signal(self.form, 'cancel', self.cancel) connect_signal(self.form, 'cancel', self.cancel)
self.form.subnet.help = "CIDR e.g. %s"%(self.example_address,) self.form.subnet.help = _("CIDR e.g. %s"%(self.example_address,))
configured_addresses = self.dev.configured_ip_addresses_for_version(self.ip_version) configured_addresses = self.dev.configured_ip_addresses_for_version(self.ip_version)
if configured_addresses: if configured_addresses:
addr = ipaddress.ip_interface(configured_addresses[0]) addr = ipaddress.ip_interface(configured_addresses[0])
@ -155,10 +156,10 @@ class BaseNetworkConfigureManualView(BaseView):
self.is_gateway = self.model.v4_gateway_dev == self.dev.name self.is_gateway = self.model.v4_gateway_dev == self.dev.name
if not self.is_gateway and len(devs) > 1: if not self.is_gateway and len(devs) > 1:
btn = menu_btn(label="Set this as default gateway", btn = menu_btn(label=_("Set this as default gateway"),
on_press=self.set_default_gateway) on_press=self.set_default_gateway)
else: else:
btn = Text("This will be your default gateway") btn = Text(_("This will be your default gateway"))
return [btn] return [btn]

View File

@ -20,10 +20,7 @@ class NetworkList(WidgetWrap):
def __init__(self, parent, ssids): def __init__(self, parent, ssids):
self.parent = parent self.parent = parent
button = cancel_btn(on_press=self.do_cancel) button = cancel_btn(on_press=self.do_cancel)
ssid_list = [ ssid_list = [menu_btn(label=ssid, on_press=self.do_network) for ssid in ssids]
Color.menu_button(
Button(label=ssid, on_press=self.do_network))
for ssid in ssids]
p = Pile([BoxAdapter(ListBox(ssid_list), height=10), Padding.fixed_10(button)]) p = Pile([BoxAdapter(ListBox(ssid_list), height=10), Padding.fixed_10(button)])
box = LineBox(p, title="Select a network") box = LineBox(p, title="Select a network")
super().__init__(box) super().__init__(box)
@ -38,6 +35,8 @@ class NetworkList(WidgetWrap):
class WLANForm(Form): class WLANForm(Form):
ok_label = _("Save")
ssid = StringField(caption="Network Name:") ssid = StringField(caption="Network Name:")
psk = PasswordField(caption="Password:") psk = PasswordField(caption="Password:")
@ -95,8 +94,7 @@ class NetworkConfigureWLANView(BaseView):
def _build_iface_inputs(self): def _build_iface_inputs(self):
if len(self.dev.actual_ssids) > 0: if len(self.dev.actual_ssids) > 0:
networks_btn = Color.menu_button( networks_btn = menu_btn("Choose a visible network", on_press=self.show_ssid_list)
menu_btn("Choose a visible network", on_press=self.show_ssid_list))
else: else:
networks_btn = Color.info_minor(Columns( networks_btn = Color.info_minor(Columns(
[ [
@ -106,8 +104,7 @@ class NetworkConfigureWLANView(BaseView):
], dividechars=1)) ], dividechars=1))
if not self.dev.scan_state: if not self.dev.scan_state:
scan_btn = Color.menu_button( scan_btn = menu_btn("Scan for networks", on_press=self.start_scan)
menu_btn("Scan for networks", on_press=self.start_scan))
else: else:
scan_btn = Color.info_minor(Columns( scan_btn = Color.info_minor(Columns(
[ [

View File

@ -78,30 +78,26 @@ class NetworkSetDefaultRouteView(BaseView):
log.debug('gateway providers: {}'.format(providers)) log.debug('gateway providers: {}'.format(providers))
items = [] items = []
items.append(Padding.center_79( items.append(Padding.center_79(
Color.menu_button(menu_btn(label="None", on_press=self.done)))) menu_btn(label="None", on_press=self.done)))
for (gw, ifaces) in providers.items(): for (gw, ifaces) in providers.items():
if gw is None: if gw is None:
continue continue
items.append(Padding.center_79( items.append(Padding.center_79(
Color.menu_button(menu_btn( menu_btn(
label="{gw} ({ifaces})".format( label="{gw} ({ifaces})".format(
gw=gw, gw=gw,
ifaces=(",".join(ifaces))), ifaces=(",".join(ifaces))),
on_press=self.done)))) on_press=self.done)))
items.append(Padding.center_79( items.append(Padding.center_79(
Color.menu_button( menu_btn(label="Specify the default route manually",
menu_btn(label="Specify the default route manually", on_press=self.show_edit_default_route)))
on_press=self.show_edit_default_route))))
return items return items
def _build_buttons(self): def _build_buttons(self):
cancel = cancel_btn(on_press=self.cancel)
done = done_btn(on_press=self.done)
buttons = [ buttons = [
Color.button(done), done_btn(on_press=self.done),
Color.button(cancel) cancel_btn(on_press=self.cancel),
] ]
return Pile(buttons) return Pile(buttons)