Commit 5d0363b6 authored by Tijmen de Mes's avatar Tijmen de Mes

Allow python strings to be translated

parent d0a4a70d
...@@ -3,7 +3,7 @@ from PyQt5 import uic ...@@ -3,7 +3,7 @@ from PyQt5 import uic
from blink import __date__, __version__ from blink import __date__, __version__
from blink.resources import Resources from blink.resources import Resources
from blink.util import QSingleton from blink.util import QSingleton, translate
__all__ = ['AboutPanel'] __all__ = ['AboutPanel']
...@@ -41,7 +41,7 @@ class AboutPanel(base_class, ui_class, metaclass=QSingleton): ...@@ -41,7 +41,7 @@ class AboutPanel(base_class, ui_class, metaclass=QSingleton):
with Resources.directory: with Resources.directory:
self.setupUi(self) self.setupUi(self)
self.version.setText('Version %s\n%s' % (__version__, __date__)) self.version.setText(translate('about_panel', 'Version %s\n%s') % (__version__, __date__))
credits_width = self.credits_text.fontMetrics().width("NLnet Foundation" + "http://sipsimpleclient.org") + 40 credits_width = self.credits_text.fontMetrics().width("NLnet Foundation" + "http://sipsimpleclient.org") + 40
self.credits_text.setFixedWidth(credits_width) self.credits_text.setFixedWidth(credits_width)
......
...@@ -32,7 +32,7 @@ from blink.contacts import URIUtils ...@@ -32,7 +32,7 @@ from blink.contacts import URIUtils
from blink.resources import ApplicationData, IconManager, Resources from blink.resources import ApplicationData, IconManager, Resources
from blink.sessions import SessionManager, StreamDescription from blink.sessions import SessionManager, StreamDescription
from blink.widgets.labels import Status from blink.widgets.labels import Status
from blink.util import QSingleton, call_in_gui_thread, run_in_gui_thread from blink.util import QSingleton, call_in_gui_thread, run_in_gui_thread, translate
__all__ = ['AccountModel', 'ActiveAccountModel', 'AccountSelector', 'AddAccountDialog', 'ServerToolsAccountModel', 'ServerToolsWindow'] __all__ = ['AccountModel', 'ActiveAccountModel', 'AccountSelector', 'AddAccountDialog', 'ServerToolsAccountModel', 'ServerToolsWindow']
...@@ -379,7 +379,7 @@ class AddAccountDialog(base_class, ui_class, metaclass=QSingleton): ...@@ -379,7 +379,7 @@ class AddAccountDialog(base_class, ui_class, metaclass=QSingleton):
self.accept() self.accept()
else: else:
self.setEnabled(False) self.setEnabled(False)
self.create_status_label.value = Status('Creating account on server...') self.create_status_label.value = Status(translate('add_account_dialog', 'Creating account on server...'))
self._create_sip_account(self.username, self.password, self.email_address, self.display_name) self._create_sip_account(self.username, self.password, self.email_address, self.display_name)
def _SH_PanelChangeRequest(self, index): def _SH_PanelChangeRequest(self, index):
...@@ -397,28 +397,28 @@ class AddAccountDialog(base_class, ui_class, metaclass=QSingleton): ...@@ -397,28 +397,28 @@ class AddAccountDialog(base_class, ui_class, metaclass=QSingleton):
red = '#cc0000' red = '#cc0000'
# validate the add panel # validate the add panel
if not self.display_name_editor.text_valid: if not self.display_name_editor.text_valid:
self.add_status_label.value = Status("Display name cannot be empty", color=red) self.add_status_label.value = Status(translate('add_account_dialog', "Display name cannot be empty"), color=red)
elif not self.sip_address_editor.text_correct: elif not self.sip_address_editor.text_correct:
self.add_status_label.value = Status("SIP address should be specified as user@domain", color=red) self.add_status_label.value = Status(translate('add_account_dialog', "SIP address should be specified as user@domain"), color=red)
elif not self.sip_address_editor.text_allowed: elif not self.sip_address_editor.text_allowed:
self.add_status_label.value = Status("An account with this SIP address was already added", color=red) self.add_status_label.value = Status(translate('add_account_dialog', "An account with this SIP address was already added"), color=red)
elif not self.password_editor.text_valid: elif not self.password_editor.text_valid:
self.add_status_label.value = Status("Password cannot be empty", color=red) self.add_status_label.value = Status(translate('add_account_dialog', "Password cannot be empty"), color=red)
else: else:
self.add_status_label.value = None self.add_status_label.value = None
# validate the create panel # validate the create panel
if not self.name_editor.text_valid: if not self.name_editor.text_valid:
self.create_status_label.value = Status("Name cannot be empty", color=red) self.create_status_label.value = Status(translate('add_account_dialog', "Name cannot be empty"), color=red)
elif not self.username_editor.text_correct: elif not self.username_editor.text_correct:
self.create_status_label.value = Status("Username should have 5 to 32 characters, start with a letter or non-zero digit, contain only letters, digits or .-_ and end with a letter or digit", color=red) self.create_status_label.value = Status(translate('add_account_dialog', "Username should have 5 to 32 characters, start with a letter or non-zero digit, contain only letters, digits or .-_ and end with a letter or digit"), color=red)
elif not self.username_editor.text_allowed: elif not self.username_editor.text_allowed:
self.create_status_label.value = Status("The username you requested is already taken. Please choose another one and try again.", color=red) self.create_status_label.value = Status(translate('add_account_dialog', "The username you requested is already taken. Please choose another one and try again."), color=red)
elif not self.new_password_editor.text_valid: elif not self.new_password_editor.text_valid:
self.create_status_label.value = Status("Password should contain at least 8 characters", color=red) self.create_status_label.value = Status(translate('add_account_dialog', "Password should contain at least 8 characters"), color=red)
elif not self.verify_password_editor.text_valid: elif not self.verify_password_editor.text_valid:
self.create_status_label.value = Status("Passwords do not match", color=red) self.create_status_label.value = Status(translate('add_account_dialog', "Passwords do not match"), color=red)
elif not self.email_address_editor.text_valid: elif not self.email_address_editor.text_valid:
self.create_status_label.value = Status("E-mail address should be specified as user@domain", color=red) self.create_status_label.value = Status(translate('add_account_dialog', "E-mail address should be specified as user@domain"), color=red)
else: else:
self.create_status_label.value = None self.create_status_label.value = None
# enable the accept button if everything is valid in the current panel # enable the accept button if everything is valid in the current panel
...@@ -488,9 +488,9 @@ class AddAccountDialog(base_class, ui_class, metaclass=QSingleton): ...@@ -488,9 +488,9 @@ class AddAccountDialog(base_class, ui_class, metaclass=QSingleton):
else: else:
call_in_gui_thread(setattr, self.create_status_label, 'value', Status(response_data['error_message'], color=red)) call_in_gui_thread(setattr, self.create_status_label, 'value', Status(response_data['error_message'], color=red))
except (json.decoder.JSONDecodeError, KeyError): except (json.decoder.JSONDecodeError, KeyError):
call_in_gui_thread(setattr, self.create_status_label, 'value', Status('Illegal server response', color=red)) call_in_gui_thread(setattr, self.create_status_label, 'value', Status(translate('add_account_dialog', 'Illegal server response'), color=red))
except urllib.error.URLError as e: except urllib.error.URLError as e:
call_in_gui_thread(setattr, self.create_status_label, 'value', Status('Failed to contact server: %s' % e.reason, color=red)) call_in_gui_thread(setattr, self.create_status_label, 'value', Status(translate('add_account_dialog', 'Failed to contact server: %s') % e.reason, color=red))
finally: finally:
call_in_gui_thread(self.setEnabled, True) call_in_gui_thread(self.setEnabled, True)
...@@ -783,7 +783,7 @@ class ServerToolsWindow(base_class, ui_class, metaclass=QSingleton): ...@@ -783,7 +783,7 @@ class ServerToolsWindow(base_class, ui_class, metaclass=QSingleton):
self._update_navigation_buttons() self._update_navigation_buttons()
def _SH_WebViewTitleChanged(self, title): def _SH_WebViewTitleChanged(self, title):
self.window().setWindowTitle('Blink Server Tools: {}'.format(title)) self.window().setWindowTitle(translate('server_window', 'Blink Server Tools: {}').format(title))
def _SH_ModelChanged(self, parent_index, start, end): def _SH_ModelChanged(self, parent_index, start, end):
menu = self.account_button.menu() menu = self.account_button.menu()
......
...@@ -44,7 +44,7 @@ from blink.history import HistoryManager ...@@ -44,7 +44,7 @@ from blink.history import HistoryManager
from blink.messages import MessageManager, BlinkMessage from blink.messages import MessageManager, BlinkMessage
from blink.resources import IconManager, Resources from blink.resources import IconManager, Resources
from blink.sessions import ChatSessionModel, ChatSessionListView, SessionManager, StreamDescription from blink.sessions import ChatSessionModel, ChatSessionListView, SessionManager, StreamDescription
from blink.util import run_in_gui_thread, call_later from blink.util import run_in_gui_thread, call_later, translate
from blink.widgets.color import ColorHelperMixin from blink.widgets.color import ColorHelperMixin
from blink.widgets.graph import Graph from blink.widgets.graph import Graph
from blink.widgets.otr import OTRWidget from blink.widgets.otr import OTRWidget
...@@ -894,7 +894,7 @@ class ChatWidget(base_class, ui_class): ...@@ -894,7 +894,7 @@ class ChatWidget(base_class, ui_class):
image_data = base64.b64encode(data).decode() image_data = base64.b64encode(data).decode()
self.send_message(image_data, content_type=match.group('type')) self.send_message(image_data, content_type=match.group('type'))
except Exception as e: except Exception as e:
self.add_message(ChatStatus('Error sending image: %s' % str(e))) self.add_message(ChatStatus(translate('chat_window', 'Error sending image: %s') % str(e)))
else: else:
account = self.session.blink_session.account account = self.session.blink_session.account
content = '''<img src="{}" class="scaled-to-fit" />'''.format(text) content = '''<img src="{}" class="scaled-to-fit" />'''.format(text)
...@@ -964,7 +964,7 @@ class ChatWidget(base_class, ui_class): ...@@ -964,7 +964,7 @@ class ChatWidget(base_class, ui_class):
try: try:
msg_id = self.send_message(text, content_type='text/html', id=id) msg_id = self.send_message(text, content_type='text/html', id=id)
except Exception as e: except Exception as e:
self.add_message(ChatStatus('Error sending message: %s' % e)) # decide what type to use here. -Dan self.add_message(ChatStatus(translate('chat_window', 'Error sending message: %s') % e)) # decide what type to use here. -Dan
else: else:
if msg_id is not None: if msg_id is not None:
id = msg_id id = msg_id
...@@ -996,7 +996,7 @@ class ChatWidget(base_class, ui_class): ...@@ -996,7 +996,7 @@ class ChatWidget(base_class, ui_class):
def _SH_OTRTimerTimeout(self): def _SH_OTRTimerTimeout(self):
self.otr_timer.stop() self.otr_timer.stop()
self.add_message(ChatStatus('Timeout in enabling OTR, recipient did not answer to OTR encryption request')) # decide what type to use here. -Dan self.add_message(ChatStatus(translate('chat_window', 'Timeout in enabling OTR, recipient did not answer to OTR encryption request'))) # decide what type to use here. -Dan
NotificationCenter().post_notification('ChatStreamOTRTimeout', self.session.blink_session) NotificationCenter().post_notification('ChatStreamOTRTimeout', self.session.blink_session)
@run_in_gui_thread @run_in_gui_thread
...@@ -1146,7 +1146,7 @@ class VideoWidget(VideoSurface, ui_class): ...@@ -1146,7 +1146,7 @@ class VideoWidget(VideoSurface, ui_class):
self.close_button.setIcon(close_icon) self.close_button.setIcon(close_icon)
self.screenshot_button_menu = QMenu(self) self.screenshot_button_menu = QMenu(self)
self.screenshot_button_menu.addAction('Open screenshots folder', self._SH_ScreenshotsFolderActionTriggered) self.screenshot_button_menu.addAction(translate('chat_window', 'Open screenshots folder'), self._SH_ScreenshotsFolderActionTriggered)
@property @property
def interactive(self): def interactive(self):
...@@ -1572,7 +1572,7 @@ class NoSessionsLabel(QLabel): ...@@ -1572,7 +1572,7 @@ class NoSessionsLabel(QLabel):
self.setFont(font) self.setFont(font)
self.setAlignment(Qt.AlignCenter) self.setAlignment(Qt.AlignCenter)
self.setStyleSheet("""QLabel { border: 1px inset palette(dark); border-radius: 3px; background-color: white; color: #545454; }""") self.setStyleSheet("""QLabel { border: 1px inset palette(dark); border-radius: 3px; background-color: white; color: #545454; }""")
self.setText("No Sessions") self.setText(translate('chat_window', "No Sessions"))
chat_window.session_panel.installEventFilter(self) chat_window.session_panel.installEventFilter(self)
def eventFilter(self, watched, event): def eventFilter(self, watched, event):
...@@ -1735,23 +1735,23 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin): ...@@ -1735,23 +1735,23 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
self.control_menu = QMenu(self.control_button) self.control_menu = QMenu(self.control_button)
self.control_button.setMenu(self.control_menu) self.control_button.setMenu(self.control_menu)
self.control_button.actions = ContextMenuActions() self.control_button.actions = ContextMenuActions()
self.control_button.actions.connect = QAction("Start real time chat session", self, triggered=self._AH_Connect) self.control_button.actions.connect = QAction(translate('chat_window', "Start real time chat session"), self, triggered=self._AH_Connect)
self.control_button.actions.connect_with_audio = QAction("Start audio call", self, triggered=self._AH_ConnectWithAudio) self.control_button.actions.connect_with_audio = QAction(translate('chat_window', "Start audio call"), self, triggered=self._AH_ConnectWithAudio)
self.control_button.actions.connect_with_video = QAction("Start video call", self, triggered=self._AH_ConnectWithVideo) self.control_button.actions.connect_with_video = QAction(translate('chat_window', "Start video call"), self, triggered=self._AH_ConnectWithVideo)
self.control_button.actions.disconnect = QAction("Disconnect", self, triggered=self._AH_Disconnect) self.control_button.actions.disconnect = QAction(translate('chat_window', "Disconnect"), self, triggered=self._AH_Disconnect)
self.control_button.actions.add_audio = QAction("Add audio", self, triggered=self._AH_AddAudio) self.control_button.actions.add_audio = QAction(translate('chat_window', "Add audio"), self, triggered=self._AH_AddAudio)
self.control_button.actions.remove_audio = QAction("Remove audio", self, triggered=self._AH_RemoveAudio) self.control_button.actions.remove_audio = QAction(translate('chat_window', "Remove audio"), self, triggered=self._AH_RemoveAudio)
self.control_button.actions.add_video = QAction("Add video", self, triggered=self._AH_AddVideo) self.control_button.actions.add_video = QAction(translate('chat_window', "Add video"), self, triggered=self._AH_AddVideo)
self.control_button.actions.remove_video = QAction("Remove video", self, triggered=self._AH_RemoveVideo) self.control_button.actions.remove_video = QAction(translate('chat_window', "Remove video"), self, triggered=self._AH_RemoveVideo)
self.control_button.actions.add_chat = QAction("Add real time chat", self, triggered=self._AH_AddChat) self.control_button.actions.add_chat = QAction(translate('chat_window', "Add real time chat"), self, triggered=self._AH_AddChat)
self.control_button.actions.remove_chat = QAction("Remove real time chat", self, triggered=self._AH_RemoveChat) self.control_button.actions.remove_chat = QAction(translate('chat_window', "Remove real time chat"), self, triggered=self._AH_RemoveChat)
self.control_button.actions.share_my_screen = QAction("Share my screen", self, triggered=self._AH_ShareMyScreen) self.control_button.actions.share_my_screen = QAction(translate('chat_window', "Share my screen"), self, triggered=self._AH_ShareMyScreen)
self.control_button.actions.request_screen = QAction("Request screen", self, triggered=self._AH_RequestScreen) self.control_button.actions.request_screen = QAction(translate('chat_window', "Request screen"), self, triggered=self._AH_RequestScreen)
self.control_button.actions.end_screen_sharing = QAction("End screen sharing", self, triggered=self._AH_EndScreenSharing) self.control_button.actions.end_screen_sharing = QAction(translate('chat_window', "End screen sharing"), self, triggered=self._AH_EndScreenSharing)
self.control_button.actions.enable_otr = QAction("Enable OTR for messaging", self, triggered=self._AH_EnableOTR) self.control_button.actions.enable_otr = QAction(translate('chat_window', "Enable OTR for messaging"), self, triggered=self._AH_EnableOTR)
self.control_button.actions.enable_otr_progress = QAction("Enabling OTR for messaging", self, enabled=False) self.control_button.actions.enable_otr_progress = QAction(translate('chat_window', "Enabling OTR for messaging"), self, enabled=False)
self.control_button.actions.disable_otr = QAction("Disable OTR for messaging", self, triggered=self._AH_DisableOTR) self.control_button.actions.disable_otr = QAction(translate('chat_window', "Disable OTR for messaging"), self, triggered=self._AH_DisableOTR)
self.control_button.actions.main_window = QAction("Main Window", self, triggered=self._AH_MainWindow, shortcut='Ctrl+B', shortcutContext=Qt.ApplicationShortcut) self.control_button.actions.main_window = QAction(translate('chat_window', "Main Window"), self, triggered=self._AH_MainWindow, shortcut='Ctrl+B', shortcutContext=Qt.ApplicationShortcut)
self.addAction(self.control_button.actions.main_window) # make this active even when it's not in the control_button's menu self.addAction(self.control_button.actions.main_window) # make this active even when it's not in the control_button's menu
...@@ -1941,19 +1941,19 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin): ...@@ -1941,19 +1941,19 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
state = "%s" % blink_session.state state = "%s" % blink_session.state
if 'status' in elements and blink_session.state in ('initialized', 'connecting/*', 'connected/*', 'ended'): if 'status' in elements and blink_session.state in ('initialized', 'connecting/*', 'connected/*', 'ended'):
state_map = {'initialized': 'Disconnected', state_map = {'initialized': translate('chat_window', 'Disconnected'),
'connecting/dns_lookup': 'Finding destination...', 'connecting/dns_lookup': translate('chat_window', "Finding destination..."),
'connecting': 'Connecting...', 'connecting': translate('chat_window', "Connecting..."),
'connecting/ringing': 'Ringing', 'connecting/ringing': translate('chat_window', "Ringing"),
'connecting/starting': 'Starting media...', 'connecting/starting': translate('chat_window', "Starting media..."),
'connected': 'Connected'} 'connected': translate('chat_window', "Connected")}
if blink_session.state == 'ended': if blink_session.state == 'ended':
self.status_value_label.setForegroundRole(QPalette.AlternateBase if blink_session.state.error else QPalette.WindowText) self.status_value_label.setForegroundRole(QPalette.AlternateBase if blink_session.state.error else QPalette.WindowText)
self.status_value_label.setText(blink_session.state.reason) self.status_value_label.setText(blink_session.state.reason)
self.chat_value_widget.setEnabled(True) self.chat_value_widget.setEnabled(True)
self.chat_value_label.setText('Using SIP Message') self.chat_value_label.setText(translate('chat_window', "Using SIP Message"))
if blink_session.chat_type is not None: if blink_session.chat_type is not None:
self.chat_encryption_label.setVisible(False) self.chat_encryption_label.setVisible(False)
self.chat_connection_label.setVisible(False) self.chat_connection_label.setVisible(False)
...@@ -1976,31 +1976,31 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin): ...@@ -1976,31 +1976,31 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
if audio_info.ice_status == 'succeeded': if audio_info.ice_status == 'succeeded':
if 'relay' in {candidate.type.lower() for candidate in (audio_info.local_rtp_candidate, audio_info.remote_rtp_candidate)}: if 'relay' in {candidate.type.lower() for candidate in (audio_info.local_rtp_candidate, audio_info.remote_rtp_candidate)}:
self.audio_connection_label.setPixmap(self.pixmaps.relay_connection) self.audio_connection_label.setPixmap(self.pixmaps.relay_connection)
self.audio_connection_label.setToolTip('Using relay') self.audio_connection_label.setToolTip(translate('chat_window', "Using relay"))
else: else:
self.audio_connection_label.setPixmap(self.pixmaps.direct_connection) self.audio_connection_label.setPixmap(self.pixmaps.direct_connection)
self.audio_connection_label.setToolTip('Peer to peer') self.audio_connection_label.setToolTip(translate('chat_window', "Peer to peer"))
elif audio_info.ice_status == 'failed': elif audio_info.ice_status == 'failed':
self.audio_connection_label.setPixmap(self.pixmaps.unknown_connection) self.audio_connection_label.setPixmap(self.pixmaps.unknown_connection)
self.audio_connection_label.setToolTip("Couldn't negotiate ICE") self.audio_connection_label.setToolTip(translate('chat_window', "Couldn't negotiate ICE"))
elif audio_info.ice_status == 'disabled': elif audio_info.ice_status == 'disabled':
if blink_session.contact.type == 'bonjour': if blink_session.contact.type == 'bonjour':
self.audio_connection_label.setPixmap(self.pixmaps.direct_connection) self.audio_connection_label.setPixmap(self.pixmaps.direct_connection)
self.audio_connection_label.setToolTip('Peer to peer') self.audio_connection_label.setToolTip(translate('chat_window', "Peer to peer"))
else: else:
self.audio_connection_label.setPixmap(self.pixmaps.unknown_connection) self.audio_connection_label.setPixmap(self.pixmaps.unknown_connection)
self.audio_connection_label.setToolTip('ICE is disabled') self.audio_connection_label.setToolTip(translate('chat_window', "ICE is disabled"))
elif audio_info.ice_status is None: elif audio_info.ice_status is None:
self.audio_connection_label.setPixmap(self.pixmaps.unknown_connection) self.audio_connection_label.setPixmap(self.pixmaps.unknown_connection)
self.audio_connection_label.setToolTip('ICE is unavailable') self.audio_connection_label.setToolTip(translate('chat_window', "ICE is unavailable"))
else: else:
self.audio_connection_label.setPixmap(self.pixmaps.unknown_connection) self.audio_connection_label.setPixmap(self.pixmaps.unknown_connection)
self.audio_connection_label.setToolTip('Negotiating ICE') self.audio_connection_label.setToolTip(translate('chat_window', "Negotiating ICE"))
if audio_info.encryption is not None: if audio_info.encryption is not None:
self.audio_encryption_label.setToolTip('Media is encrypted using %s (%s)' % (audio_info.encryption, audio_info.encryption_cipher)) self.audio_encryption_label.setToolTip(translate('chat_window', "Media is encrypted using %s (%s)") % (audio_info.encryption, audio_info.encryption_cipher))
else: else:
self.audio_encryption_label.setToolTip('Media is not encrypted') self.audio_encryption_label.setToolTip(translate('chat_window', "Media is not encrypted"))
self._update_rtp_encryption_icon(self.audio_encryption_label) self._update_rtp_encryption_icon(self.audio_encryption_label)
self.audio_connection_label.setVisible(audio_info.remote_address is not None) self.audio_connection_label.setVisible(audio_info.remote_address is not None)
...@@ -2010,31 +2010,31 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin): ...@@ -2010,31 +2010,31 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
if video_info.ice_status == 'succeeded': if video_info.ice_status == 'succeeded':
if 'relay' in {candidate.type.lower() for candidate in (video_info.local_rtp_candidate, video_info.remote_rtp_candidate)}: if 'relay' in {candidate.type.lower() for candidate in (video_info.local_rtp_candidate, video_info.remote_rtp_candidate)}:
self.video_connection_label.setPixmap(self.pixmaps.relay_connection) self.video_connection_label.setPixmap(self.pixmaps.relay_connection)
self.video_connection_label.setToolTip('Using relay') self.video_connection_label.setToolTip(translate('chat_window', "Using relay"))
else: else:
self.video_connection_label.setPixmap(self.pixmaps.direct_connection) self.video_connection_label.setPixmap(self.pixmaps.direct_connection)
self.video_connection_label.setToolTip('Peer to peer') self.video_connection_label.setToolTip(translate('chat_window', "Peer to peer"))
elif video_info.ice_status == 'failed': elif video_info.ice_status == 'failed':
self.video_connection_label.setPixmap(self.pixmaps.unknown_connection) self.video_connection_label.setPixmap(self.pixmaps.unknown_connection)
self.video_connection_label.setToolTip("Couldn't negotiate ICE") self.video_connection_label.setToolTip("Couldn't negotiate ICE")
elif video_info.ice_status == 'disabled': elif video_info.ice_status == 'disabled':
if blink_session.contact.type == 'bonjour': if blink_session.contact.type == 'bonjour':
self.video_connection_label.setPixmap(self.pixmaps.direct_connection) self.video_connection_label.setPixmap(self.pixmaps.direct_connection)
self.video_connection_label.setToolTip('Peer to peer') self.video_connection_label.setToolTip(translate('chat_window', "Peer to peer"))
else: else:
self.video_connection_label.setPixmap(self.pixmaps.unknown_connection) self.video_connection_label.setPixmap(self.pixmaps.unknown_connection)
self.video_connection_label.setToolTip('ICE is disabled') self.video_connection_label.setToolTip(translate('chat_window', "ICE is disabled"))
elif video_info.ice_status is None: elif video_info.ice_status is None:
self.video_connection_label.setPixmap(self.pixmaps.unknown_connection) self.video_connection_label.setPixmap(self.pixmaps.unknown_connection)
self.video_connection_label.setToolTip('ICE is unavailable') self.video_connection_label.setToolTip(translate('chat_window', "ICE is unavailable"))
else: else:
self.video_connection_label.setPixmap(self.pixmaps.unknown_connection) self.video_connection_label.setPixmap(self.pixmaps.unknown_connection)
self.video_connection_label.setToolTip('Negotiating ICE') self.video_connection_label.setToolTip(translate('chat_window', "Negotiating ICE"))
if video_info.encryption is not None: if video_info.encryption is not None:
self.video_encryption_label.setToolTip('Media is encrypted using %s (%s)' % (video_info.encryption, video_info.encryption_cipher)) self.video_encryption_label.setToolTip(translate('chat_window', "Media is encrypted using %s (%s)") % (video_info.encryption, video_info.encryption_cipher))
else: else:
self.video_encryption_label.setToolTip('Media is not encrypted') self.video_encryption_label.setToolTip(translate('chat_window', "Media is not encrypted"))
self._update_rtp_encryption_icon(self.video_encryption_label) self._update_rtp_encryption_icon(self.video_encryption_label)
self.video_connection_label.setVisible(video_info.remote_address is not None) self.video_connection_label.setVisible(video_info.remote_address is not None)
...@@ -2050,33 +2050,33 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin): ...@@ -2050,33 +2050,33 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
self.zrtp_widget.show() self.zrtp_widget.show()
if any(len(path) > 1 for path in (chat_info.full_local_path, chat_info.full_remote_path)): if any(len(path) > 1 for path in (chat_info.full_local_path, chat_info.full_remote_path)):
self.chat_value_label.setText('Using relay') self.chat_value_label.setText(translate('chat_window', "Using relay"))
self.chat_connection_label.setPixmap(self.pixmaps.relay_connection) self.chat_connection_label.setPixmap(self.pixmaps.relay_connection)
self.chat_connection_label.setToolTip('Using relay') self.chat_connection_label.setToolTip(translate('chat_window', "Using relay"))
elif chat_info.full_local_path and chat_info.full_remote_path: elif chat_info.full_local_path and chat_info.full_remote_path:
self.chat_value_label.setText('Peer to peer') self.chat_value_label.setText(translate('chat_window', "Peer to peer"))
self.chat_connection_label.setPixmap(self.pixmaps.direct_connection) self.chat_connection_label.setPixmap(self.pixmaps.direct_connection)
self.chat_connection_label.setToolTip('Peer to peer') self.chat_connection_label.setToolTip(translate('chat_window', "Peer to peer"))
elif blink_session.chat_type is None: elif blink_session.chat_type is None:
self.chat_value_widget.setEnabled(True) self.chat_value_widget.setEnabled(True)
self.chat_value_label.setText('Using SIP Message') self.chat_value_label.setText(translate('chat_window', "Using SIP Message"))
self.chat_connection_label.setToolTip('Using SIP Message') self.chat_connection_label.setToolTip(translate('chat_window', "Using SIP Message"))
else: else:
self.chat_value_label.setText('N/A') self.chat_value_label.setText(translate('chat_window', "N/A"))
if chat_info.encryption is not None and chat_info.transport == 'tls': if chat_info.encryption is not None and chat_info.transport == 'tls':
self.chat_encryption_label.setToolTip('Media is encrypted using TLS and {0.encryption} ({0.encryption_cipher})'.format(chat_info)) self.chat_encryption_label.setToolTip(translate('chat_window', "Media is encrypted using TLS and {0.encryption} ({0.encryption_cipher})").format(chat_info))
elif chat_info.encryption is not None: elif chat_info.encryption is not None:
self.chat_encryption_label.setToolTip('Media is encrypted using {0.encryption} ({0.encryption_cipher})'.format(chat_info)) self.chat_encryption_label.setToolTip(translate('chat_window', "Media is encrypted using {0.encryption} ({0.encryption_cipher})").format(chat_info))
elif chat_info.transport == 'tls': elif chat_info.transport == 'tls':
self.chat_encryption_label.setToolTip('Media is encrypted using TLS') self.chat_encryption_label.setToolTip(translate('chat_window', "Media is encrypted using TLS"))
else: else:
self.chat_encryption_label.setToolTip('Media is not encrypted') self.chat_encryption_label.setToolTip(translate('chat_window', "Media is not encrypted"))
if messages_info.encryption is not None: if messages_info.encryption is not None:
if messages_info.encryption == 'OpenPGP': if messages_info.encryption == 'OpenPGP':
self.chat_encryption_label.setToolTip('Media is encrypted using {0.encryption}'.format(messages_info)) self.chat_encryption_label.setToolTip(translate('chat_window', "Media is encrypted using {0.encryption}").format(messages_info))
else: else:
self.chat_encryption_label.setToolTip('Media is encrypted using {0.encryption} ({0.encryption_cipher})'.format(messages_info)) self.chat_encryption_label.setToolTip(translate('chat_window', "Media is encrypted using {0.encryption} ({0.encryption_cipher})").format(messages_info))
self._update_chat_encryption_icon() self._update_chat_encryption_icon()
...@@ -2095,20 +2095,20 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin): ...@@ -2095,20 +2095,20 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
self.otr_widget.show() self.otr_widget.show()
if screen_info.remote_address is not None and screen_info.mode == 'active': if screen_info.remote_address is not None and screen_info.mode == 'active':
self.screen_value_label.setText('Viewing remote') self.screen_value_label.setText(translate('chat_window', "Viewing remote"))
elif screen_info.remote_address is not None and screen_info.mode == 'passive': elif screen_info.remote_address is not None and screen_info.mode == 'passive':
self.screen_value_label.setText('Sharing local') self.screen_value_label.setText(translate('chat_window', "Sharing local"))
else: else:
self.screen_value_label.setText('N/A') self.screen_value_label.setText(translate('chat_window', "N/A"))
if any(len(path) > 1 for path in (screen_info.full_local_path, screen_info.full_remote_path)): if any(len(path) > 1 for path in (screen_info.full_local_path, screen_info.full_remote_path)):
self.screen_connection_label.setPixmap(self.pixmaps.relay_connection) self.screen_connection_label.setPixmap(self.pixmaps.relay_connection)
self.screen_connection_label.setToolTip('Using relay') self.screen_connection_label.setToolTip(translate('chat_window', "Using relay"))
elif screen_info.full_local_path and screen_info.full_remote_path: elif screen_info.full_local_path and screen_info.full_remote_path:
self.screen_connection_label.setPixmap(self.pixmaps.direct_connection) self.screen_connection_label.setPixmap(self.pixmaps.direct_connection)
self.screen_connection_label.setToolTip('Peer to peer') self.screen_connection_label.setToolTip(translate('chat_window', "Peer to peer"))
self.screen_encryption_label.setToolTip('Media is encrypted using TLS') self.screen_encryption_label.setToolTip(translate('chat_window', "Media is encrypted using TLS"))
self.screen_connection_label.setVisible(screen_info.remote_address is not None) self.screen_connection_label.setVisible(screen_info.remote_address is not None)
self.screen_encryption_label.setVisible(screen_info.remote_address is not None and screen_info.transport == 'tls') self.screen_encryption_label.setVisible(screen_info.remote_address is not None and screen_info.transport == 'tls')
...@@ -2535,7 +2535,7 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin): ...@@ -2535,7 +2535,7 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
session = blink_session.items.chat session = blink_session.items.chat
if session is None: if session is None:
return return
session.chat_widget.add_message(ChatStatus(f'Delivery failed: {notification.data.data.code} - {notification.data.data.reason}')) session.chat_widget.add_message(ChatStatus(translate('chat_window', f'Delivery failed: {notification.data.data.code} - {notification.data.data.reason}')))
call_later(.5, session.chat_widget.update_message_status, id=notification.data.id, status='failed') call_later(.5, session.chat_widget.update_message_status, id=notification.data.id, status='failed')
def _NH_BlinkMessageWillRemove(self, notification): def _NH_BlinkMessageWillRemove(self, notification):
...@@ -2582,7 +2582,7 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin): ...@@ -2582,7 +2582,7 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
session = blink_session.items.chat session = blink_session.items.chat
if session is None: if session is None:
return return
session.chat_widget.add_message(ChatStatus(f'Decryption failed: {notification.data.error}')) session.chat_widget.add_message(ChatStatus(translate('chat_window', f'Decryption failed: {notification.data.error}')))
def _NH_MessageStreamPGPKeysDidLoad(self, notification): def _NH_MessageStreamPGPKeysDidLoad(self, notification):
stream = notification.sender stream = notification.sender
...@@ -2761,9 +2761,9 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin): ...@@ -2761,9 +2761,9 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
return return
if notification.data.new_state is OTRState.Encrypted: if notification.data.new_state is OTRState.Encrypted:
session.chat_widget.stop_otr_timer() session.chat_widget.stop_otr_timer()
session.chat_widget.add_message(ChatStatus('Encryption enabled')) session.chat_widget.add_message(ChatStatus(translate('chat_window','Encryption enabled')))
elif notification.data.old_state is OTRState.Encrypted: elif notification.data.old_state is OTRState.Encrypted:
session.chat_widget.add_message(ChatStatus('Encryption disabled')) session.chat_widget.add_message(ChatStatus(translate('chat_window', 'Encryption disabled')))
self.otr_widget.hide() self.otr_widget.hide()
if notification.data.new_state is OTRState.Finished: if notification.data.new_state is OTRState.Finished:
session.chat_widget.chat_input.lock(EncryptionLock) session.chat_widget.chat_input.lock(EncryptionLock)
...@@ -2793,7 +2793,7 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin): ...@@ -2793,7 +2793,7 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
session = notification.sender.blink_session.items.chat session = notification.sender.blink_session.items.chat
if session is None: if session is None:
return return
session.chat_widget.add_message(ChatStatus('Failed to initialize chat: %s' % notification.data.reason)) session.chat_widget.add_message(ChatStatus(translate('chat_window', 'Failed to initialize chat: %s') % notification.data.reason))
def _NH_MediaStreamDidStart(self, notification): def _NH_MediaStreamDidStart(self, notification):
if notification.sender.type != 'chat': if notification.sender.type != 'chat':
...@@ -2810,9 +2810,9 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin): ...@@ -2810,9 +2810,9 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
if session is None: if session is None:
return return
if notification.data.error is not None: if notification.data.error is not None:
session.chat_widget.add_message(ChatStatus('Disconnected: %s' % notification.data.error)) session.chat_widget.add_message(ChatStatus(translate('chat_window', 'Disconnected: %s') % notification.data.error))
else: else:
session.chat_widget.add_message(ChatStatus('Disconnected')) session.chat_widget.add_message(ChatStatus(translate('chat_window', 'Disconnected')))
# Set type back for message as the stream ended cleanly -- Tijmen # Set type back for message as the stream ended cleanly -- Tijmen
notification.sender.blink_session.chat_type = None notification.sender.blink_session.chat_type = None
...@@ -2848,10 +2848,10 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin): ...@@ -2848,10 +2848,10 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
self.selected_session.active_panel = self.participants_panel self.selected_session.active_panel = self.participants_panel
def _SH_LatencyGraphUpdated(self): def _SH_LatencyGraphUpdated(self):
self.latency_label.setText('Network Latency: %dms, max=%dms' % (max(self.audio_latency_graph.last_value, self.video_latency_graph.last_value), self.latency_graph.max_value)) self.latency_label.setText(translate('chat_window', 'Network Latency: %dms, max=%dms') % (max(self.audio_latency_graph.last_value, self.video_latency_graph.last_value), self.latency_graph.max_value))
def _SH_PacketLossGraphUpdated(self): def _SH_PacketLossGraphUpdated(self):
self.packet_loss_label.setText('Packet Loss: %.1f%%, max=%.1f%%' % (max(self.audio_packet_loss_graph.last_value, self.video_packet_loss_graph.last_value), self.packet_loss_graph.max_value)) self.packet_loss_label.setText(translate('chat_window', 'Packet Loss: %.1f%%, max=%.1f%%') % (max(self.audio_packet_loss_graph.last_value, self.video_packet_loss_graph.last_value), self.packet_loss_graph.max_value))
def _SH_TrafficGraphUpdated(self): def _SH_TrafficGraphUpdated(self):
blink_settings = BlinkSettings() blink_settings = BlinkSettings()
...@@ -2861,7 +2861,7 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin): ...@@ -2861,7 +2861,7 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
else: else:
incoming_traffic = TrafficNormalizer.normalize(self.incoming_traffic_graph.last_value * 8, bits_per_second=True) incoming_traffic = TrafficNormalizer.normalize(self.incoming_traffic_graph.last_value * 8, bits_per_second=True)
outgoing_traffic = TrafficNormalizer.normalize(self.outgoing_traffic_graph.last_value * 8, bits_per_second=True) outgoing_traffic = TrafficNormalizer.normalize(self.outgoing_traffic_graph.last_value * 8, bits_per_second=True)
self.traffic_label.setText("""<p>Traffic: <span style="font-family: sans-serif; color: #d70000;">\u2193</span> %s <span style="font-family: sans-serif; color: #0064d7;">\u2191</span> %s</p>""" % (incoming_traffic, outgoing_traffic)) self.traffic_label.setText(translate('chat_window', """<p>Traffic: <span style="font-family: sans-serif; color: #d70000;">\u2193</span> %s <span style="font-family: sans-serif; color: #0064d7;">\u2191</span> %s</p>""") % (incoming_traffic, outgoing_traffic))
def _SH_MuteButtonClicked(self, checked): def _SH_MuteButtonClicked(self, checked):
settings = SIPSimpleSettings() settings = SIPSimpleSettings()
......
...@@ -8,7 +8,7 @@ import sys ...@@ -8,7 +8,7 @@ import sys
from PyQt5 import uic from PyQt5 import uic
from PyQt5.QtCore import Qt, QAbstractListModel, QAbstractTableModel, QEasingCurve, QModelIndex, QPropertyAnimation, QSortFilterProxyModel from PyQt5.QtCore import Qt, QAbstractListModel, QAbstractTableModel, QEasingCurve, QModelIndex, QPropertyAnimation, QSortFilterProxyModel
from PyQt5.QtCore import QByteArray, QEvent, QMimeData, QPointF, QRectF, QRect, QSize, QTimer, QUrl, pyqtSignal from PyQt5.QtCore import QByteArray, QEvent, QMimeData, QPointF, QRectF, QRect, QSize, QTimer, QUrl, pyqtSignal, QT_TRANSLATE_NOOP
from PyQt5.QtGui import QBrush, QColor, QIcon, QKeyEvent, QLinearGradient, QMouseEvent, QPainter, QPainterPath, QPalette, QPen, QPixmap, QPolygonF from PyQt5.QtGui import QBrush, QColor, QIcon, QKeyEvent, QLinearGradient, QMouseEvent, QPainter, QPainterPath, QPalette, QPen, QPixmap, QPolygonF
from PyQt5.QtWebKitWidgets import QWebView from PyQt5.QtWebKitWidgets import QWebView
from PyQt5.QtWidgets import QAction, QApplication, QItemDelegate, QStyledItemDelegate, QStyle from PyQt5.QtWidgets import QAction, QApplication, QItemDelegate, QStyledItemDelegate, QStyle
...@@ -48,7 +48,7 @@ from blink.configuration.datatypes import IconDescriptor, FileURL ...@@ -48,7 +48,7 @@ from blink.configuration.datatypes import IconDescriptor, FileURL
from blink.resources import ApplicationData, Resources, IconManager from blink.resources import ApplicationData, Resources, IconManager
from blink.sessions import SessionManager, StreamDescription from blink.sessions import SessionManager, StreamDescription
from blink.messages import MessageManager from blink.messages import MessageManager
from blink.util import call_in_gui_thread, run_in_gui_thread from blink.util import call_in_gui_thread, run_in_gui_thread, translate
from blink.widgets.buttons import SwitchViewButton from blink.widgets.buttons import SwitchViewButton
from blink.widgets.color import ColorHelperMixin from blink.widgets.color import ColorHelperMixin
from blink.widgets.util import ContextMenuActions from blink.widgets.util import ContextMenuActions
...@@ -643,7 +643,7 @@ class GoogleContact(object): ...@@ -643,7 +643,7 @@ class GoogleContact(object):
organization = next((entry.get('name') for entry in contact_data.get('organizations', Null)), None) organization = next((entry.get('name') for entry in contact_data.get('organizations', Null)), None)
icon_url, icon_metadata = next(((entry['url'], entry['metadata']) for entry in contact_data.get('photos', Null)), (None, None)) icon_url, icon_metadata = next(((entry['url'], entry['metadata']) for entry in contact_data.get('photos', Null)), (None, None))
name = name.strip() if name is not None else 'Unknown' name = name.strip() if name is not None else translate('contact_list', 'Unknown')
organization = organization.strip() if organization is not None else organization organization = organization.strip() if organization is not None else organization
uris = [GoogleContactURI.from_number(number) for number in contact_data.get('phoneNumbers', Null)] uris = [GoogleContactURI.from_number(number) for number in contact_data.get('phoneNumbers', Null)]
...@@ -2288,7 +2288,7 @@ class ContactModel(QAbstractListModel): ...@@ -2288,7 +2288,7 @@ class ContactModel(QAbstractListModel):
# The MIME types we accept in drop operations, in the order they should be handled # The MIME types we accept in drop operations, in the order they should be handled
accepted_mime_types = ['application/x-blink-group-list', 'application/x-blink-contact-list', 'text/uri-list'] accepted_mime_types = ['application/x-blink-group-list', 'application/x-blink-contact-list', 'text/uri-list']
# TODO: Maybe translate? -Tijmen
test_contacts = (dict(id='test_call', name='Test Call', preferred_media='audio+chat', uri='echo@conference.sip2sip.info', icon=Resources.get('icons/test-call.png')), test_contacts = (dict(id='test_call', name='Test Call', preferred_media='audio+chat', uri='echo@conference.sip2sip.info', icon=Resources.get('icons/test-call.png')),
dict(id='test_conference', name='Test Conference', preferred_media='audio+chat', uri='test@conference.sip2sip.info', icon=Resources.get('icons/test-conference.png'))) dict(id='test_conference', name='Test Conference', preferred_media='audio+chat', uri='test@conference.sip2sip.info', icon=Resources.get('icons/test-conference.png')))
...@@ -3136,20 +3136,20 @@ class ContactListView(QListView): ...@@ -3136,20 +3136,20 @@ class ContactListView(QListView):
self.detail_view.hide() self.detail_view.hide()
self.context_menu = QMenu(self) self.context_menu = QMenu(self)
self.actions = ContextMenuActions() self.actions = ContextMenuActions()
self.actions.add_group = QAction("Add Group", self, triggered=self._AH_AddGroup) self.actions.add_group = QAction(translate("contact_list", "Add Group"), self, triggered=self._AH_AddGroup)
self.actions.add_contact = QAction("Add Contact", self, triggered=self._AH_AddContact) self.actions.add_contact = QAction(translate("contact_list", "Add Contact"), self, triggered=self._AH_AddContact)
self.actions.edit_item = QAction("Edit", self, triggered=self._AH_EditItem) self.actions.edit_item = QAction(translate("contact_list", "Edit"), self, triggered=self._AH_EditItem)
self.actions.delete_item = QAction("Delete", self, triggered=self._AH_DeleteSelection) self.actions.delete_item = QAction(translate("contact_list", "Delete"), self, triggered=self._AH_DeleteSelection)
self.actions.delete_selection = QAction("Delete Selection", self, triggered=self._AH_DeleteSelection) self.actions.delete_selection = QAction(translate("contact_list", "Delete Selection"), self, triggered=self._AH_DeleteSelection)
self.actions.undo_last_delete = QAction("Undo Last Delete", self, triggered=self._AH_UndoLastDelete) self.actions.undo_last_delete = QAction(translate("contact_list", "Undo Last Delete"), self, triggered=self._AH_UndoLastDelete)
self.actions.start_audio_call = QAction("Start Audio Call", self, triggered=self._AH_StartAudioCall) self.actions.start_audio_call = QAction(translate("contact_list", "Start Audio Call"), self, triggered=self._AH_StartAudioCall)
self.actions.start_video_call = QAction("Start Video Call", self, triggered=self._AH_StartVideoCall) self.actions.start_video_call = QAction(translate("contact_list", "Start Video Call"), self, triggered=self._AH_StartVideoCall)
self.actions.start_chat_session = QAction("Start Real Time Chat Session", self, triggered=self._AH_StartChatSession) self.actions.start_chat_session = QAction(translate("contact_list", "Start Real Time Chat Session"), self, triggered=self._AH_StartChatSession)
self.actions.send_sms = QAction("Send Messages", self, triggered=self._AH_SendSMS) self.actions.send_sms = QAction(translate("contact_list", "Send Messages"), self, triggered=self._AH_SendSMS)
self.actions.send_files = QAction("Send File(s)...", self, triggered=self._AH_SendFiles) self.actions.send_files = QAction(translate("contact_list", "Send File(s)..."), self, triggered=self._AH_SendFiles)
self.actions.request_screen = QAction("Request Screen", self, triggered=self._AH_RequestScreen) self.actions.request_screen = QAction(translate("contact_list", "Request Screen"), self, triggered=self._AH_RequestScreen)
self.actions.share_my_screen = QAction("Share My Screen", self, triggered=self._AH_ShareMyScreen) self.actions.share_my_screen = QAction(translate("contact_list", "Share My Screen"), self, triggered=self._AH_ShareMyScreen)
self.actions.transfer_call = QAction("Transfer Active Call", self, triggered=self._AH_TransferCall) self.actions.transfer_call = QAction(translate("contact_list", "Transfer Active Call"), self, triggered=self._AH_TransferCall)
self.drop_indicator_index = QModelIndex() self.drop_indicator_index = QModelIndex()
self.needs_restore = False self.needs_restore = False
self.doubleClicked.connect(self._SH_DoubleClicked) # activated is emitted on single click self.doubleClicked.connect(self._SH_DoubleClicked) # activated is emitted on single click
...@@ -3171,7 +3171,7 @@ class ContactListView(QListView): ...@@ -3171,7 +3171,7 @@ class ContactListView(QListView):
model = self.model() model = self.model()
selected_items = [index.data(Qt.UserRole) for index in self.selectionModel().selectedIndexes()] selected_items = [index.data(Qt.UserRole) for index in self.selectionModel().selectedIndexes()]
if not model.deleted_items: if not model.deleted_items:
undo_delete_text = "Undo Delete" undo_delete_text = translate("contact_list", "Undo Delete")
elif len(model.deleted_items[-1]) == 1: elif len(model.deleted_items[-1]) == 1:
operation = model.deleted_items[-1][0] operation = model.deleted_items[-1][0]
if type(operation) is AddContactOperation: if type(operation) is AddContactOperation:
...@@ -3185,12 +3185,12 @@ class ContactListView(QListView): ...@@ -3185,12 +3185,12 @@ class ContactListView(QListView):
try: try:
contact = addressbook_manager.get_contact(operation.contact_id) contact = addressbook_manager.get_contact(operation.contact_id)
except KeyError: except KeyError:
name = 'Contact' name = translate('contact_list', 'Contact')
else: else:
name = contact.name or 'Contact' name = contact.name or translate('contact_list', 'Contact')
undo_delete_text = 'Undo Delete "%s"' % name undo_delete_text = translate('contact_list', 'Undo Delete "%s"') % name
else: else:
undo_delete_text = "Undo Delete (%d items)" % len(model.deleted_items[-1]) undo_delete_text = translate('contact_list', "Undo Delete (%d items)") % len(model.deleted_items[-1])
menu = self.context_menu menu = self.context_menu
menu.clear() menu.clear()
if not selected_items: if not selected_items:
...@@ -3225,50 +3225,49 @@ class ContactListView(QListView): ...@@ -3225,50 +3225,49 @@ class ContactListView(QListView):
can_transfer = contact.uri is not None and session_manager.active_session is not None and session_manager.active_session.state == 'connected' can_transfer = contact.uri is not None and session_manager.active_session is not None and session_manager.active_session.state == 'connected'
if len(contact.uris) > 1 and can_call: if len(contact.uris) > 1 and can_call:
call_submenu = menu.addMenu('Start Audio Call') call_submenu = menu.addMenu(translate('contact_list', 'Start Audio Call'))
for uri in contact.uris: for uri in contact.uris:
uri_text = '%s (%s)' % (uri.uri, uri.type) if uri.type not in ('SIP', 'Other') else uri.uri uri_text = '%s (%s)' % (uri.uri, uri.type) if uri.type not in ('SIP', 'Other') else uri.uri
call_item = QAction(uri_text, self) call_item = QAction(uri_text, self)
call_item.triggered.connect(partial(self._AH_StartAudioCall, uri)) call_item.triggered.connect(partial(self._AH_StartAudioCall, uri))
call_submenu.addAction(call_item) call_submenu.addAction(call_item)
call_submenu = menu.addMenu('Start Video Call') call_submenu = menu.addMenu(translate('contact_list', 'Start Video Call'))
for uri in contact.uris: for uri in contact.uris:
uri_text = '%s (%s)' % (uri.uri, uri.type) if uri.type not in ('SIP', 'Other') else uri.uri uri_text = '%s (%s)' % (uri.uri, uri.type) if uri.type not in ('SIP', 'Other') else uri.uri
call_item = QAction(uri_text, self) call_item = QAction(uri_text, self)
call_item.triggered.connect(partial(self._AH_StartVideoCall, uri)) call_item.triggered.connect(partial(self._AH_StartVideoCall, uri))
call_submenu.addAction(call_item) call_submenu.addAction(call_item)
call_submenu = menu.addMenu(translate('contact_list', 'Send Messages'))
call_submenu = menu.addMenu('Send Messages')
for uri in contact.uris: for uri in contact.uris:
uri_text = '%s (%s)' % (uri.uri, uri.type) if uri.type not in ('SIP', 'Other') else uri.uri uri_text = '%s (%s)' % (uri.uri, uri.type) if uri.type not in ('SIP', 'Other') else uri.uri
call_item = QAction(uri_text, self) call_item = QAction(uri_text, self)
call_item.triggered.connect(partial(self._AH_SendSMS, uri)) call_item.triggered.connect(partial(self._AH_SendSMS, uri))
call_submenu.addAction(call_item) call_submenu.addAction(call_item)
call_submenu = menu.addMenu('Start Real Time Chat Session') call_submenu = menu.addMenu(translate('contact_list', 'Start Real Time Chat Session'))
for uri in contact.uris: for uri in contact.uris:
uri_text = '%s (%s)' % (uri.uri, uri.type) if uri.type not in ('SIP', 'Other') else uri.uri uri_text = '%s (%s)' % (uri.uri, uri.type) if uri.type not in ('SIP', 'Other') else uri.uri
call_item = QAction(uri_text, self) call_item = QAction(uri_text, self)
call_item.triggered.connect(partial(self._AH_StartChatSession, uri)) call_item.triggered.connect(partial(self._AH_StartChatSession, uri))
call_submenu.addAction(call_item) call_submenu.addAction(call_item)
call_submenu = menu.addMenu('Send File(s)...') call_submenu = menu.addMenu(translate('contact_list', 'Send File(s)...'))
for uri in contact.uris: for uri in contact.uris:
uri_text = '%s (%s)' % (uri.uri, uri.type) if uri.type not in ('SIP', 'Other') else uri.uri uri_text = '%s (%s)' % (uri.uri, uri.type) if uri.type not in ('SIP', 'Other') else uri.uri
call_item = QAction(uri_text, self) call_item = QAction(uri_text, self)
call_item.triggered.connect(partial(self._AH_SendFiles, uri)) call_item.triggered.connect(partial(self._AH_SendFiles, uri))
call_submenu.addAction(call_item) call_submenu.addAction(call_item)
call_submenu = menu.addMenu('Request Screen') call_submenu = menu.addMenu(translate('contact_list', 'Request Screen'))
for uri in contact.uris: for uri in contact.uris:
uri_text = '%s (%s)' % (uri.uri, uri.type) if uri.type not in ('SIP', 'Other') else uri.uri uri_text = '%s (%s)' % (uri.uri, uri.type) if uri.type not in ('SIP', 'Other') else uri.uri
call_item = QAction(uri_text, self) call_item = QAction(uri_text, self)
call_item.triggered.connect(partial(self._AH_RequestScreen, uri)) call_item.triggered.connect(partial(self._AH_RequestScreen, uri))
call_submenu.addAction(call_item) call_submenu.addAction(call_item)
call_submenu = menu.addMenu('Share My Screen') call_submenu = menu.addMenu(translate('contact_list', 'Share My Screen'))
for uri in contact.uris: for uri in contact.uris:
uri_text = '%s (%s)' % (uri.uri, uri.type) if uri.type not in ('SIP', 'Other') else uri.uri uri_text = '%s (%s)' % (uri.uri, uri.type) if uri.type not in ('SIP', 'Other') else uri.uri
call_item = QAction(uri_text, self) call_item = QAction(uri_text, self)
...@@ -3293,7 +3292,7 @@ class ContactListView(QListView): ...@@ -3293,7 +3292,7 @@ class ContactListView(QListView):
self.actions.share_my_screen.setEnabled(can_call) self.actions.share_my_screen.setEnabled(can_call)
if len(contact.uris) > 1 and can_transfer: if len(contact.uris) > 1 and can_transfer:
call_submenu = menu.addMenu('Transfer Call') call_submenu = menu.addMenu(translate('contact_list', 'Transfer Call'))
for uri in contact.uris: for uri in contact.uris:
uri_text = '%s (%s)' % (uri.uri, uri.type) if uri.type not in ('SIP', 'Other') else uri.uri uri_text = '%s (%s)' % (uri.uri, uri.type) if uri.type not in ('SIP', 'Other') else uri.uri
call_item = QAction(uri_text, self) call_item = QAction(uri_text, self)
...@@ -3680,18 +3679,18 @@ class ContactSearchListView(QListView): ...@@ -3680,18 +3679,18 @@ class ContactSearchListView(QListView):
self.detail_view.hide() self.detail_view.hide()
self.context_menu = QMenu(self) self.context_menu = QMenu(self)
self.actions = ContextMenuActions() self.actions = ContextMenuActions()
self.actions.edit_item = QAction("Edit", self, triggered=self._AH_EditItem) self.actions.edit_item = QAction(translate("contact_list", "Edit"), self, triggered=self._AH_EditItem)
self.actions.delete_item = QAction("Delete", self, triggered=self._AH_DeleteSelection) self.actions.delete_item = QAction(translate("contact_list", "Delete"), self, triggered=self._AH_DeleteSelection)
self.actions.delete_selection = QAction("Delete Selection", self, triggered=self._AH_DeleteSelection) self.actions.delete_selection = QAction(translate("contact_list", "Delete Selection"), self, triggered=self._AH_DeleteSelection)
self.actions.undo_last_delete = QAction("Undo Last Delete", self, triggered=self._AH_UndoLastDelete) self.actions.undo_last_delete = QAction(translate("contact_list", "Undo Last Delete"), self, triggered=self._AH_UndoLastDelete)
self.actions.start_audio_call = QAction("Start Audio Call", self, triggered=self._AH_StartAudioCall) self.actions.start_audio_call = QAction(translate("contact_list", "Start Audio Call"), self, triggered=self._AH_StartAudioCall)
self.actions.start_video_call = QAction("Start Video Call", self, triggered=self._AH_StartVideoCall) self.actions.start_video_call = QAction(translate("contact_list", "Start Video Call"), self, triggered=self._AH_StartVideoCall)
self.actions.start_chat_session = QAction("Start Real Time Chat Session", self, triggered=self._AH_StartChatSession) self.actions.start_chat_session = QAction(translate("contact_list", "Start Real Time Chat Session"), self, triggered=self._AH_StartChatSession)
self.actions.send_sms = QAction("Send Messages", self, triggered=self._AH_SendSMS) self.actions.send_sms = QAction(translate("contact_list", "Send Messages"), self, triggered=self._AH_SendSMS)
self.actions.send_files = QAction("Send File(s)...", self, triggered=self._AH_SendFiles) self.actions.send_files = QAction(translate("contact_list", "Send File(s)..."), self, triggered=self._AH_SendFiles)
self.actions.request_screen = QAction("Request Screen", self, triggered=self._AH_RequestScreen) self.actions.request_screen = QAction(translate("contact_list", "Request Screen"), self, triggered=self._AH_RequestScreen)
self.actions.share_my_screen = QAction("Share My Screen", self, triggered=self._AH_ShareMyScreen) self.actions.share_my_screen = QAction(translate("contact_list", "Share My Screen"), self, triggered=self._AH_ShareMyScreen)
self.actions.transfer_call = QAction("Transfer Active Call", self, triggered=self._AH_TransferCall) self.actions.transfer_call = QAction(translate("contact_list", "Transfer Active Call"), self, triggered=self._AH_TransferCall)
self.drop_indicator_index = QModelIndex() self.drop_indicator_index = QModelIndex()
self.doubleClicked.connect(self._SH_DoubleClicked) # activated is emitted on single click self.doubleClicked.connect(self._SH_DoubleClicked) # activated is emitted on single click
notification_center = NotificationCenter() notification_center = NotificationCenter()
...@@ -3727,12 +3726,12 @@ class ContactSearchListView(QListView): ...@@ -3727,12 +3726,12 @@ class ContactSearchListView(QListView):
try: try:
contact = addressbook_manager.get_contact(operation.contact_id) contact = addressbook_manager.get_contact(operation.contact_id)
except KeyError: except KeyError:
name = 'Contact' name = translate('contact_list', 'Contact')
else: else:
name = contact.name or 'Contact' name = contact.name or translate('contact_list', 'Contact')
undo_delete_text = 'Undo Delete "%s"' % name undo_delete_text = translate('contact_list', 'Undo Delete "%s"') % name
else: else:
undo_delete_text = "Undo Delete (%d items)" % len(source_model.deleted_items[-1]) undo_delete_text = translate('contact_list', "Undo Delete (%d items)") % len(source_model.deleted_items[-1])
menu = self.context_menu menu = self.context_menu
menu.clear() menu.clear()
if not selected_items: if not selected_items:
...@@ -3941,7 +3940,7 @@ class ContactSearchListView(QListView): ...@@ -3941,7 +3940,7 @@ class ContactSearchListView(QListView):
def _AH_SendFiles(self, uri=None): def _AH_SendFiles(self, uri=None):
session_manager = SessionManager() session_manager = SessionManager()
contact = self.selectionModel().selectedIndexes()[0].data(Qt.UserRole) contact = self.selectionModel().selectedIndexes()[0].data(Qt.UserRole)
for filename in QFileDialog.getOpenFileNames(self, 'Select File(s)', session_manager.send_file_directory, 'Any file (*.*)')[0]: for filename in QFileDialog.getOpenFileNames(self, translate('contact_list', 'Select File(s)'), session_manager.send_file_directory, 'Any file (*.*)')[0]:
session_manager.send_file(contact, uri or contact.uri, filename) session_manager.send_file(contact, uri or contact.uri, filename)
def _AH_RequestScreen(self, uri=None): def _AH_RequestScreen(self, uri=None):
...@@ -4028,17 +4027,17 @@ class ContactDetailView(QListView): ...@@ -4028,17 +4027,17 @@ class ContactDetailView(QListView):
self.animation.finished.connect(self._SH_AnimationFinished) self.animation.finished.connect(self._SH_AnimationFinished)
self.context_menu = QMenu(self) self.context_menu = QMenu(self)
self.actions = ContextMenuActions() self.actions = ContextMenuActions()
self.actions.delete_contact = QAction("Delete Contact", self, triggered=self._AH_DeleteContact) self.actions.delete_contact = QAction(translate("contact_list", "Delete Contact"), self, triggered=self._AH_DeleteContact)
self.actions.edit_contact = QAction("Edit Contact", self, triggered=self._AH_EditContact) self.actions.edit_contact = QAction(translate("contact_list", "Edit Contact"), self, triggered=self._AH_EditContact)
self.actions.make_uri_default = QAction("Set Address As Default", self, triggered=self._AH_MakeURIDefault) self.actions.make_uri_default = QAction(translate("contact_list", "Set Address As Default"), self, triggered=self._AH_MakeURIDefault)
self.actions.start_audio_call = QAction("Start Audio Call", self, triggered=self._AH_StartAudioCall) self.actions.start_audio_call = QAction(translate("contact_list", "Start Audio Call"), self, triggered=self._AH_StartAudioCall)
self.actions.start_video_call = QAction("Start Video Call", self, triggered=self._AH_StartVideoCall) self.actions.start_video_call = QAction(translate("contact_list", "Start Video Call"), self, triggered=self._AH_StartVideoCall)
self.actions.start_chat_session = QAction("Start Real Time Chat Session", self, triggered=self._AH_StartChatSession) self.actions.start_chat_session = QAction(translate("contact_list", "Start Real Time Chat Session"), self, triggered=self._AH_StartChatSession)
self.actions.send_sms = QAction("Send Messages", self, triggered=self._AH_SendSMS) self.actions.send_sms = QAction(translate("contact_list", "Send Messages"), self, triggered=self._AH_SendSMS)
self.actions.send_files = QAction("Send File(s)...", self, triggered=self._AH_SendFiles) self.actions.send_files = QAction(translate("contact_list", "Send File(s)..."), self, triggered=self._AH_SendFiles)
self.actions.request_screen = QAction("Request Screen", self, triggered=self._AH_RequestScreen) self.actions.request_screen = QAction(translate("contact_list", "Request Screen"), self, triggered=self._AH_RequestScreen)
self.actions.share_my_screen = QAction("Share My Screen", self, triggered=self._AH_ShareMyScreen) self.actions.share_my_screen = QAction(translate("contact_list", "Share My Screen"), self, triggered=self._AH_ShareMyScreen)
self.actions.transfer_call = QAction("Transfer Active Call", self, triggered=self._AH_TransferCall) self.actions.transfer_call = QAction(translate("contact_list", "Transfer Active Call"), self, triggered=self._AH_TransferCall)
self.drop_indicator_index = QModelIndex() self.drop_indicator_index = QModelIndex()
self.doubleClicked.connect(self._SH_DoubleClicked) # activated is emitted on single click self.doubleClicked.connect(self._SH_DoubleClicked) # activated is emitted on single click
contact_list.installEventFilter(self) contact_list.installEventFilter(self)
...@@ -4257,7 +4256,7 @@ class ContactDetailView(QListView): ...@@ -4257,7 +4256,7 @@ class ContactDetailView(QListView):
selected_uri = item.uri selected_uri = item.uri
else: else:
selected_uri = uri or contact.uri selected_uri = uri or contact.uri
for filename in QFileDialog.getOpenFileNames(self, 'Select File(s)', session_manager.send_file_directory, 'Any file (*.*)')[0]: for filename in QFileDialog.getOpenFileNames(self, translate('contact_list', 'Select File(s)'), session_manager.send_file_directory, 'Any file (*.*)')[0]:
session_manager.send_file(contact, selected_uri, filename) session_manager.send_file(contact, selected_uri, filename)
def _AH_RequestScreen(self, uri=None): def _AH_RequestScreen(self, uri=None):
...@@ -4373,12 +4372,18 @@ class ContactURIItem(object): ...@@ -4373,12 +4372,18 @@ class ContactURIItem(object):
class URITypeComboBox(QComboBox): class URITypeComboBox(QComboBox):
builtin_types = (None, "Mobile", "Home", "Work", "SIP", "XMPP", "Other") builtin_types = (None,
QT_TRANSLATE_NOOP('contact_editor', "Mobile"),
QT_TRANSLATE_NOOP('contact_editor', "Home"),
QT_TRANSLATE_NOOP('contact_editor', "Work"),
QT_TRANSLATE_NOOP('contact_editor', "SIP"),
QT_TRANSLATE_NOOP('contact_editor', "XMPP"),
QT_TRANSLATE_NOOP('contact_editor', "Other"))
def __init__(self, parent=None, types=()): def __init__(self, parent=None, types=()):
super(URITypeComboBox, self).__init__(parent) super(URITypeComboBox, self).__init__(parent)
self.setEditable(True) self.setEditable(True)
self.addItems(self.builtin_types) self.addItems((translate('contact_editor', item) for item in self.builtin_types))
self.addItems(sorted(set(types) - set(self.builtin_types))) self.addItems(sorted(set(types) - set(self.builtin_types)))
...@@ -4471,7 +4476,9 @@ class ContactURIDelegate(QItemDelegate): ...@@ -4471,7 +4476,9 @@ class ContactURIDelegate(QItemDelegate):
class ContactURIModel(QAbstractTableModel): class ContactURIModel(QAbstractTableModel):
columns = ('Address', 'Type', 'Default') columns = (QT_TRANSLATE_NOOP('contact_editor', 'Address'),
QT_TRANSLATE_NOOP('contact_editor', 'Type'),
QT_TRANSLATE_NOOP('contact_editor', 'Default'))
AddressColumn = 0 AddressColumn = 0
TypeColumn = 1 TypeColumn = 1
...@@ -4507,7 +4514,7 @@ class ContactURIModel(QAbstractTableModel): ...@@ -4507,7 +4514,7 @@ class ContactURIModel(QAbstractTableModel):
return item return item
elif role == Qt.DisplayRole: elif role == Qt.DisplayRole:
if column == ContactURIModel.AddressColumn: if column == ContactURIModel.AddressColumn:
return 'Edit to add address' if item.ghost else str(item.uri or '') return translate('contact_list', 'Edit to add address') if item.ghost else str(item.uri or '')
elif role == Qt.EditRole: elif role == Qt.EditRole:
if column == ContactURIModel.AddressColumn: if column == ContactURIModel.AddressColumn:
return str(item.uri or '') return str(item.uri or '')
...@@ -4544,7 +4551,7 @@ class ContactURIModel(QAbstractTableModel): ...@@ -4544,7 +4551,7 @@ class ContactURIModel(QAbstractTableModel):
def headerData(self, section, orientation, role=Qt.DisplayRole): def headerData(self, section, orientation, role=Qt.DisplayRole):
if orientation == Qt.Horizontal and role == Qt.DisplayRole: if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self.columns[section] return translate('contact_editor', self.columns[section])
return super(ContactURIModel, self).headerData(section, orientation, role) return super(ContactURIModel, self).headerData(section, orientation, role)
def init_with_address(self, address=None): def init_with_address(self, address=None):
...@@ -4622,7 +4629,7 @@ class ContactURITableView(QTableView): ...@@ -4622,7 +4629,7 @@ class ContactURITableView(QTableView):
super(ContactURITableView, self).__init__(parent) super(ContactURITableView, self).__init__(parent)
self.setItemDelegate(ContactURIDelegate(self)) self.setItemDelegate(ContactURIDelegate(self))
self.context_menu = QMenu(self) self.context_menu = QMenu(self)
self.context_menu.addAction("Delete", self._AH_DeleteSelection) self.context_menu.addAction(translate('contact_editor', "Delete"), self._AH_DeleteSelection)
self.horizontalHeader().setSectionResizeMode(self.horizontalHeader().ResizeToContents) self.horizontalHeader().setSectionResizeMode(self.horizontalHeader().ResizeToContents)
def selectionChanged(self, selected, deselected): def selectionChanged(self, selected, deselected):
...@@ -4673,11 +4680,11 @@ class ContactEditorDialog(base_class, ui_class): ...@@ -4673,11 +4680,11 @@ class ContactEditorDialog(base_class, ui_class):
def setupUi(self, contact_editor): def setupUi(self, contact_editor):
super(ContactEditorDialog, self).setupUi(contact_editor) super(ContactEditorDialog, self).setupUi(contact_editor)
self.preferred_media.setItemData(0, 'audio') self.preferred_media.setItemData(0, translate('contact_editor', 'audio'))
self.preferred_media.setItemData(1, 'video') self.preferred_media.setItemData(1, translate('contact_editor', 'video'))
self.preferred_media.setItemData(2, 'chat') self.preferred_media.setItemData(2, translate('contact_editor', 'chat'))
self.preferred_media.setItemData(3, 'audio+chat') self.preferred_media.setItemData(3, translate('contact_editor', 'audio+chat'))
self.preferred_media.setItemData(4, 'messages') self.preferred_media.setItemData(4, translate('contact_editor', 'messages'))
self.addresses_table.verticalHeader().setDefaultSectionSize(URITypeComboBox().sizeHint().height()) self.addresses_table.verticalHeader().setDefaultSectionSize(URITypeComboBox().sizeHint().height())
def open_for_add(self, sip_address='', target_group=None): def open_for_add(self, sip_address='', target_group=None):
...@@ -4688,7 +4695,7 @@ class ContactEditorDialog(base_class, ui_class): ...@@ -4688,7 +4695,7 @@ class ContactEditorDialog(base_class, ui_class):
self.icon_selector.init_with_contact(None) self.icon_selector.init_with_contact(None)
self.presence.setChecked(True) self.presence.setChecked(True)
self.preferred_media.setCurrentIndex(0) self.preferred_media.setCurrentIndex(0)
self.accept_button.setText('Add') self.accept_button.setText(translate('contact_editor', 'Add'))
self.accept_button.setEnabled(False) self.accept_button.setEnabled(False)
self.show() self.show()
...@@ -4702,7 +4709,7 @@ class ContactEditorDialog(base_class, ui_class): ...@@ -4702,7 +4709,7 @@ class ContactEditorDialog(base_class, ui_class):
self.presence.setChecked(contact.presence.subscribe) self.presence.setChecked(contact.presence.subscribe)
self.auto_answer.setChecked(contact.auto_answer) self.auto_answer.setChecked(contact.auto_answer)
self.preferred_media.setCurrentIndex(self.preferred_media.findData(contact.preferred_media)) self.preferred_media.setCurrentIndex(self.preferred_media.findData(contact.preferred_media))
self.accept_button.setText('Ok') self.accept_button.setText(translate('contact_editor', 'Ok'))
self.accept_button.setEnabled(True) self.accept_button.setEnabled(True)
self.show() self.show()
......
...@@ -14,6 +14,7 @@ from zope.interface import implementer ...@@ -14,6 +14,7 @@ from zope.interface import implementer
from blink.configuration.settings import BlinkSettings from blink.configuration.settings import BlinkSettings
from blink.resources import Resources from blink.resources import Resources
from blink.sessions import FileTransferDelegate, FileTransferModel from blink.sessions import FileTransferDelegate, FileTransferModel
from blink.util import translate
from blink.widgets.util import ContextMenuActions from blink.widgets.util import ContextMenuActions
...@@ -38,13 +39,13 @@ class FileTransferWindow(base_class, ui_class): ...@@ -38,13 +39,13 @@ class FileTransferWindow(base_class, ui_class):
self.context_menu = QMenu(self.listview) self.context_menu = QMenu(self.listview)
self.actions = ContextMenuActions() self.actions = ContextMenuActions()
self.actions.open_file = QAction("Open", self, triggered=self._AH_OpenFile) self.actions.open_file = QAction(translate('filetransfer_window', "Open"), self, triggered=self._AH_OpenFile)
self.actions.open_file_folder = QAction("Open File Folder", self, triggered=self._AH_OpenFileFolder) self.actions.open_file_folder = QAction(translate('filetransfer_window', "Open File Folder"), self, triggered=self._AH_OpenFileFolder)
self.actions.cancel_transfer = QAction("Cancel", self, triggered=self._AH_CancelTransfer) self.actions.cancel_transfer = QAction(translate('filetransfer_window', "Cancel"), self, triggered=self._AH_CancelTransfer)
self.actions.retry_transfer = QAction("Retry", self, triggered=self._AH_RetryTransfer) self.actions.retry_transfer = QAction(translate('filetransfer_window', "Retry"), self, triggered=self._AH_RetryTransfer)
self.actions.remove_entry = QAction("Remove From List", self, triggered=self._AH_RemoveEntry) self.actions.remove_entry = QAction(translate('filetransfer_window', "Remove From List"), self, triggered=self._AH_RemoveEntry)
self.actions.open_downloads_folder = QAction("Open Transfers Folder", self, triggered=self._AH_OpenTransfersFolder) self.actions.open_downloads_folder = QAction(translate('filetransfer_window', "Open Transfers Folder"), self, triggered=self._AH_OpenTransfersFolder)
self.actions.clear_list = QAction("Clear List", self, triggered=self._AH_ClearList) self.actions.clear_list = QAction(translate('filetransfer_window', "Clear List"), self, triggered=self._AH_ClearList)
self.model.itemAdded.connect(self.update_status) self.model.itemAdded.connect(self.update_status)
self.model.itemRemoved.connect(self.update_status) self.model.itemRemoved.connect(self.update_status)
...@@ -66,9 +67,9 @@ class FileTransferWindow(base_class, ui_class): ...@@ -66,9 +67,9 @@ class FileTransferWindow(base_class, ui_class):
def update_status(self): def update_status(self):
total = len(self.model.items) total = len(self.model.items)
active = len([item for item in self.model.items if not item.ended]) active = len([item for item in self.model.items if not item.ended])
text = '%d %s' % (total, 'transfer' if total == 1 else 'transfers') text = '%d %s' % (total, translate('filetransfer_window', 'transfer') if total == 1 else translate('filetransfer_window', 'transfers'))
if active > 0: if active > 0:
text += ' (%d active)' % active text += translate('filetransfer_window', ' (%d active)') % active
self.status_label.setText(text) self.status_label.setText(text)
def handle_notification(self, notification): def handle_notification(self, notification):
......
...@@ -24,7 +24,7 @@ from blink.configuration.settings import BlinkSettings ...@@ -24,7 +24,7 @@ from blink.configuration.settings import BlinkSettings
from blink.logging import MessagingTrace as log from blink.logging import MessagingTrace as log
from blink.messages import BlinkMessage from blink.messages import BlinkMessage
from blink.resources import ApplicationData, Resources from blink.resources import ApplicationData, Resources
from blink.util import run_in_gui_thread from blink.util import run_in_gui_thread, translate
import traceback import traceback
from sqlobject import SQLObject, StringCol, DateTimeCol, IntCol, UnicodeCol, DatabaseIndex from sqlobject import SQLObject, StringCol, DateTimeCol, IntCol, UnicodeCol, DatabaseIndex
...@@ -587,15 +587,15 @@ class HistoryEntry(object): ...@@ -587,15 +587,15 @@ class HistoryEntry(object):
today = date.today() today = date.today()
days = (today - call_date).days days = (today - call_date).days
if call_date == today: if call_date == today:
result += call_time.strftime(" at %H:%M") result += call_time.strftime(translate("history", " at %H:%M"))
elif days == 1: elif days == 1:
result += call_time.strftime(" Yesterday at %H:%M") result += call_time.strftime(translate("history", " Yesterday at %H:%M"))
elif days < 7: elif days < 7:
result += call_time.strftime(" on %A") result += call_time.strftime(translate("history", " on %A"))
elif call_date.year == today.year: elif call_date.year == today.year:
result += call_time.strftime(" on %B %d") result += call_time.strftime(translate("history", " on %B %d"))
else: else:
result += call_time.strftime(" on %Y-%m-%d") result += call_time.strftime(translate("history", " on %Y-%m-%d"))
if self.duration: if self.duration:
seconds = int(self.duration.total_seconds()) seconds = int(self.duration.total_seconds())
if seconds >= 3600: if seconds >= 3600:
......
...@@ -31,7 +31,7 @@ from blink.configuration.datatypes import IconDescriptor, FileURL, PresenceState ...@@ -31,7 +31,7 @@ from blink.configuration.datatypes import IconDescriptor, FileURL, PresenceState
from blink.configuration.settings import BlinkSettings from blink.configuration.settings import BlinkSettings
from blink.presence import PendingWatcherDialog from blink.presence import PendingWatcherDialog
from blink.resources import ApplicationData, IconManager, Resources from blink.resources import ApplicationData, IconManager, Resources
from blink.util import run_in_gui_thread from blink.util import run_in_gui_thread, translate
from blink.widgets.buttons import AccountState, SwitchViewButton from blink.widgets.buttons import AccountState, SwitchViewButton
...@@ -97,8 +97,8 @@ class MainWindow(base_class, ui_class): ...@@ -97,8 +97,8 @@ class MainWindow(base_class, ui_class):
self.system_tray_icon = QSystemTrayIcon(QIcon(Resources.get('icons/blink.png')), self) self.system_tray_icon = QSystemTrayIcon(QIcon(Resources.get('icons/blink.png')), self)
self.system_tray_icon.activated.connect(self._SH_SystemTrayIconActivated) self.system_tray_icon.activated.connect(self._SH_SystemTrayIconActivated)
menu = QMenu(self) menu = QMenu(self)
menu.addAction("Show", self._AH_SystemTrayShowWindow) menu.addAction(translate("main_window", "Show"), self._AH_SystemTrayShowWindow)
menu.addAction(QIcon(Resources.get('icons/application-exit.png')), "Quit", self._AH_QuitActionTriggered) menu.addAction(QIcon(Resources.get('icons/application-exit.png')), translate("main_window", "Quit"), self._AH_QuitActionTriggered)
self.system_tray_icon.setContextMenu(menu) self.system_tray_icon.setContextMenu(menu)
self.system_tray_icon.show() self.system_tray_icon.show()
else: else:
...@@ -225,8 +225,8 @@ class MainWindow(base_class, ui_class): ...@@ -225,8 +225,8 @@ class MainWindow(base_class, ui_class):
self.alert_devices_group = QActionGroup(self) self.alert_devices_group = QActionGroup(self)
self.video_devices_group = QActionGroup(self) self.video_devices_group = QActionGroup(self)
self.screen_sharing_button.addAction(QAction('Request screen', self.screen_sharing_button, triggered=self._AH_RequestScreenActionTriggered)) self.screen_sharing_button.addAction(QAction(translate('main_window', 'Request screen'), self.screen_sharing_button, triggered=self._AH_RequestScreenActionTriggered))
self.screen_sharing_button.addAction(QAction('Share my screen', self.screen_sharing_button, triggered=self._AH_ShareMyScreenActionTriggered)) self.screen_sharing_button.addAction(QAction(translate('main_window', 'Share my screen'), self.screen_sharing_button, triggered=self._AH_ShareMyScreenActionTriggered))
# adjust search box height depending on theme as the value set in designer isn't suited for all themes # adjust search box height depending on theme as the value set in designer isn't suited for all themes
search_box = self.search_box search_box = self.search_box
...@@ -270,7 +270,7 @@ class MainWindow(base_class, ui_class): ...@@ -270,7 +270,7 @@ class MainWindow(base_class, ui_class):
action_map = {} action_map = {}
action = action_map['system_default'] = self.output_device_menu.addAction('System default') action = action_map['system_default'] = self.output_device_menu.addAction(translate('main_window', 'System default'))
action.setData('system_default') action.setData('system_default')
action.setCheckable(True) action.setCheckable(True)
self.output_devices_group.addAction(action) self.output_devices_group.addAction(action)
...@@ -283,7 +283,7 @@ class MainWindow(base_class, ui_class): ...@@ -283,7 +283,7 @@ class MainWindow(base_class, ui_class):
action.setCheckable(True) action.setCheckable(True)
self.output_devices_group.addAction(action) self.output_devices_group.addAction(action)
action = action_map[None] = self.output_device_menu.addAction('None') action = action_map[None] = self.output_device_menu.addAction(translate('main_window', 'None'))
action.setData(None) action.setData(None)
action.setCheckable(True) action.setCheckable(True)
self.output_devices_group.addAction(action) self.output_devices_group.addAction(action)
...@@ -293,7 +293,7 @@ class MainWindow(base_class, ui_class): ...@@ -293,7 +293,7 @@ class MainWindow(base_class, ui_class):
action_map = {} action_map = {}
action = action_map['system_default'] = self.input_device_menu.addAction('System default') action = action_map['system_default'] = self.input_device_menu.addAction(translate('main_window', 'System default'))
action.setData('system_default') action.setData('system_default')
action.setCheckable(True) action.setCheckable(True)
self.input_devices_group.addAction(action) self.input_devices_group.addAction(action)
...@@ -306,7 +306,7 @@ class MainWindow(base_class, ui_class): ...@@ -306,7 +306,7 @@ class MainWindow(base_class, ui_class):
action.setCheckable(True) action.setCheckable(True)
self.input_devices_group.addAction(action) self.input_devices_group.addAction(action)
action = action_map[None] = self.input_device_menu.addAction('None') action = action_map[None] = self.input_device_menu.addAction(translate('main_window', 'None'))
action.setData(None) action.setData(None)
action.setCheckable(True) action.setCheckable(True)
self.input_devices_group.addAction(action) self.input_devices_group.addAction(action)
...@@ -316,7 +316,7 @@ class MainWindow(base_class, ui_class): ...@@ -316,7 +316,7 @@ class MainWindow(base_class, ui_class):
action_map = {} action_map = {}
action = action_map['system_default'] = self.alert_device_menu.addAction('System default') action = action_map['system_default'] = self.alert_device_menu.addAction(translate('main_window', 'System default'))
action.setData('system_default') action.setData('system_default')
action.setCheckable(True) action.setCheckable(True)
self.alert_devices_group.addAction(action) self.alert_devices_group.addAction(action)
...@@ -329,7 +329,7 @@ class MainWindow(base_class, ui_class): ...@@ -329,7 +329,7 @@ class MainWindow(base_class, ui_class):
action.setCheckable(True) action.setCheckable(True)
self.alert_devices_group.addAction(action) self.alert_devices_group.addAction(action)
action = action_map[None] = self.alert_device_menu.addAction('None') action = action_map[None] = self.alert_device_menu.addAction(translate('main_window', 'None'))
action.setData(None) action.setData(None)
action.setCheckable(True) action.setCheckable(True)
self.alert_devices_group.addAction(action) self.alert_devices_group.addAction(action)
...@@ -342,7 +342,7 @@ class MainWindow(base_class, ui_class): ...@@ -342,7 +342,7 @@ class MainWindow(base_class, ui_class):
action_map = {} action_map = {}
action = action_map['system_default'] = self.video_camera_menu.addAction('System default') action = action_map['system_default'] = self.video_camera_menu.addAction(translate('main_window', 'System default'))
action.setData('system_default') action.setData('system_default')
action.setCheckable(True) action.setCheckable(True)
self.video_devices_group.addAction(action) self.video_devices_group.addAction(action)
...@@ -355,7 +355,7 @@ class MainWindow(base_class, ui_class): ...@@ -355,7 +355,7 @@ class MainWindow(base_class, ui_class):
action.setCheckable(True) action.setCheckable(True)
self.video_devices_group.addAction(action) self.video_devices_group.addAction(action)
action = action_map[None] = self.video_camera_menu.addAction('None') action = action_map[None] = self.video_camera_menu.addAction(translate('main_window', 'None'))
action.setData(None) action.setData(None)
action.setCheckable(True) action.setCheckable(True)
self.video_devices_group.addAction(action) self.video_devices_group.addAction(action)
...@@ -476,7 +476,7 @@ class MainWindow(base_class, ui_class): ...@@ -476,7 +476,7 @@ class MainWindow(base_class, ui_class):
action.entry = entry action.entry = entry
action.setToolTip(entry.uri) action.setToolTip(entry.uri)
else: else:
action = self.history_menu.addAction("Call history is empty") action = self.history_menu.addAction(translate("main_window", "Call history is empty"))
action.setEnabled(False) action.setEnabled(False)
def _AH_HistoryMenuTriggered(self, action): def _AH_HistoryMenuTriggered(self, action):
...@@ -502,11 +502,11 @@ class MainWindow(base_class, ui_class): ...@@ -502,11 +502,11 @@ class MainWindow(base_class, ui_class):
def _SH_AccountStateChanged(self): def _SH_AccountStateChanged(self):
self.activity_note.setText(self.account_state.note) self.activity_note.setText(self.account_state.note)
if self.account_state.state is AccountState.Invisible: if self.account_state.state is AccountState.Invisible:
self.activity_note.inactiveText = '(invisible)' self.activity_note.inactiveText = translate('main_window', '(invisible)')
self.activity_note.setEnabled(False) self.activity_note.setEnabled(False)
else: else:
if not self.activity_note.isEnabled(): if not self.activity_note.isEnabled():
self.activity_note.inactiveText = 'Add an activity note here' self.activity_note.inactiveText = translate('main_window', 'Add an activity note here')
self.activity_note.setEnabled(True) self.activity_note.setEnabled(True)
if not self.account_state.state.internal: if not self.account_state.state.internal:
self.saved_account_state = None self.saved_account_state = None
...@@ -516,7 +516,7 @@ class MainWindow(base_class, ui_class): ...@@ -516,7 +516,7 @@ class MainWindow(base_class, ui_class):
blink_settings.save() blink_settings.save()
def _SH_AccountStateClicked(self, checked): def _SH_AccountStateClicked(self, checked):
filename = QFileDialog.getOpenFileName(self, 'Select Icon', self.last_icon_directory, "Images (*.png *.tiff *.jpg *.xmp *.svg)")[0] filename = QFileDialog.getOpenFileName(self, translate('main_window', 'Select Icon'), self.last_icon_directory, "Images (*.png *.tiff *.jpg *.xmp *.svg)")[0]
if filename: if filename:
self.last_icon_directory = os.path.dirname(filename) self.last_icon_directory = os.path.dirname(filename)
filename = filename if os.path.realpath(filename) != os.path.realpath(self.default_icon_path) else None filename = filename if os.path.realpath(filename) != os.path.realpath(self.default_icon_path) else None
...@@ -700,7 +700,7 @@ class MainWindow(base_class, ui_class): ...@@ -700,7 +700,7 @@ class MainWindow(base_class, ui_class):
self.contacts_view.setCurrentWidget(self.search_panel) self.contacts_view.setCurrentWidget(self.search_panel)
self.search_view.setCurrentWidget(self.search_list_panel if self.contact_search_model.rowCount() else self.not_found_panel) self.search_view.setCurrentWidget(self.search_list_panel if self.contact_search_model.rowCount() else self.not_found_panel)
selected_items = self.search_list.selectionModel().selectedIndexes() selected_items = self.search_list.selectionModel().selectedIndexes()
self.enable_call_buttons(account_manager.default_account is not None and len(selected_items)<=1) self.enable_call_buttons(account_manager.default_account is not None and len(selected_items) <= 1)
else: else:
self.contacts_view.setCurrentWidget(self.contact_list_panel) self.contacts_view.setCurrentWidget(self.contact_list_panel)
selected_items = self.contact_list.selectionModel().selectedIndexes() selected_items = self.contact_list.selectionModel().selectedIndexes()
...@@ -739,7 +739,7 @@ class MainWindow(base_class, ui_class): ...@@ -739,7 +739,7 @@ class MainWindow(base_class, ui_class):
def _SH_AudioSessionModelChangedStructure(self): def _SH_AudioSessionModelChangedStructure(self):
active_sessions = self.session_model.active_sessions active_sessions = self.session_model.active_sessions
self.active_sessions_label.setText('There is 1 active call' if len(active_sessions) == 1 else 'There are %d active calls' % len(active_sessions)) self.active_sessions_label.setText(translate('main_window', 'There is 1 active call') if len(active_sessions) == 1 else translate('main_window', 'There are %d active calls') % len(active_sessions))
self.active_sessions_label.setVisible(any(active_sessions)) self.active_sessions_label.setVisible(any(active_sessions))
self.hangup_all_button.setEnabled(any(active_sessions)) self.hangup_all_button.setEnabled(any(active_sessions))
selected_indexes = self.session_list.selectionModel().selectedIndexes() selected_indexes = self.session_list.selectionModel().selectedIndexes()
...@@ -754,7 +754,7 @@ class MainWindow(base_class, ui_class): ...@@ -754,7 +754,7 @@ class MainWindow(base_class, ui_class):
if self.account_state.state is not AccountState.Invisible: if self.account_state.state is not AccountState.Invisible:
if self.saved_account_state is None: if self.saved_account_state is None:
self.saved_account_state = self.account_state.state, self.activity_note.text() self.saved_account_state = self.account_state.state, self.activity_note.text()
self.account_state.setState(AccountState.Busy.Internal, note='On the phone') self.account_state.setState(AccountState.Busy.Internal, note=translate('main_window', 'On the phone'))
elif self.saved_account_state is not None: elif self.saved_account_state is not None:
state, note = self.saved_account_state state, note = self.saved_account_state
self.saved_account_state = None self.saved_account_state = None
...@@ -797,9 +797,9 @@ class MainWindow(base_class, ui_class): ...@@ -797,9 +797,9 @@ class MainWindow(base_class, ui_class):
self.auto_accept_chat_action.setChecked(settings.chat.auto_accept) self.auto_accept_chat_action.setChecked(settings.chat.auto_accept)
self.received_messages_sound_action.setChecked(settings.sounds.play_message_alerts) self.received_messages_sound_action.setChecked(settings.sounds.play_message_alerts)
if settings.google_contacts.enabled: if settings.google_contacts.enabled:
self.google_contacts_action.setText('Disable &Google Contacts') self.google_contacts_action.setText(translate('main_window', 'Disable &Google Contacts'))
else: else:
self.google_contacts_action.setText('Enable &Google Contacts...') self.google_contacts_action.setText(translate('main_window', 'Enable &Google Contacts...'))
if not any(account.enabled for account in account_manager.iter_accounts()): if not any(account.enabled for account in account_manager.iter_accounts()):
self.display_name.setEnabled(False) self.display_name.setEnabled(False)
self.activity_note.setEnabled(False) self.activity_note.setEnabled(False)
...@@ -874,9 +874,9 @@ class MainWindow(base_class, ui_class): ...@@ -874,9 +874,9 @@ class MainWindow(base_class, ui_class):
self.received_messages_sound_action.setChecked(settings.sounds.play_message_alerts) self.received_messages_sound_action.setChecked(settings.sounds.play_message_alerts)
if 'google_contacts.enabled' in notification.data.modified: if 'google_contacts.enabled' in notification.data.modified:
if notification.sender.google_contacts.enabled: if notification.sender.google_contacts.enabled:
self.google_contacts_action.setText('Disable &Google Contacts') self.google_contacts_action.setText(translate('main_window', 'Disable &Google Contacts'))
else: else:
self.google_contacts_action.setText('Enable &Google Contacts...') self.google_contacts_action.setText(translate('main_window', 'Enable &Google Contacts...'))
elif notification.sender is blink_settings: elif notification.sender is blink_settings:
if 'presence.current_state' in notification.data.modified: if 'presence.current_state' in notification.data.modified:
state = getattr(AccountState, blink_settings.presence.current_state.state, AccountState.Available) state = getattr(AccountState, blink_settings.presence.current_state.state, AccountState.Available)
......
...@@ -41,7 +41,7 @@ from sipsimple.util import ISOTimestamp ...@@ -41,7 +41,7 @@ from sipsimple.util import ISOTimestamp
from blink.logging import MessagingTrace as log from blink.logging import MessagingTrace as log
from blink.resources import Resources from blink.resources import Resources
from blink.sessions import SessionManager, StreamDescription, IncomingDialogBase from blink.sessions import SessionManager, StreamDescription, IncomingDialogBase
from blink.util import run_in_gui_thread from blink.util import run_in_gui_thread, translate
__all__ = ['MessageManager', 'BlinkMessage'] __all__ = ['MessageManager', 'BlinkMessage']
...@@ -60,7 +60,7 @@ class GeneratePGPKeyDialog(IncomingDialogBase, ui_class): ...@@ -60,7 +60,7 @@ class GeneratePGPKeyDialog(IncomingDialogBase, ui_class):
self.setupUi(self) self.setupUi(self)
self.slot = None self.slot = None
self.generate_button = self.dialog_button_box.addButton("Generate", QDialogButtonBox.AcceptRole) self.generate_button = self.dialog_button_box.addButton(translate("generate_pgp_key_dialog", "Generate"), QDialogButtonBox.AcceptRole)
self.generate_button.setIcon(QApplication.style().standardIcon(QStyle.SP_DialogApplyButton)) self.generate_button.setIcon(QApplication.style().standardIcon(QStyle.SP_DialogApplyButton))
def show(self, activate=True): def show(self, activate=True):
...@@ -136,7 +136,7 @@ class ImportDialog(IncomingDialogBase, ui_class): ...@@ -136,7 +136,7 @@ class ImportDialog(IncomingDialogBase, ui_class):
self.setupUi(self) self.setupUi(self)
self.slot = None self.slot = None
self.import_button = self.dialog_button_box.addButton("Import", QDialogButtonBox.AcceptRole) self.import_button = self.dialog_button_box.addButton(translate("import_key_dialog", "Import"), QDialogButtonBox.AcceptRole)
self.import_button.setIcon(QApplication.style().standardIcon(QStyle.SP_DialogApplyButton)) self.import_button.setIcon(QApplication.style().standardIcon(QStyle.SP_DialogApplyButton))
self.import_button.setEnabled(False) self.import_button.setEnabled(False)
...@@ -232,7 +232,7 @@ class ExportDialog(IncomingDialogBase, ui_class): ...@@ -232,7 +232,7 @@ class ExportDialog(IncomingDialogBase, ui_class):
self.setupUi(self) self.setupUi(self)
self.slot = None self.slot = None
self.export_button = self.dialog_button_box.addButton("Export", QDialogButtonBox.AcceptRole) self.export_button = self.dialog_button_box.addButton(translate("export_key_dialog", "Export"), QDialogButtonBox.AcceptRole)
self.export_button.setIcon(QApplication.style().standardIcon(QStyle.SP_DialogApplyButton)) self.export_button.setIcon(QApplication.style().standardIcon(QStyle.SP_DialogApplyButton))
self.export_button.setEnabled(False) self.export_button.setEnabled(False)
......
...@@ -28,7 +28,7 @@ from blink.configuration.datatypes import FileURL ...@@ -28,7 +28,7 @@ from blink.configuration.datatypes import FileURL
from blink.configuration.settings import BlinkSettings from blink.configuration.settings import BlinkSettings
from blink.resources import ApplicationData, Resources from blink.resources import ApplicationData, Resources
from blink.logging import LogManager from blink.logging import LogManager
from blink.util import QSingleton, call_in_gui_thread, run_in_gui_thread from blink.util import QSingleton, call_in_gui_thread, run_in_gui_thread, translate
__all__ = ['PreferencesWindow', 'AccountListView', 'SIPPortEditor'] __all__ = ['PreferencesWindow', 'AccountListView', 'SIPPortEditor']
...@@ -217,7 +217,7 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton): ...@@ -217,7 +217,7 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton):
with Resources.directory: with Resources.directory:
self.setupUi() self.setupUi()
self.setWindowTitle('Blink Preferences') self.setWindowTitle(translate('preferences_window', 'Blink Preferences'))
self.account_list.setModel(account_model) self.account_list.setModel(account_model)
self.delete_account_button.setEnabled(False) self.delete_account_button.setEnabled(False)
...@@ -395,10 +395,10 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton): ...@@ -395,10 +395,10 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton):
# Accounts # Accounts
self.key_negotiation_button.clear() self.key_negotiation_button.clear()
self.key_negotiation_button.addItem('Opportunistic', 'opportunistic') self.key_negotiation_button.addItem(translate('preferences_window', 'Opportunistic'), 'opportunistic')
self.key_negotiation_button.addItem('ZRTP', 'zrtp') self.key_negotiation_button.addItem(translate('preferences_window', 'ZRTP'), 'zrtp')
self.key_negotiation_button.addItem('SDES optional', 'sdes_optional') self.key_negotiation_button.addItem(translate('preferences_window', 'SDES optional'), 'sdes_optional')
self.key_negotiation_button.addItem('SDES mandatory', 'sdes_mandatory') self.key_negotiation_button.addItem(translate('preferences_window', 'SDES mandatory'), 'sdes_mandatory')
# Audio # Audio
...@@ -427,7 +427,7 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton): ...@@ -427,7 +427,7 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton):
self.video_framerate_button.addItem('%d fps' % rate, rate) self.video_framerate_button.addItem('%d fps' % rate, rate)
self.video_codec_bitrate_button.clear() self.video_codec_bitrate_button.clear()
self.video_codec_bitrate_button.addItem('automatic', None) self.video_codec_bitrate_button.addItem(translate('preferences_window', 'automatic'), None)
for bitrate in (1.0, 2.0, 4.0): for bitrate in (1.0, 2.0, 4.0):
self.video_codec_bitrate_button.addItem('%g Mbps' % bitrate, bitrate) self.video_codec_bitrate_button.addItem('%g Mbps' % bitrate, bitrate)
...@@ -473,7 +473,7 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton): ...@@ -473,7 +473,7 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton):
# Languages # Languages
self.language_button.clear() self.language_button.clear()
languages_path = Resources.get('i18n') languages_path = Resources.get('i18n')
self.language_button.addItem('System Default', Language('default')) self.language_button.addItem(translate('preferences_window', 'System Default'), Language('default'))
self.language_button.addItem('English', Language('en')) self.language_button.addItem('English', Language('en'))
for language_file in os.listdir(languages_path): for language_file in os.listdir(languages_path):
try: try:
...@@ -660,30 +660,30 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton): ...@@ -660,30 +660,30 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton):
class Separator: pass class Separator: pass
self.audio_input_device_button.clear() self.audio_input_device_button.clear()
self.audio_input_device_button.addItem('System Default', 'system_default') self.audio_input_device_button.addItem(translate('preferences_window', 'System Default'), 'system_default')
self.audio_input_device_button.insertSeparator(1) self.audio_input_device_button.insertSeparator(1)
self.audio_input_device_button.setItemData(1, Separator) # prevent the separator from being selected (must have different itemData than the None device) self.audio_input_device_button.setItemData(1, Separator) # prevent the separator from being selected (must have different itemData than the None device)
for device in SIPApplication.engine.input_devices: for device in SIPApplication.engine.input_devices:
self.audio_input_device_button.addItem(device, device) self.audio_input_device_button.addItem(device, device)
self.audio_input_device_button.addItem('None', None) self.audio_input_device_button.addItem(translate('preferences_window', 'None'), None)
self.audio_input_device_button.setCurrentIndex(self.audio_input_device_button.findData(settings.audio.input_device)) self.audio_input_device_button.setCurrentIndex(self.audio_input_device_button.findData(settings.audio.input_device))
self.audio_output_device_button.clear() self.audio_output_device_button.clear()
self.audio_output_device_button.addItem('System Default', 'system_default') self.audio_output_device_button.addItem(translate('preferences_window', 'System Default'), 'system_default')
self.audio_output_device_button.insertSeparator(1) self.audio_output_device_button.insertSeparator(1)
self.audio_output_device_button.setItemData(1, Separator) # prevent the separator from being selected (must have different itemData than the None device) self.audio_output_device_button.setItemData(1, Separator) # prevent the separator from being selected (must have different itemData than the None device)
for device in SIPApplication.engine.output_devices: for device in SIPApplication.engine.output_devices:
self.audio_output_device_button.addItem(device, device) self.audio_output_device_button.addItem(device, device)
self.audio_output_device_button.addItem('None', None) self.audio_output_device_button.addItem(translate('preferences_window', 'None'), None)
self.audio_output_device_button.setCurrentIndex(self.audio_output_device_button.findData(settings.audio.output_device)) self.audio_output_device_button.setCurrentIndex(self.audio_output_device_button.findData(settings.audio.output_device))
self.audio_alert_device_button.clear() self.audio_alert_device_button.clear()
self.audio_alert_device_button.addItem('System Default', 'system_default') self.audio_alert_device_button.addItem(translate('preferences_window', 'System Default'), 'system_default')
self.audio_alert_device_button.insertSeparator(1) self.audio_alert_device_button.insertSeparator(1)
self.audio_alert_device_button.setItemData(1, Separator) # prevent the separator from being selected (must have different itemData than the None device) self.audio_alert_device_button.setItemData(1, Separator) # prevent the separator from being selected (must have different itemData than the None device)
for device in SIPApplication.engine.output_devices: for device in SIPApplication.engine.output_devices:
self.audio_alert_device_button.addItem(device, device) self.audio_alert_device_button.addItem(device, device)
self.audio_alert_device_button.addItem('None', None) self.audio_alert_device_button.addItem(translate('preferences_window', 'None'), None)
self.audio_alert_device_button.setCurrentIndex(self.audio_alert_device_button.findData(settings.audio.alert_device)) self.audio_alert_device_button.setCurrentIndex(self.audio_alert_device_button.findData(settings.audio.alert_device))
def load_video_devices(self): def load_video_devices(self):
...@@ -692,12 +692,12 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton): ...@@ -692,12 +692,12 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton):
class Separator: pass class Separator: pass
self.video_camera_button.clear() self.video_camera_button.clear()
self.video_camera_button.addItem('System Default', 'system_default') self.video_camera_button.addItem(translate('preferences_window', 'System Default'), 'system_default')
self.video_camera_button.insertSeparator(1) self.video_camera_button.insertSeparator(1)
self.video_camera_button.setItemData(1, Separator) # prevent the separator from being selected (must have different itemData than the None device) self.video_camera_button.setItemData(1, Separator) # prevent the separator from being selected (must have different itemData than the None device)
for device in SIPApplication.engine.video_devices: for device in SIPApplication.engine.video_devices:
self.video_camera_button.addItem(device, device) self.video_camera_button.addItem(device, device)
self.video_camera_button.addItem('None', None) self.video_camera_button.addItem(translate('preferences_window', 'None'), None)
self.video_camera_button.setCurrentIndex(self.video_camera_button.findData(settings.video.device)) self.video_camera_button.setCurrentIndex(self.video_camera_button.findData(settings.video.device))
def load_settings(self): def load_settings(self):
...@@ -859,11 +859,11 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton): ...@@ -859,11 +859,11 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton):
if selected_account_info.registration_state: if selected_account_info.registration_state:
if selected_account_info.registration_state == 'succeeded' and selected_account_info.registrar is not None: if selected_account_info.registration_state == 'succeeded' and selected_account_info.registrar is not None:
self.account_registration_label.setText('Registered at %s' % selected_account_info.registrar) self.account_registration_label.setText(translate('preferences_window', 'Registered at %s') % selected_account_info.registrar)
else: else:
self.account_registration_label.setText('Registration %s' % selected_account_info.registration_state.title()) self.account_registration_label.setText(translate('preferences_window', 'Registration %s') % selected_account_info.registration_state.title())
else: else:
self.account_registration_label.setText('Not Registered') self.account_registration_label.setText(translate('preferences_window', 'Not Registered'))
else: else:
self.account_registration_label.setText('') self.account_registration_label.setText('')
...@@ -903,7 +903,7 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton): ...@@ -903,7 +903,7 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton):
self.message_pgp_enabled_button.setChecked(account.sms.enable_pgp) self.message_pgp_enabled_button.setChecked(account.sms.enable_pgp)
if account is not bonjour_account: if account is not bonjour_account:
self.account_auto_answer.setText('Auto answer from allowed contacts') self.account_auto_answer.setText(translate('preferences_window', 'Auto answer from allowed contacts'))
# Server settings tab # Server settings tab
self.always_use_my_proxy_button.setChecked(account.sip.always_use_my_proxy) self.always_use_my_proxy_button.setChecked(account.sip.always_use_my_proxy)
outbound_proxy = account.sip.outbound_proxy or UnspecifiedOutboundProxy outbound_proxy = account.sip.outbound_proxy or UnspecifiedOutboundProxy
...@@ -952,7 +952,7 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton): ...@@ -952,7 +952,7 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton):
self.idd_prefix_button.addItem(item_text) self.idd_prefix_button.addItem(item_text)
self.idd_prefix_button.setCurrentIndex(self.idd_prefix_button.findText(item_text)) self.idd_prefix_button.setCurrentIndex(self.idd_prefix_button.findText(item_text))
item_text = account.pstn.prefix or 'None' item_text = account.pstn.prefix or translate('preferences_window', 'None')
index = self.prefix_button.findText(item_text) index = self.prefix_button.findText(item_text)
if index == -1: if index == -1:
self.prefix_button.addItem(item_text) self.prefix_button.addItem(item_text)
...@@ -975,7 +975,7 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton): ...@@ -975,7 +975,7 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton):
self.last_id_editor.setEnabled(account.sms.enable_history_synchronization) self.last_id_editor.setEnabled(account.sms.enable_history_synchronization)
self.last_id_editor.setText(account.sms.history_synchronization_id) self.last_id_editor.setText(account.sms.history_synchronization_id)
else: else:
self.account_auto_answer.setText('Auto answer from all neighbours') self.account_auto_answer.setText(translate('preferences_window', 'Auto answer from all neighbours'))
self.message_replication_button.hide() self.message_replication_button.hide()
self.message_synchronization_button.hide() self.message_synchronization_button.hide()
...@@ -1079,7 +1079,7 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton): ...@@ -1079,7 +1079,7 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton):
logs_size += os.stat(os.path.join(path, name)).st_size logs_size += os.stat(os.path.join(path, name)).st_size
except (OSError, IOError): except (OSError, IOError):
pass pass
self.log_files_size_label.setText("There are currently %s of log files" % self._normalize_binary_size(logs_size)) self.log_files_size_label.setText(translate('preferences_window', "There are currently %s of log files") % self._normalize_binary_size(logs_size))
def _update_pstn_example_label(self): def _update_pstn_example_label(self):
prefix = self.prefix_button.currentText() prefix = self.prefix_button.currentText()
...@@ -1142,15 +1142,15 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton): ...@@ -1142,15 +1142,15 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton):
self.password_editor.hide() self.password_editor.hide()
else: else:
if tab_widget.indexOf(self.server_settings_tab) == -1: if tab_widget.indexOf(self.server_settings_tab) == -1:
tab_widget.addTab(self.server_settings_tab, "Server Settings") tab_widget.addTab(self.server_settings_tab, translate('preferences_window', "Server Settings"))
if tab_widget.indexOf(self.network_tab) == -1: if tab_widget.indexOf(self.network_tab) == -1:
tab_widget.addTab(self.network_tab, "NAT Traversal") tab_widget.addTab(self.network_tab, translate('preferences_window', "NAT Traversal"))
if tab_widget.indexOf(self.advanced_tab) == -1: if tab_widget.indexOf(self.advanced_tab) == -1:
tab_widget.addTab(self.advanced_tab, "Advanced") tab_widget.addTab(self.advanced_tab, translate('preferences_window', "Advanced"))
self.password_label.show() self.password_label.show()
self.password_editor.show() self.password_editor.show()
self.voicemail_uri_editor.inactiveText = "Discovered by subscribing to %s" % selected_account.id self.voicemail_uri_editor.inactiveText = translate('preferences_window', "Discovered by subscribing to %s") % selected_account.id
self.xcap_root_editor.inactiveText = "Taken from the DNS TXT record for xcap.%s" % selected_account.id.domain self.xcap_root_editor.inactiveText = translate('preferences_window', "Taken from the DNS TXT record for xcap.%s") % selected_account.id.domain
self.load_account_settings(selected_account) self.load_account_settings(selected_account)
def _SH_AccountListDataChanged(self, topLeft, bottomRight): def _SH_AccountListDataChanged(self, topLeft, bottomRight):
...@@ -1163,9 +1163,9 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton): ...@@ -1163,9 +1163,9 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton):
selected_account_info = self.account_list.model().data(selected_index, Qt.UserRole) selected_account_info = self.account_list.model().data(selected_index, Qt.UserRole)
if selected_account_info is account_info: if selected_account_info is account_info:
if account_info.registration_state: if account_info.registration_state:
self.account_registration_label.setText('Registration %s' % account_info.registration_state.title()) self.account_registration_label.setText(translate('preferences_window', 'Registration %s') % account_info.registration_state.title())
else: else:
self.account_registration_label.setText('Not Registered') self.account_registration_label.setText(translate('preferences_window', 'Not Registered'))
def _SH_DeleteAccountButtonClicked(self): def _SH_DeleteAccountButtonClicked(self):
model = self.account_list.model() model = self.account_list.model()
...@@ -1173,7 +1173,7 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton): ...@@ -1173,7 +1173,7 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton):
selected_index = self.account_list.selectionModel().selectedIndexes()[0] selected_index = self.account_list.selectionModel().selectedIndexes()[0]
selected_account = selected_index.data(Qt.UserRole).account selected_account = selected_index.data(Qt.UserRole).account
title, message = "Remove Account", "Permanently remove account %s?" % selected_account.id title, message = translate('preferences_window', "Remove Account"), translate('preferences_window', "Permanently remove account %s?") % selected_account.id
if QMessageBox.question(self, title, message, QMessageBox.Ok | QMessageBox.Cancel) == QMessageBox.Cancel: if QMessageBox.question(self, title, message, QMessageBox.Ok | QMessageBox.Cancel) == QMessageBox.Cancel:
return return
...@@ -1498,9 +1498,9 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton): ...@@ -1498,9 +1498,9 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton):
X509Certificate(contents) X509Certificate(contents)
X509PrivateKey(contents) X509PrivateKey(contents)
except (OSError, IOError) as e: except (OSError, IOError) as e:
QMessageBox.critical(self, "TLS Certificate Error", "The certificate file could not be opened: %s" % e.strerror) QMessageBox.critical(self, translate('preferences_window', "TLS Certificate Error"), translate('preferences_window', "The certificate file could not be opened: %s") % e.strerror)
except GNUTLSError as e: except GNUTLSError as e:
QMessageBox.critical(self, "TLS Certificate Error", "The certificate file is invalid: %s" % e) QMessageBox.critical(self, translate('preferences_window', "TLS Certificate Error"), translate('preferences_window', "The certificate file is invalid: %s") % e)
else: else:
self.tls_cert_file_editor.setText(cert_path) self.tls_cert_file_editor.setText(cert_path)
settings.tls.certificate = cert_path settings.tls.certificate = cert_path
...@@ -1619,16 +1619,16 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton): ...@@ -1619,16 +1619,16 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton):
if value == 0: if value == 0:
self.answer_delay_seconds_label.setText('') self.answer_delay_seconds_label.setText('')
elif value == 1: elif value == 1:
self.answer_delay_seconds_label.setText('second') self.answer_delay_seconds_label.setText(translate('preferences_window', 'second'))
else: else:
self.answer_delay_seconds_label.setText('seconds') self.answer_delay_seconds_label.setText(translate('preferences_window', 'seconds'))
settings = SIPSimpleSettings() settings = SIPSimpleSettings()
if settings.answering_machine.answer_delay != value: if settings.answering_machine.answer_delay != value:
settings.answering_machine.answer_delay = value settings.answering_machine.answer_delay = value
settings.save() settings.save()
def _SH_MaxRecordingValueChanged(self, value): def _SH_MaxRecordingValueChanged(self, value):
self.max_recording_minutes_label.setText('minute' if value == 1 else 'minutes') self.max_recording_minutes_label.setText(translate('preferences_window', 'minute') if value == 1 else translate('preferences_window', 'minutes'))
settings = SIPSimpleSettings() settings = SIPSimpleSettings()
if settings.answering_machine.max_recording != value: if settings.answering_machine.max_recording != value:
settings.answering_machine.max_recording = value settings.answering_machine.max_recording = value
...@@ -1762,7 +1762,7 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton): ...@@ -1762,7 +1762,7 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton):
def _SH_ScreenshotsDirectoryBrowseButtonClicked(self, checked): def _SH_ScreenshotsDirectoryBrowseButtonClicked(self, checked):
# TODO: open the file selection dialog in non-modal mode. Same for the one for TLS CA list and the IconSelector from contacts. -Dan # TODO: open the file selection dialog in non-modal mode. Same for the one for TLS CA list and the IconSelector from contacts. -Dan
settings = BlinkSettings() settings = BlinkSettings()
directory = QFileDialog.getExistingDirectory(self, 'Select Screenshots Directory', settings.screenshots_directory.normalized) or None directory = QFileDialog.getExistingDirectory(self, translate('preferences_window', 'Select Screenshots Directory'), settings.screenshots_directory.normalized) or None
if directory is not None: if directory is not None:
directory = os.path.normpath(directory) directory = os.path.normpath(directory)
if directory != settings.screenshots_directory: if directory != settings.screenshots_directory:
...@@ -1789,7 +1789,7 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton): ...@@ -1789,7 +1789,7 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton):
def _SH_TransfersDirectoryBrowseButtonClicked(self, checked): def _SH_TransfersDirectoryBrowseButtonClicked(self, checked):
# TODO: open the file selection dialog in non-modal mode. Same for the one for TLS CA list and the IconSelector from contacts. -Dan # TODO: open the file selection dialog in non-modal mode. Same for the one for TLS CA list and the IconSelector from contacts. -Dan
settings = BlinkSettings() settings = BlinkSettings()
directory = QFileDialog.getExistingDirectory(self, 'Select Transfers Directory', settings.transfers_directory.normalized) or None directory = QFileDialog.getExistingDirectory(self, translate('preferences_window', 'Select Transfers Directory'), settings.transfers_directory.normalized) or None
if directory is not None: if directory is not None:
directory = os.path.normpath(directory) directory = os.path.normpath(directory)
if directory != settings.transfers_directory: if directory != settings.transfers_directory:
...@@ -1909,9 +1909,9 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton): ...@@ -1909,9 +1909,9 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton):
try: try:
X509Certificate(open(ca_path).read()) X509Certificate(open(ca_path).read())
except (OSError, IOError) as e: except (OSError, IOError) as e:
QMessageBox.critical(self, "TLS Certificate Error", "The certificate authority file could not be opened: %s" % e.strerror) QMessageBox.critical(self, translate('preferences_window', "TLS Certificate Error"), translate('preferences_window', "The certificate authority file could not be opened: %s") % e.strerror)
except GNUTLSError as e: except GNUTLSError as e:
QMessageBox.critical(self, "TLS Certificate Error", "The certificate authority file is invalid: %s" % e) QMessageBox.critical(self, translate('preferences_window', "TLS Certificate Error"), translate('preferences_window', "The certificate authority file is invalid: %s") % e)
else: else:
self.tls_ca_file_editor.setText(ca_path) self.tls_ca_file_editor.setText(ca_path)
settings.tls.ca_list = ca_path settings.tls.ca_list = ca_path
...@@ -1928,8 +1928,8 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton): ...@@ -1928,8 +1928,8 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton):
if data.language_code != settings.interface.language: if data.language_code != settings.interface.language:
settings.interface.language = data.language_code settings.interface.language = data.language_code
settings.save() settings.save()
title = "Restart required" title = translate('preferences_window', "Restart required")
question = "The application language was changed. A restart is required to apply the change. Would you like to restart now?" question = translate('preferences_window', "The application language was changed. A restart is required to apply the change. Would you like to restart now?")
if QMessageBox.question(self, title, question) == QMessageBox.No: if QMessageBox.question(self, title, question) == QMessageBox.No:
return return
...@@ -1983,13 +1983,13 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton): ...@@ -1983,13 +1983,13 @@ class PreferencesWindow(base_class, ui_class, metaclass=QSingleton):
if 'sounds.play_message_alerts' in notification.data.modified: if 'sounds.play_message_alerts' in notification.data.modified:
self.chat_message_alert_button.setChecked(settings.sounds.play_message_alerts) self.chat_message_alert_button.setChecked(settings.sounds.play_message_alerts)
if 'sip.auto_answer_interval' in notification.data.modified: if 'sip.auto_answer_interval' in notification.data.modified:
self.auto_answer_interval.setValue(settings.sip.auto_answer_interval) self.auto_answer_interval.setValue(settings.sip.auto_answer_interval)
if 'video.device' in notification.data.modified: if 'video.device' in notification.data.modified:
self.video_camera_button.setCurrentIndex(self.video_camera_button.findData(settings.video.device)) self.video_camera_button.setCurrentIndex(self.video_camera_button.findData(settings.video.device))
elif notification.sender is self.selected_account is not None: elif notification.sender is self.selected_account is not None:
account = notification.sender account = notification.sender
if 'sip.auto_answer' in notification.data.modified: if 'sip.auto_answer' in notification.data.modified:
self.account_auto_answer.setChecked(account.sip.auto_answer) self.account_auto_answer.setChecked(account.sip.auto_answer)
if 'enabled' in notification.data.modified: if 'enabled' in notification.data.modified:
self.account_enabled_button.setChecked(account.enabled) self.account_enabled_button.setChecked(account.enabled)
if not account.enabled: if not account.enabled:
......
...@@ -23,6 +23,7 @@ from sipsimple.threading import run_in_thread ...@@ -23,6 +23,7 @@ from sipsimple.threading import run_in_thread
from blink.configuration.settings import BlinkSettings from blink.configuration.settings import BlinkSettings
from blink.resources import Resources from blink.resources import Resources
from blink.screensharing.vncclient import ServerDefault, TrueColor, HighColor, LowColor from blink.screensharing.vncclient import ServerDefault, TrueColor, HighColor, LowColor
from blink.util import translate
__all__ = ['ScreensharingWindow', 'VNCViewer'] __all__ = ['ScreensharingWindow', 'VNCViewer']
...@@ -401,7 +402,7 @@ class ScreensharingDialog(base_class, ui_class): ...@@ -401,7 +402,7 @@ class ScreensharingDialog(base_class, ui_class):
return False return False
def get_credentials(self): def get_credentials(self):
self.message_label.setText('Screen sharing requires authentication') self.message_label.setText(translate('vnc_viewer', 'Screen sharing requires authentication'))
self.username_label.show() self.username_label.show()
self.username_editor.show() self.username_editor.show()
self.username_editor.clear() self.username_editor.clear()
...@@ -413,7 +414,7 @@ class ScreensharingDialog(base_class, ui_class): ...@@ -413,7 +414,7 @@ class ScreensharingDialog(base_class, ui_class):
return (self.username_editor.text(), self.password_editor.text()) if result == self.Accepted else (None, None) return (self.username_editor.text(), self.password_editor.text()) if result == self.Accepted else (None, None)
def get_password(self): def get_password(self):
self.message_label.setText('Screen sharing requires a password') self.message_label.setText(translate('vnc_viewer', 'Screen sharing requires a password'))
self.username_label.hide() self.username_label.hide()
self.username_editor.hide() self.username_editor.hide()
self.username_editor.clear() self.username_editor.clear()
...@@ -493,7 +494,7 @@ class ScreensharingToolbox(base_class, ui_class): ...@@ -493,7 +494,7 @@ class ScreensharingToolbox(base_class, ui_class):
self.close_button.setDefaultAction(self.close_action) self.close_button.setDefaultAction(self.close_action)
self.color_depth_button.clear() self.color_depth_button.clear()
self.color_depth_button.addItem('Default Color Depth', ServerDefault) self.color_depth_button.addItem(translate('vnc_viewer', 'Default Color Depth'), ServerDefault)
self.color_depth_button.addItem('TrueColor (24 bits)', TrueColor) self.color_depth_button.addItem('TrueColor (24 bits)', TrueColor)
self.color_depth_button.addItem('HighColor (16 bits)', HighColor) self.color_depth_button.addItem('HighColor (16 bits)', HighColor)
self.color_depth_button.addItem('LowColor (8 bits)', LowColor) self.color_depth_button.addItem('LowColor (8 bits)', LowColor)
...@@ -593,13 +594,13 @@ class ScreensharingWindow(base_class, ui_class): ...@@ -593,13 +594,13 @@ class ScreensharingWindow(base_class, ui_class):
self.fullscreen_button.setDefaultAction(self.fullscreen_action) self.fullscreen_button.setDefaultAction(self.fullscreen_action)
self.color_depth_button.clear() self.color_depth_button.clear()
self.color_depth_button.addItem('Default Color Depth', ServerDefault) self.color_depth_button.addItem(translate('vnc_viewer', 'Default Color Depth'), ServerDefault)
self.color_depth_button.addItem('TrueColor (24 bits)', TrueColor) self.color_depth_button.addItem('TrueColor (24 bits)', TrueColor)
self.color_depth_button.addItem('HighColor (16 bits)', HighColor) self.color_depth_button.addItem('HighColor (16 bits)', HighColor)
self.color_depth_button.addItem('LowColor (8 bits)', LowColor) self.color_depth_button.addItem('LowColor (8 bits)', LowColor)
self.screenshot_button_menu = QMenu(self) self.screenshot_button_menu = QMenu(self)
self.screenshot_button_menu.addAction('Open screenshots folder', self._SH_ScreenshotsFolderActionTriggered) self.screenshot_button_menu.addAction(translate('vnc_viewer', 'Open screenshots folder'), self._SH_ScreenshotsFolderActionTriggered)
def closeEvent(self, event): def closeEvent(self, event):
super(ScreensharingWindow, self).closeEvent(event) super(ScreensharingWindow, self).closeEvent(event)
......
...@@ -46,7 +46,7 @@ from sipsimple.threading import run_in_thread, run_in_twisted_thread ...@@ -46,7 +46,7 @@ from sipsimple.threading import run_in_thread, run_in_twisted_thread
from blink.configuration.settings import BlinkSettings from blink.configuration.settings import BlinkSettings
from blink.resources import ApplicationData, Resources from blink.resources import ApplicationData, Resources
from blink.screensharing import ScreensharingWindow, VNCClient, ServerDefault from blink.screensharing import ScreensharingWindow, VNCClient, ServerDefault
from blink.util import call_later, run_in_gui_thread from blink.util import call_later, run_in_gui_thread, translate
from blink.widgets.buttons import LeftSegment, MiddleSegment, RightSegment from blink.widgets.buttons import LeftSegment, MiddleSegment, RightSegment
from blink.widgets.labels import Status from blink.widgets.labels import Status
from blink.widgets.color import ColorHelperMixin, ColorUtils, cache_result, background_color_key from blink.widgets.color import ColorHelperMixin, ColorUtils, cache_result, background_color_key
...@@ -1275,7 +1275,7 @@ class SMPVerification(Enum): ...@@ -1275,7 +1275,7 @@ class SMPVerification(Enum):
@implementer(IObserver) @implementer(IObserver)
class SMPVerificationHandler(object): class SMPVerificationHandler(object):
question = 'What is the ZRTP authentication string?'.encode('utf-8') question = translate('zrtp_widget', 'What is the ZRTP authentication string?').encode('utf-8')
def __init__(self, blink_session): def __init__(self, blink_session):
"""@type blink_session: BlinkSession""" """@type blink_session: BlinkSession"""
...@@ -1874,9 +1874,9 @@ class DraggedAudioSessionWidget(base_class, ui_class): ...@@ -1874,9 +1874,9 @@ class DraggedAudioSessionWidget(base_class, ui_class):
self.address_label.setText(session_widget.address_label.text()) self.address_label.setText(session_widget.address_label.text())
if self.in_conference: if self.in_conference:
self.note_label.setText('Drop outside the conference to detach') self.note_label.setText(translate('sessions', 'Drop outside the conference to detach'))
else: else:
self.note_label.setText('<p><b>Drop</b>:&nbsp;Conference&nbsp; <b>Alt+Drop</b>:&nbsp;Transfer</p>') self.note_label.setText(translate('sessions', '<p><b>Drop</b>:&nbsp;Conference&nbsp; <b>Alt+Drop</b>:&nbsp;Transfer</p>'))
def paintEvent(self, event): def paintEvent(self, event):
painter = QPainter(self) painter = QPainter(self)
...@@ -1949,11 +1949,11 @@ class AudioSessionItem(object): ...@@ -1949,11 +1949,11 @@ class AudioSessionItem(object):
def __unicode__(self): def __unicode__(self):
if self.status is not None: if self.status is not None:
return '{0.type} call with {0.name} ({0.status})'.format(self) return translate('sessions', '{0.type} call with {0.name} ({0.status})').format(self)
elif self.codec_info: elif self.codec_info:
return '{0.type} call with {0.name} using {0.codec_info} ({0.duration!s})'.format(self) return translate('sessions', '{0.type} call with {0.name} using {0.codec_info} ({0.duration!s})').format(self)
else: else:
return '{0.type} call with {0.name}'.format(self) return translate('sessions', '{0.type} call with {0.name}').format(self)
@property @property
def audio_stream(self): def audio_stream(self):
...@@ -2172,30 +2172,30 @@ class AudioSessionItem(object): ...@@ -2172,30 +2172,30 @@ class AudioSessionItem(object):
def _NH_BlinkSessionConnectionProgress(self, notification): def _NH_BlinkSessionConnectionProgress(self, notification):
stage = notification.data.stage stage = notification.data.stage
if stage == 'initializing': if stage == 'initializing':
self.status = Status('Initializing...') self.status = Status(translate('sessions', 'Initializing...'))
elif stage == 'connecting/dns_lookup': elif stage == 'connecting/dns_lookup':
self.status = Status('Looking up destination...') self.status = Status(translate('sessions', 'Looking up destination...'))
elif stage == 'connecting' and self.blink_session.routes: elif stage == 'connecting' and self.blink_session.routes:
self.tls = self.blink_session.transport == 'tls' self.tls = self.blink_session.transport == 'tls'
uri = self.blink_session.routes[0].uri uri = self.blink_session.routes[0].uri
destination = '%s:%s' % (self.blink_session.transport, uri.host.decode()) destination = '%s:%s' % (self.blink_session.transport, uri.host.decode())
self.status = Status('Trying %s' % destination) self.status = Status(translate('sessions', 'Trying %s') % destination)
elif stage == 'ringing': elif stage == 'ringing':
self.status = Status('Ringing...') self.status = Status(translate('sessions', 'Ringing...'))
elif stage == 'starting': elif stage == 'starting':
self.status = Status('Starting media...') self.status = Status(translate('sessions', 'Starting media...'))
else: else:
self.status = None self.status = None
def _NH_BlinkSessionInfoUpdated(self, notification): def _NH_BlinkSessionInfoUpdated(self, notification):
if 'media' in notification.data.elements: if 'media' in notification.data.elements:
audio_info = self.blink_session.info.streams.audio audio_info = self.blink_session.info.streams.audio
self.type = 'HD Audio' if audio_info.sample_rate and audio_info.sample_rate >= 16000 else 'Audio' self.type = translate('sessions', 'HD Audio') if audio_info.sample_rate and audio_info.sample_rate >= 16000 else translate('sessions', 'Audio')
self.codec_info = audio_info.codec self.codec_info = audio_info.codec
if audio_info.encryption is not None: if audio_info.encryption is not None:
self.widget.srtp_label.setToolTip('Media is encrypted using %s (%s)' % (audio_info.encryption, audio_info.encryption_cipher)) self.widget.srtp_label.setToolTip(translate('sessions', 'Media is encrypted using %s (%s)') % (audio_info.encryption, audio_info.encryption_cipher))
else: else:
self.widget.srtp_label.setToolTip('Media is not encrypted') self.widget.srtp_label.setToolTip(translate('sessions', 'Media is not encrypted'))
self.widget.update_rtp_encryption_icon() self.widget.update_rtp_encryption_icon()
self.srtp = audio_info.encryption is not None self.srtp = audio_info.encryption is not None
if 'statistics' in notification.data.elements: if 'statistics' in notification.data.elements:
...@@ -2206,9 +2206,9 @@ class AudioSessionItem(object): ...@@ -2206,9 +2206,9 @@ class AudioSessionItem(object):
self.widget.hold_button.setChecked(notification.data.local_hold) self.widget.hold_button.setChecked(notification.data.local_hold)
if self.blink_session.state == 'connected': if self.blink_session.state == 'connected':
if notification.data.local_hold: if notification.data.local_hold:
self.status = Status('On hold', color='#000090') self.status = Status(translate('sessions', 'On hold'), color='#000090')
elif notification.data.remote_hold: elif notification.data.remote_hold:
self.status = Status('Hold by remote', color='#000090') self.status = Status(translate('sessions', 'Hold by remote'), color='#000090')
else: else:
self.status = None self.status = None
...@@ -2226,7 +2226,7 @@ class AudioSessionItem(object): ...@@ -2226,7 +2226,7 @@ class AudioSessionItem(object):
self.status = Status('Connected') self.status = Status('Connected')
call_later(3, self._reset_status, self.status) # reset status 3 seconds later if it hasn't changed until then call_later(3, self._reset_status, self.status) # reset status 3 seconds later if it hasn't changed until then
else: else:
self.status = Status('Audio refused', color='#900000') self.status = Status(translate('sessions', 'Audio refused'), color='#900000')
self._cleanup() self._cleanup()
def _NH_BlinkSessionDidAddStream(self, notification): def _NH_BlinkSessionDidAddStream(self, notification):
...@@ -2240,7 +2240,7 @@ class AudioSessionItem(object): ...@@ -2240,7 +2240,7 @@ class AudioSessionItem(object):
def _NH_BlinkSessionDidNotAddStream(self, notification): def _NH_BlinkSessionDidNotAddStream(self, notification):
if notification.data.stream.type == 'audio': if notification.data.stream.type == 'audio':
self.status = Status('Audio refused', color='#900000') # where can we get the reason from? (rejected, cancelled, failed, ...) -Dan self.status = Status(translate('sessions', 'Audio refused'), color='#900000') # where can we get the reason from? (rejected, cancelled, failed, ...) -Dan
self._cleanup() self._cleanup()
def _NH_BlinkSessionWillRemoveStream(self, notification): def _NH_BlinkSessionWillRemoveStream(self, notification):
...@@ -2273,24 +2273,25 @@ class AudioSessionItem(object): ...@@ -2273,24 +2273,25 @@ class AudioSessionItem(object):
def _NH_BlinkSessionTransferNewOutgoing(self, notification): def _NH_BlinkSessionTransferNewOutgoing(self, notification):
self.status_context = 'transfer' self.status_context = 'transfer'
self.status = Status('Transfer: Trying', context='transfer') self.status = Status(translate('sessions', 'Transfer: Trying'), context='transfer')
def _NH_BlinkSessionTransferDidEnd(self, notification): def _NH_BlinkSessionTransferDidEnd(self, notification):
if self.blink_session.transfer_direction == 'outgoing': if self.blink_session.transfer_direction == 'outgoing':
self.status = Status('Transfer: Succeeded', context='transfer') self.status = Status(translate('sessions', 'Transfer: Succeeded'), context='transfer')
def _NH_BlinkSessionTransferDidFail(self, notification): def _NH_BlinkSessionTransferDidFail(self, notification):
if self.blink_session.transfer_direction == 'outgoing': if self.blink_session.transfer_direction == 'outgoing':
# TODO: maybe translate? -Tijmen
reason_map = {403: 'Forbidden', 404: 'Not Found', 408: 'Timeout', 480: 'Unavailable', 486: 'Busy', reason_map = {403: 'Forbidden', 404: 'Not Found', 408: 'Timeout', 480: 'Unavailable', 486: 'Busy',
487: 'Cancelled', 488: 'Not Acceptable', 600: 'Busy', 603: 'Declined'} 487: 'Cancelled', 488: 'Not Acceptable', 600: 'Busy', 603: 'Declined'}
reason = reason_map.get(notification.data.code, 'Failed') reason = reason_map.get(notification.data.code, translate('sessions', 'Failed'))
self.status = Status("Transfer: {}".format(reason), context='transfer') self.status = Status(translate('sessions', "Transfer: {}").format(reason), context='transfer')
call_later(3, self._reset_status, self.status) call_later(3, self._reset_status, self.status)
self.status_context = None self.status_context = None
def _NH_BlinkSessionTransferGotProgress(self, notification): def _NH_BlinkSessionTransferGotProgress(self, notification):
if notification.data.code < 200: # final answers are handled in DidEnd and DiDFail if notification.data.code < 200: # final answers are handled in DidEnd and DiDFail
self.status = Status("Transfer: {}".format(notification.data.reason), context='transfer') self.status = Status(translate('sessions', "Transfer: {}").format(notification.data.reason), context='transfer')
def _NH_MediaStreamWillEnd(self, notification): def _NH_MediaStreamWillEnd(self, notification):
stream = notification.sender stream = notification.sender
...@@ -4121,7 +4122,7 @@ class BlinkFileTransfer(BlinkSessionBase): ...@@ -4121,7 +4122,7 @@ class BlinkFileTransfer(BlinkSessionBase):
if failure_reason is not None: if failure_reason is not None:
end_reason = failure_reason end_reason = failure_reason
else: else:
end_reason = 'Completed (%s)' % FileSizeFormatter.format(self.file_selector.size) end_reason = translate('sessions', 'Completed (%s)') % FileSizeFormatter.format(self.file_selector.size)
state = SessionState('ended') state = SessionState('ended')
state.reason = end_reason state.reason = end_reason
state.error = failure_reason is not None state.error = failure_reason is not None
...@@ -4142,7 +4143,7 @@ class BlinkFileTransfer(BlinkSessionBase): ...@@ -4142,7 +4143,7 @@ class BlinkFileTransfer(BlinkSessionBase):
self.state = 'connecting' self.state = 'connecting'
routes = notification.data.result routes = notification.data.result
if not routes: if not routes:
self._terminate(failure_reason='Destination not found') self._terminate(failure_reason=translate('sessions', 'Destination not found'))
self.routes = None self.routes = None
return return
self.routes = routes self.routes = routes
...@@ -4155,7 +4156,7 @@ class BlinkFileTransfer(BlinkSessionBase): ...@@ -4155,7 +4156,7 @@ class BlinkFileTransfer(BlinkSessionBase):
notification.center.remove_observer(self, sender=notification.sender) notification.center.remove_observer(self, sender=notification.sender)
if self.state in ('ending', 'ended'): if self.state in ('ending', 'ended'):
return return
self._terminate(failure_reason='DNS Lookup failed') self._terminate(failure_reason=translate('sessions', 'DNS Lookup failed'))
def _NH_SIPSessionNewOutgoing(self, notification): def _NH_SIPSessionNewOutgoing(self, notification):
self.state = 'initializing' self.state = 'initializing'
...@@ -4479,17 +4480,17 @@ class FileTransferItem(object): ...@@ -4479,17 +4480,17 @@ class FileTransferItem(object):
def _NH_BlinkFileTransferDidChangeState(self, notification): def _NH_BlinkFileTransferDidChangeState(self, notification):
state = notification.data.new_state state = notification.data.new_state
if state == 'connecting/dns_lookup': if state == 'connecting/dns_lookup':
self.status = 'Looking up destination...' self.status = translate('sessions', 'Looking up destination...')
elif state == 'connecting': elif state == 'connecting':
self.status = 'Connecting...' self.status = translate('sessions', 'Connecting...')
elif state == 'connecting/ringing': elif state == 'connecting/ringing':
self.status = 'Ringing...' self.status = translate('sessions', 'Ringing...')
elif state == 'connecting/starting': elif state == 'connecting/starting':
self.status = 'Starting...' self.status = translate('sessions', 'Starting...')
elif state == 'connected': elif state == 'connected':
self.status = 'Connected' self.status = translate('sessions', 'Connected')
elif state == 'ending': elif state == 'ending':
self.status = 'Ending...' self.status = translate('sessions', 'Ending...')
else: else:
self.status = None self.status = None
self.progress = None self.progress = None
...@@ -4498,7 +4499,7 @@ class FileTransferItem(object): ...@@ -4498,7 +4499,7 @@ class FileTransferItem(object):
def _NH_BlinkFileTransferDidInitialize(self, notification): def _NH_BlinkFileTransferDidInitialize(self, notification):
self.progress = None self.progress = None
self.status = 'Connecting...' self.status = translate('sessions', 'Connecting...')
self.widget.update_content(self) self.widget.update_content(self)
notification.center.post_notification('FileTransferItemDidChange', sender=self) notification.center.post_notification('FileTransferItemDidChange', sender=self)
...@@ -4506,7 +4507,7 @@ class FileTransferItem(object): ...@@ -4506,7 +4507,7 @@ class FileTransferItem(object):
progress = notification.data.progress progress = notification.data.progress
if self.progress is None or progress > self.progress: if self.progress is None or progress > self.progress:
self.progress = progress self.progress = progress
self.status = 'Computing hash (%s%%)' % notification.data.progress self.status = translate('sessions', 'Computing hash (%s%%)') % notification.data.progress
self.widget.update_content(self) self.widget.update_content(self)
notification.center.post_notification('FileTransferItemDidChange', sender=self) notification.center.post_notification('FileTransferItemDidChange', sender=self)
...@@ -4514,7 +4515,7 @@ class FileTransferItem(object): ...@@ -4514,7 +4515,7 @@ class FileTransferItem(object):
self.bytes = notification.data.bytes self.bytes = notification.data.bytes
self.total_bytes = notification.data.total_bytes self.total_bytes = notification.data.total_bytes
progress = int(self.bytes * 100 / self.total_bytes) progress = int(self.bytes * 100 / self.total_bytes)
status = 'Transferring: %s/%s (%s%%)' % (FileSizeFormatter.format(self.bytes), FileSizeFormatter.format(self.total_bytes), progress) status = translate('sessions', 'Transferring: %s/%s (%s%%)') % (FileSizeFormatter.format(self.bytes), FileSizeFormatter.format(self.total_bytes), progress)
if self.progress is None or progress > self.progress or status != self.status: if self.progress is None or progress > self.progress or status != self.status:
self.progress = progress self.progress = progress
self.status = status self.status = status
...@@ -5233,7 +5234,7 @@ class IncomingDialog(IncomingDialogBase, ui_class): ...@@ -5233,7 +5234,7 @@ class IncomingDialog(IncomingDialogBase, ui_class):
self.reject_button.released.connect(self._set_reject_mode) self.reject_button.released.connect(self._set_reject_mode)
self.screensharing_stream.hidden.connect(self.screensharing_label.hide) self.screensharing_stream.hidden.connect(self.screensharing_label.hide)
self.screensharing_stream.shown.connect(self.screensharing_label.show) self.screensharing_stream.shown.connect(self.screensharing_label.show)
self.auto_answer_label.setText('Auto-answer is inactive') self.auto_answer_label.setText(translate('incoming_dialog', 'Auto-answer is inactive'))
self.auto_answer_interval = None self.auto_answer_interval = None
self._auto_answer_timer = None self._auto_answer_timer = None
self.passed_time = 0 self.passed_time = 0
...@@ -5269,12 +5270,12 @@ class IncomingDialog(IncomingDialogBase, ui_class): ...@@ -5269,12 +5270,12 @@ class IncomingDialog(IncomingDialogBase, ui_class):
self._auto_answer_timer.setInterval(1000) self._auto_answer_timer.setInterval(1000)
self._auto_answer_timer.timeout.connect(self._update_auto_answer) self._auto_answer_timer.timeout.connect(self._update_auto_answer)
self._auto_answer_timer.start() self._auto_answer_timer.start()
self.auto_answer_label.setText('Auto answer in %d seconds' % interval) self.auto_answer_label.setText(translate('incoming_dialog', 'Auto answer in %d seconds') % interval)
def _update_auto_answer(self): def _update_auto_answer(self):
self.passed_time = self.passed_time + 1 self.passed_time = self.passed_time + 1
remaining_time = self.auto_answer_interval - self.passed_time remaining_time = self.auto_answer_interval - self.passed_time
self.auto_answer_label.setText('Auto answer in %d seconds' % remaining_time) self.auto_answer_label.setText(translate('incoming_dialog', 'Auto answer in %d seconds') % remaining_time)
if remaining_time == 0: if remaining_time == 0:
self._auto_answer_timer.stop() self._auto_answer_timer.stop()
self.hide() self.hide()
...@@ -5285,20 +5286,20 @@ class IncomingDialog(IncomingDialogBase, ui_class): ...@@ -5285,20 +5286,20 @@ class IncomingDialog(IncomingDialogBase, ui_class):
self.chat_stream.active = True self.chat_stream.active = True
self.screensharing_stream.active = True self.screensharing_stream.active = True
self.video_stream.active = True self.video_stream.active = True
self.note_label.setText('To refuse a media type click its icon') self.note_label.setText(translate('incoming_dialog', 'To refuse a media type click its icon'))
else: else:
self.audio_stream.active = False self.audio_stream.active = False
self.chat_stream.active = False self.chat_stream.active = False
self.screensharing_stream.active = False self.screensharing_stream.active = False
self.video_stream.active = False self.video_stream.active = False
if self.audio_stream.in_use: if self.audio_stream.in_use:
self.note_label.setText('Audio call') self.note_label.setText(translate('incoming_dialog', 'Audio call'))
elif self.chat_stream.in_use: elif self.chat_stream.in_use:
self.note_label.setText('Chat session') self.note_label.setText(translate('incoming_dialog', 'Chat session'))
elif self.video_stream.in_use: elif self.video_stream.in_use:
self.note_label.setText('Video call') self.note_label.setText(translate('incoming_dialog', 'Video call'))
elif self.screensharing_stream.in_use: elif self.screensharing_stream.in_use:
self.note_label.setText('Screen sharing request') self.note_label.setText(translate('incoming_dialog', 'Screen sharing request'))
else: else:
self.note_label.setText('') self.note_label.setText('')
self._update_accept_button() self._update_accept_button()
...@@ -5326,10 +5327,10 @@ class IncomingRequest(QObject): ...@@ -5326,10 +5327,10 @@ class IncomingRequest(QObject):
self._auto_answer_timer = None self._auto_answer_timer = None
if proposal: if proposal:
self.dialog.setWindowTitle('Incoming Session Update') self.dialog.setWindowTitle(translate('incoming_dialog', 'Incoming Session Update'))
self.dialog.busy_button.hide() self.dialog.busy_button.hide()
else: else:
self.dialog.setWindowTitle('Incoming Session Request') self.dialog.setWindowTitle(translate('incoming_dialog', 'Incoming Session Request'))
address = '%s@%s' % (session.remote_identity.uri.user, session.remote_identity.uri.host) address = '%s@%s' % (session.remote_identity.uri.user, session.remote_identity.uri.host)
self.dialog.uri_label.setText(address) self.dialog.uri_label.setText(address)
self.dialog.username_label.setText(contact.name or session.remote_identity.display_name or address) self.dialog.username_label.setText(contact.name or session.remote_identity.display_name or address)
...@@ -5360,14 +5361,14 @@ class IncomingRequest(QObject): ...@@ -5360,14 +5361,14 @@ class IncomingRequest(QObject):
self.dialog.screensharing_stream.setVisible(self.screensharing_stream is not None) self.dialog.screensharing_stream.setVisible(self.screensharing_stream is not None)
if self.screensharing_stream is not None: if self.screensharing_stream is not None:
if self.screensharing_stream.handler.type == 'active': if self.screensharing_stream.handler.type == 'active':
self.dialog.screensharing_label.setText('is offering screen sharing') self.dialog.screensharing_label.setText(translate('incoming_dialog', 'is offering screen sharing'))
else: else:
self.dialog.screensharing_label.setText('is asking to share your screen') self.dialog.screensharing_label.setText(translate('incoming_dialog', 'is asking to share your screen'))
# self.dialog.screensharing_stream.accepted = bool(proposal) # self.dialog.screensharing_stream.accepted = bool(proposal)
self.dialog.finished.connect(self._SH_DialogFinished) self.dialog.finished.connect(self._SH_DialogFinished)
def __eq__(self, other): def __eq__(self, other):
return self is other return self is other
...@@ -5472,6 +5473,7 @@ class IncomingFileTransferDialog(IncomingDialogBase, ui_class): ...@@ -5472,6 +5473,7 @@ class IncomingFileTransferDialog(IncomingDialogBase, ui_class):
def _set_reject_mode(self): def _set_reject_mode(self):
self.reject_mode = 'reject' self.reject_mode = 'reject'
del ui_class, base_class del ui_class, base_class
...@@ -5497,9 +5499,9 @@ class IncomingFileTransferRequest(QObject): ...@@ -5497,9 +5499,9 @@ class IncomingFileTransferRequest(QObject):
filename = os.path.basename(self.stream.file_selector.name) filename = os.path.basename(self.stream.file_selector.name)
size = self.stream.file_selector.size size = self.stream.file_selector.size
if size: if size:
self.dialog.file_label.setText('File: %s (%s)' % (filename, FileSizeFormatter.format(size))) self.dialog.file_label.setText(translate('incoming_filetransfer_dialog', 'File: %s (%s)') % (filename, FileSizeFormatter.format(size)))
else: else:
self.dialog.file_label.setText('File: %s' % filename) self.dialog.file_label.setText(translate('incoming_filetransfer_dialog', 'File: %s') % filename)
self.dialog.finished.connect(self._SH_DialogFinished) self.dialog.finished.connect(self._SH_DialogFinished)
...@@ -5572,7 +5574,7 @@ class IncomingCallTransferRequest(QObject): ...@@ -5572,7 +5574,7 @@ class IncomingCallTransferRequest(QObject):
self.dialog.uri_label.setText(contact_uri.uri) self.dialog.uri_label.setText(contact_uri.uri)
self.dialog.username_label.setText(contact.name) self.dialog.username_label.setText(contact.name)
self.dialog.user_icon.setPixmap(contact.icon.pixmap(48)) self.dialog.user_icon.setPixmap(contact.icon.pixmap(48))
self.dialog.transfer_label.setText('transfer requested by {}'.format(blink_session.contact.name or blink_session.contact_uri.uri)) self.dialog.transfer_label.setText(translate('incoming_calltransfer_dialog', 'transfer requested by {}').format(blink_session.contact.name or blink_session.contact_uri.uri))
self.dialog.finished.connect(self._SH_DialogFinished) self.dialog.finished.connect(self._SH_DialogFinished)
...@@ -5652,6 +5654,7 @@ class ConferenceDialog(base_class, ui_class): ...@@ -5652,6 +5654,7 @@ class ConferenceDialog(base_class, ui_class):
streams.append(StreamDescription('chat')) streams.append(StreamDescription('chat'))
session_manager.create_session(contact, contact_uri, streams, account=account) session_manager.create_session(contact, contact_uri, streams, account=account)
del ui_class, base_class del ui_class, base_class
......
from PyQt5.QtCore import Qt, QLineF, QPointF, QRectF, QSize, QTimer, pyqtSignal from PyQt5.QtCore import Qt, QCoreApplication, QLineF, QPointF, QRectF, QSize, QTimer, pyqtSignal, QT_TRANSLATE_NOOP
from PyQt5.QtGui import QBrush, QColor, QLinearGradient, QIcon, QPainter, QPainterPath, QPalette, QPen, QPixmap, QPolygonF from PyQt5.QtGui import QBrush, QColor, QLinearGradient, QIcon, QPainter, QPainterPath, QPalette, QPen, QPixmap, QPolygonF
from PyQt5.QtWidgets import QAction, QCommonStyle, QMenu, QPushButton, QStyle, QStyleOptionToolButton, QStylePainter, QToolButton from PyQt5.QtWidgets import QAction, QCommonStyle, QMenu, QPushButton, QStyle, QStyleOptionToolButton, QStylePainter, QToolButton
...@@ -10,6 +10,8 @@ from blink.widgets.color import ColorScheme, ColorUtils, ColorHelperMixin ...@@ -10,6 +10,8 @@ from blink.widgets.color import ColorScheme, ColorUtils, ColorHelperMixin
__all__ = ['ToolButton', 'ConferenceButton', 'StreamButton', 'SegmentButton', 'SingleSegment', 'LeftSegment', 'MiddleSegment', 'RightSegment', __all__ = ['ToolButton', 'ConferenceButton', 'StreamButton', 'SegmentButton', 'SingleSegment', 'LeftSegment', 'MiddleSegment', 'RightSegment',
'RecordButton', 'SwitchViewButton', 'StateButton', 'AccountState'] 'RecordButton', 'SwitchViewButton', 'StateButton', 'AccountState']
translate = QCoreApplication.translate
class ToolButton(QToolButton): class ToolButton(QToolButton):
"""A custom QToolButton that doesn't show a menu indicator arrow""" """A custom QToolButton that doesn't show a menu indicator arrow"""
...@@ -28,8 +30,8 @@ class ConferenceButton(ToolButton): ...@@ -28,8 +30,8 @@ class ConferenceButton(ToolButton):
def __init__(self, parent=None): def __init__(self, parent=None):
super(ConferenceButton, self).__init__(parent) super(ConferenceButton, self).__init__(parent)
self.make_conference_action = QAction('Conference all single sessions', self, triggered=self.makeConference.emit) self.make_conference_action = QAction(translate('conference_button', 'Conference all single sessions'), self, triggered=self.makeConference.emit)
self.break_conference_action = QAction('Break selected conference', self, triggered=self.breakConference.emit) self.break_conference_action = QAction(translate('conference_button', 'Break selected conference'), self, triggered=self.breakConference.emit)
self.toggled.connect(self._SH_Toggled) self.toggled.connect(self._SH_Toggled)
self.addAction(self.make_conference_action) self.addAction(self.make_conference_action)
...@@ -259,8 +261,8 @@ class SwitchViewButton(QPushButton): ...@@ -259,8 +261,8 @@ class SwitchViewButton(QPushButton):
viewChanged = pyqtSignal(int) viewChanged = pyqtSignal(int)
button_text = {ContactView: 'Switch to Calls', SessionView: 'Switch to Contacts'} button_text = {ContactView: QT_TRANSLATE_NOOP('switch_view_button', 'Switch to Calls'), SessionView: QT_TRANSLATE_NOOP('switch_view_button', 'Switch to Contacts')}
button_dnd_text = {ContactView: 'Drag here to add to a conference', SessionView: 'Drag here to go back to contacts'} button_dnd_text = {ContactView: QT_TRANSLATE_NOOP('switch_view_button', 'Drag here to add to a conference'), SessionView: QT_TRANSLATE_NOOP('switch_view_button', 'Drag here to go back to contacts')}
dnd_style_sheet1 = """ dnd_style_sheet1 = """
QPushButton { QPushButton {
...@@ -307,7 +309,7 @@ class SwitchViewButton(QPushButton): ...@@ -307,7 +309,7 @@ class SwitchViewButton(QPushButton):
text = self.button_dnd_text[value] text = self.button_dnd_text[value]
else: else:
text = self.button_text[value] text = self.button_text[value]
self.setText(text) self.setText(translate('switch_view_button', text))
self.viewChanged.emit(value) self.viewChanged.emit(value)
view = property(_get_view, _set_view) view = property(_get_view, _set_view)
...@@ -324,11 +326,11 @@ class SwitchViewButton(QPushButton): ...@@ -324,11 +326,11 @@ class SwitchViewButton(QPushButton):
self.dnd_timer.phase = 0 self.dnd_timer.phase = 0
self.original_height = self.height() self.original_height = self.height()
self.setStyleSheet(self.dnd_style_sheet1) self.setStyleSheet(self.dnd_style_sheet1)
self.setText(self.button_dnd_text[self.view]) self.setText(translate('switch_view_button', self.button_dnd_text[self.view]))
self.setFixedHeight(40) self.setFixedHeight(40)
else: else:
self.setStyleSheet('') self.setStyleSheet('')
self.setText(self.button_text[self.view]) self.setText(translate('switch_view_button', self.button_text[self.view]))
self.setFixedHeight(self.original_height) self.setFixedHeight(self.original_height)
dnd_active = property(_get_dnd_active, _set_dnd_active) dnd_active = property(_get_dnd_active, _set_dnd_active)
...@@ -662,10 +664,10 @@ class PresenceState(object): ...@@ -662,10 +664,10 @@ class PresenceState(object):
class AccountState(StateButton): class AccountState(StateButton):
Invisible = PresenceState('Invisible', '#efedeb', Resources.get('icons/state-invisible.svg')) Invisible = PresenceState(QT_TRANSLATE_NOOP('presence_state', 'Invisible'), '#efedeb', Resources.get('icons/state-invisible.svg'))
Available = PresenceState('Available', '#00ff00', Resources.get('icons/state-available.svg')) Available = PresenceState(QT_TRANSLATE_NOOP('presence_state', 'Available'), '#00ff00', Resources.get('icons/state-available.svg'))
Away = PresenceState('Away', '#ffff00', Resources.get('icons/state-away.svg')) Away = PresenceState(QT_TRANSLATE_NOOP('presence_state', 'Away'), '#ffff00', Resources.get('icons/state-away.svg'))
Busy = PresenceState('Busy', '#ff0000', Resources.get('icons/state-busy.svg')) Busy = PresenceState(QT_TRANSLATE_NOOP('presence_state', 'Busy'), '#ff0000', Resources.get('icons/state-busy.svg'))
stateChanged = pyqtSignal() stateChanged = pyqtSignal()
...@@ -675,7 +677,7 @@ class AccountState(StateButton): ...@@ -675,7 +677,7 @@ class AccountState(StateButton):
super(AccountState, self).__init__(parent) super(AccountState, self).__init__(parent)
menu = QMenu(self) menu = QMenu(self)
for state in (self.Available, self.Away, self.Busy, self.Invisible): for state in (self.Available, self.Away, self.Busy, self.Invisible):
action = menu.addAction(QIcon(state.icon), state.name) action = menu.addAction(QIcon(state.icon), translate('presence_state', state.name))
action.state = state action.state = state
action.note = None action.note = None
menu.addSeparator() menu.addSeparator()
......
...@@ -11,6 +11,7 @@ from application.python.types import MarkerType ...@@ -11,6 +11,7 @@ from application.python.types import MarkerType
from sipsimple.configuration.datatypes import Path from sipsimple.configuration.datatypes import Path
from blink.resources import IconManager from blink.resources import IconManager
from blink.util import translate
from blink.widgets.color import ColorHelperMixin from blink.widgets.color import ColorHelperMixin
from blink.widgets.util import QtDynamicProperty, ContextMenuActions from blink.widgets.util import QtDynamicProperty, ContextMenuActions
...@@ -27,8 +28,8 @@ class IconSelector(QLabel): ...@@ -27,8 +28,8 @@ class IconSelector(QLabel):
def __init__(self, parent=None): def __init__(self, parent=None):
super(IconSelector, self).__init__(parent) super(IconSelector, self).__init__(parent)
self.actions = ContextMenuActions() self.actions = ContextMenuActions()
self.actions.select_icon = QAction('Select icon...', self, triggered=self._SH_ChangeIconActionTriggered) self.actions.select_icon = QAction(translate('icon_selector', 'Select icon...'), self, triggered=self._SH_ChangeIconActionTriggered)
self.actions.remove_icon = QAction('Use contact provided icon', self, triggered=self._SH_RemoveIconActionTriggered) self.actions.remove_icon = QAction(translate('icon_selector', 'Use contact provided icon'), self, triggered=self._SH_RemoveIconActionTriggered)
self.icon_size = 48 self.icon_size = 48
self.default_icon = None self.default_icon = None
self.contact_icon = None self.contact_icon = None
...@@ -107,7 +108,7 @@ class IconSelector(QLabel): ...@@ -107,7 +108,7 @@ class IconSelector(QLabel):
super(IconSelector, self).mouseReleaseEvent(event) super(IconSelector, self).mouseReleaseEvent(event)
def _SH_ChangeIconActionTriggered(self): def _SH_ChangeIconActionTriggered(self):
filename = QFileDialog.getOpenFileName(self, 'Select Icon', self.last_icon_directory, "Images (*.png *.tiff *.jpg *.xmp *.svg)")[0] filename = QFileDialog.getOpenFileName(self, translate('icon_selector', 'Select Icon'), self.last_icon_directory, "Images (*.png *.tiff *.jpg *.xmp *.svg)")[0]
if filename: if filename:
self.filename = filename self.filename = filename
......
...@@ -6,6 +6,7 @@ from PyQt5.QtGui import QPainter, QPalette, QPixmap ...@@ -6,6 +6,7 @@ from PyQt5.QtGui import QPainter, QPalette, QPixmap
from PyQt5.QtWidgets import QAbstractButton, QLineEdit, QBoxLayout, QHBoxLayout, QLabel, QLayout, QSizePolicy, QSpacerItem, QStyle, QStyleOptionFrame, QWidget from PyQt5.QtWidgets import QAbstractButton, QLineEdit, QBoxLayout, QHBoxLayout, QLabel, QLayout, QSizePolicy, QSpacerItem, QStyle, QStyleOptionFrame, QWidget
from blink.resources import Resources from blink.resources import Resources
from blink.util import translate
from blink.widgets.util import QtDynamicProperty from blink.widgets.util import QtDynamicProperty
...@@ -274,7 +275,7 @@ class SearchBox(LineEdit): ...@@ -274,7 +275,7 @@ class SearchBox(LineEdit):
self.clear_button.hide() self.clear_button.hide()
self.clear_button.clicked.connect(self.clear) self.clear_button.clicked.connect(self.clear)
self.textChanged.connect(self._SH_TextChanged) self.textChanged.connect(self._SH_TextChanged)
self.inactiveText = "Search" self.inactiveText = translate('search_box', "Search")
def keyPressEvent(self, event): def keyPressEvent(self, event):
if event.key() == Qt.Key_Escape: if event.key() == Qt.Key_Escape:
......
...@@ -6,6 +6,7 @@ from PyQt5.QtCore import Qt, pyqtSignal ...@@ -6,6 +6,7 @@ from PyQt5.QtCore import Qt, pyqtSignal
from PyQt5.QtWidgets import QStyle, QStyleOption, QStylePainter from PyQt5.QtWidgets import QStyle, QStyleOption, QStylePainter
from blink.resources import Resources from blink.resources import Resources
from blink.util import translate
from blink.sessions import SMPVerification from blink.sessions import SMPVerification
...@@ -56,7 +57,7 @@ class OTRWidget(base_class, ui_class): ...@@ -56,7 +57,7 @@ class OTRWidget(base_class, ui_class):
@peer_verified.setter @peer_verified.setter
def peer_verified(self, verified): def peer_verified(self, verified):
self.__dict__['peer_verified'] = verified self.__dict__['peer_verified'] = verified
self.validate_button.setText('Invalidate' if verified else 'Validate') self.validate_button.setText(translate('otr_widget', 'Invalidate') if verified else translate('otr_widget', 'Validate'))
self.validate_button.setChecked(verified) self.validate_button.setChecked(verified)
self.validate_button.setEnabled(verified or self.verification_stack.currentWidget() is not self.smp_panel or self.smp_status is SMPVerification.Succeeded) self.validate_button.setEnabled(verified or self.verification_stack.currentWidget() is not self.smp_panel or self.smp_status is SMPVerification.Succeeded)
self.peer_fingerprint_value.setStyleSheet('QLabel {{ color: {}; }}'.format(self.color_table['green'] if verified else self.color_table['orange'])) self.peer_fingerprint_value.setStyleSheet('QLabel {{ color: {}; }}'.format(self.color_table['green'] if verified else self.color_table['orange']))
...@@ -93,11 +94,11 @@ class OTRWidget(base_class, ui_class): ...@@ -93,11 +94,11 @@ class OTRWidget(base_class, ui_class):
@property @property
def smp_status_text(self): def smp_status_text(self):
if self.peer_verified: if self.peer_verified:
return '<span style="color: {[green]};">Verified</span>'.format(self.color_table) return translate('otr_widget', '<span style="color: {[green]};">Verified</span>').format(self.color_table)
elif self.smp_status is SMPVerification.Succeeded: elif self.smp_status is SMPVerification.Succeeded:
return '<span style="color: {[green]};">Succeeded</span>'.format(self.color_table) return translate('otr_widget', '<span style="color: {[green]};">Succeeded</span>').format(self.color_table)
elif self.smp_status is SMPVerification.Failed: elif self.smp_status is SMPVerification.Failed:
return '<span style="color: {[orange]};">Failed</span>'.format(self.color_table) return translate('otr_widget', '<span style="color: {[orange]};">Failed</span>').format(self.color_table)
else: else:
return '{}'.format(self.smp_status.value) return '{}'.format(self.smp_status.value)
......
...@@ -4,6 +4,7 @@ from PyQt5.QtCore import Qt, pyqtSignal ...@@ -4,6 +4,7 @@ from PyQt5.QtCore import Qt, pyqtSignal
from PyQt5.QtWidgets import QStyle, QStyleOption, QStylePainter from PyQt5.QtWidgets import QStyle, QStyleOption, QStylePainter
from blink.resources import Resources from blink.resources import Resources
from blink.util import translate
__all__ = ['ZRTPWidget'] __all__ = ['ZRTPWidget']
...@@ -44,10 +45,10 @@ class ZRTPWidget(base_class, ui_class): ...@@ -44,10 +45,10 @@ class ZRTPWidget(base_class, ui_class):
self.__dict__['peer_verified'] = verified self.__dict__['peer_verified'] = verified
if verified: if verified:
self.validate_button.setText('Invalidate') self.validate_button.setText('Invalidate')
self.status_value.setText('<span style="color: hsv(100, 85%, 100%);">Verified</span>') self.status_value.setText(translate('zrtp_widget', '<span style="color: hsv(100, 85%, 100%);">Verified</span>'))
else: else:
self.validate_button.setText('Validate') self.validate_button.setText('Validate')
self.status_value.setText('<span style="color: hsv(20, 85%, 100%);">Not verified</span>') self.status_value.setText(translate('zrtp_widget', '<span style="color: hsv(20, 85%, 100%);">Not verified</span>'))
self.validate_button.setChecked(verified) self.validate_button.setChecked(verified)
peer_verified = property(_get_peer_verified, _set_peer_verified) peer_verified = property(_get_peer_verified, _set_peer_verified)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment