From fb1569184aefdc11ef7a9df236f7221524247d6e Mon Sep 17 00:00:00 2001 From: Muflone Date: Wed, 1 Jul 2009 19:55:38 +0000 Subject: [PATCH] --- DEBIAN/control | 6 +- DialogFileOpenSave.py | 13 +- EspeakFrontend.py | 40 ++- SubprocessWrapper.py | 3 + doc/changelog | 18 + gespeaker.glade | 465 ++++++++++++++------------ gespeaker.py | 2 +- gespeakerUI.py | 283 ++++++++++++---- locale/en_US.po | 180 ++++++++-- locale/en_US/LC_MESSAGES/gespeaker.mo | Bin 1768 -> 3650 bytes locale/fr.po | 184 ++++++++-- locale/fr/LC_MESSAGES/gespeaker.mo | Bin 1825 -> 3910 bytes locale/gespeaker.pot | 172 ++++++++-- locale/it.po | 184 ++++++++-- locale/it/LC_MESSAGES/gespeaker.mo | Bin 1809 -> 3871 bytes 15 files changed, 1143 insertions(+), 407 deletions(-) diff --git a/DEBIAN/control b/DEBIAN/control index 241d1c0..d7704e5 100644 --- a/DEBIAN/control +++ b/DEBIAN/control @@ -1,10 +1,10 @@ Package: gespeaker -Version: 0.4 +Version: 0.5 Section: sound Priority: optional Architecture: all -Depends: espeak, python, python-gtk2, python-gobject, alsa-utils -Installed-Size: 110 +Depends: espeak, espeak-data, python, python-gtk2, python-gobject, alsa-utils | pulseaudio-utils +Installed-Size: 280 Maintainer: Muflone Ubuntu Trucchi Description: A GTK+ frontend for the espeak system Gespeaker is a GTK+ frontend for espeak. It allows to play diff --git a/DialogFileOpenSave.py b/DialogFileOpenSave.py index b7db9c8..cc93c20 100644 --- a/DialogFileOpenSave.py +++ b/DialogFileOpenSave.py @@ -12,7 +12,7 @@ def __init__(self, useForOpen=True, title=None, initialDir=None, initialFile=Non action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons=( gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, - gtk.STOCK_SAVE, gtk.RESPONSE_OK + useForOpen and gtk.STOCK_OPEN or gtk.STOCK_SAVE, gtk.RESPONSE_OK ) ) self.connect('response', self._response_callback) @@ -32,6 +32,17 @@ def _response_callback(self, *args): def show(self): super(self.__class__, self).run() return self.response==gtk.RESPONSE_OK + + def addFilter(self, name, patterns=None, mimetypes=None): + filter = gtk.FileFilter() + filter.set_name(name) + if patterns: + for pattern in patterns: + filter.add_pattern(pattern) + if mimetypes: + for mimetype in mimetypes: + filter.add_mime_type(mimetype) + super(self.__class__, self).add_filter(filter) class DialogFileSave(DialogFileOpenSave): def __init__(self, title=None, initialDir=None, initialFile=None, askOverwrite=True): diff --git a/EspeakFrontend.py b/EspeakFrontend.py index 4bd2d9a..f8dbdfa 100644 --- a/EspeakFrontend.py +++ b/EspeakFrontend.py @@ -4,6 +4,7 @@ ## import SubprocessWrapper +import os class EspeakFrontend(object): def __init__(self): @@ -32,11 +33,20 @@ def pauseOrResume(self, status): else: self.procTalk[1].resume() - def play(self, cmdEspeak, cmdPlayer): + def play(self, cmdEspeak, cmdPlayer, fileToRecord=None): "Play the command provided" + # If save to file has been requested add -w else --stdout + cmdEspeak += fileToRecord and ['-w', fileToRecord] or ['--stdout'] # Execute espeak and pipe it with player - procEspeak = SubprocessWrapper.Popen(cmdEspeak.split(), + print cmdEspeak, cmdPlayer.split() + procEspeak = SubprocessWrapper.Popen(cmdEspeak, stdout=SubprocessWrapper.PIPE) + # Save to file has been requested so we have to wait for espeak end + # and to pipe filename content to the player + if fileToRecord: + procEspeak.wait() + procEspeak = SubprocessWrapper.Popen(['cat', fileToRecord], + stdout=SubprocessWrapper.PIPE) procPlay = SubprocessWrapper.Popen(cmdPlayer.split(), stdin=procEspeak.stdout, stdout=SubprocessWrapper.PIPE, @@ -68,3 +78,29 @@ def loadLanguages(self, cmdEspeak): proc = SubprocessWrapper.Popen((cmdEspeak, '--voices'), stdout=SubprocessWrapper.PIPE) return proc.communicate()[0].split('\n')[1:-1] + + def loadVariants(self, cmdEspeak): + "Load variants list from espeak" + vardir = '/usr/share/espeak-data/voices/!v' + print 'loading variants from %s' % vardir + variantsM = [] + variantsF = [] + # Check if voice variants dir exists + if os.path.exists(vardir) and os.path.isdir(vardir): + # Load files from vardir + for f in os.listdir(vardir): + # Only files + if os.path.isfile(os.path.join(vardir, f)): + varfile = open(os.path.join(vardir, f), mode='r') + varcontent = varfile.read().split('\n') + varfile.close() + # Check if it's a valid variant + if varcontent[0] == 'language variant' and \ + varcontent[1][:5] == 'name ' and \ + varcontent[2][:7] == 'gender ': + # Check gender + if varcontent[2][7:] == 'female': + variantsF.append((f, varcontent[1][5:])) + else: + variantsM.append((f, varcontent[1][5:])) + return (variantsM, variantsF) diff --git a/SubprocessWrapper.py b/SubprocessWrapper.py index 0194ccf..0195cad 100644 --- a/SubprocessWrapper.py +++ b/SubprocessWrapper.py @@ -49,3 +49,6 @@ def resume(self): return self.process.send_signal(signal) else: return os.kill(self.pid, signal) + + def wait(self): + return self.process.wait() diff --git a/doc/changelog b/doc/changelog index ffd830c..eb96470 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,3 +1,21 @@ +gespeaker (0.5) all; urgency=low + + * Added an exteder separator for settings to allow maximum usage of the + window with the text. + * Added filters for load/save text dialogs. + * Added support for recording the audio track to wave. + * Added a statusbar showing the active record mode. + * Added preferences dialog. + * Added preferences save and reload for welcome message, window size, + voice settings and expander status. + * Added support for audio frontend: ALSA (aplay), PulseAudio (paplay) + and user customized player command, with audio command test. + * Added voice variants by scanning /usr/share/espeak-data/voices/!v + folder for extra voice variants. + * Fixed stock icon for DialogFileOpenSave. + + -- Muflone Fri, 30 Jun 2009 18:48:50 +0100 + gespeaker (0.4) all; urgency=medium * Added SubprocessWrapper.Popen to wrap subprocess.Popen in order to diff --git a/gespeaker.glade b/gespeaker.glade index f1b009f..c7e053b 100644 --- a/gespeaker.glade +++ b/gespeaker.glade @@ -3,10 +3,10 @@ - 400 - + 370 + - + True vertical @@ -91,6 +91,7 @@ gtk-media-pause True + False True True @@ -101,6 +102,7 @@ gtk-stop True + False True True @@ -116,7 +118,6 @@ gtk-media-record True - False True True @@ -131,6 +132,16 @@ + + + gtk-preferences + True + True + True + + + + @@ -214,13 +225,12 @@ - + True - False True True gtk-media-record - + False @@ -256,12 +266,12 @@ - + True 7 vertical - + True vertical @@ -279,7 +289,7 @@ - 50 + 30 True True 1 @@ -294,7 +304,6 @@ True 2 False - Welcome in Gespeaker @@ -308,20 +317,8 @@ - + True - - - True - 0 - 1 - <b>Settings</b> - True - - - 0 - - gtk-media-play @@ -334,6 +331,8 @@ False + False + end 1 @@ -345,7 +344,7 @@ True - + True gtk-media-pause @@ -354,221 +353,265 @@ False False - 2 + end + 0 False + False 3 1 - + True - 6 - 2 - - - True - 0 - 12 - _Language: - True - cboLanguages - - - 1 - 2 - GTK_FILL - GTK_EXPAND - - - - - True - 1 - - - 1 - 2 - 1 - 2 - GTK_EXPAND - 5 - - - - - True - 0 - 12 - Dela_y: - True - hscDelay - - - 5 - 6 - GTK_FILL - - - - - True - 0 - 12 - Spee_d: - True - hscSpeed - - - 4 - 5 - GTK_FILL - - - - - True - 0 - 12 - _Volume: - True - hscVolume - - - 3 - 4 - GTK_FILL - - - - - True - 0 - 12 - P_itch: - True - hscPitch - - - 2 - 3 - GTK_FILL - - - - - True - True - 10 5 100 1 10 0 - 0 - - - 1 - 2 - 5 - 6 - - - - - True - True - discontinuous - 170 80 390 1 10 0 - 0 - - - 1 - 2 - 4 - 5 - - - - - True - True - discontinuous - 100 0 200 1 10 0 - 0 - - - 1 - 2 - 3 - 4 - - - - - True - True - 50 0 99 1 10 0 - 0 - - - 1 - 2 - 2 - 3 - - - - - True - 0 - 12 - Voice: - - - GTK_FILL - GTK_EXPAND - - + True + True + True - + True + 6 + 2 - - _Male + True - True - False + 0 + 12 + _Language: True - True + cboLanguages - 0 + 1 + 2 + GTK_FILL + GTK_EXPAND - - Fem_ale + True - True - False + 1 + + + 1 + 2 + 1 + 2 + GTK_EXPAND + 5 + + + + + True + 0 + 12 + Dela_y: + True + hscDelay + + + 5 + 6 + GTK_FILL + + + + + True + 0 + 12 + Spee_d: True - True - True - radioVoiceMale + hscSpeed + + + 4 + 5 + GTK_FILL + + + + + True + 0 + 12 + _Volume: + True + hscVolume + + + 3 + 4 + GTK_FILL + + + + + True + 0 + 12 + P_itch: + True + hscPitch + + + 2 + 3 + GTK_FILL + + + + + True + True + 10 5 100 1 10 0 + 0 + + + 1 + 2 + 5 + 6 + + + + + True + True + discontinuous + 170 80 390 1 10 0 + 0 - 1 + 1 + 2 + 4 + 5 + + + True + True + discontinuous + 100 0 200 1 10 0 + 0 + + + 1 + 2 + 3 + 4 + + + + + True + True + 50 0 99 1 10 0 + 0 + + + 1 + 2 + 2 + 3 + + + + + True + 0 + 12 + Voice: + + + GTK_FILL + GTK_EXPAND + + + + + True + + + _Male + True + True + False + True + True + + + + 0 + + + + + Fem_ale + True + True + False + True + True + radioVoiceMale + + + + 1 + + + + + True + 0 + 6 + Varia_nt: + True + cboVariants + + + False + 2 + + + + + True + + + 3 + + + + + 1 + 2 + + + + + + + True + <b>Settings</b> + True - 1 - 2 + label_item False + False 2 @@ -577,6 +620,16 @@ 2 + + + True + 2 + + + False + 3 + + diff --git a/gespeaker.py b/gespeaker.py index aa6b9e5..b8c3116 100755 --- a/gespeaker.py +++ b/gespeaker.py @@ -12,7 +12,7 @@ APP_NAME = 'gespeaker' APP_TITLE = 'Gespeaker' -APP_VERSION = '0.4' +APP_VERSION = '0.5' LOCALE_DIR = '/usr/share/locale' if __name__ == '__main__': diff --git a/gespeakerUI.py b/gespeakerUI.py index 6b33748..56b1e46 100644 --- a/gespeakerUI.py +++ b/gespeakerUI.py @@ -7,7 +7,7 @@ import gtk.glade import pygtk import gobject -pygtk.require("2.0") +pygtk.require('2.0') # No more used # import TempfileWrapper @@ -20,26 +20,31 @@ from DialogSimpleMessages import * from DialogAbout import DialogAbout from EspeakFrontend import EspeakFrontend +import PreferencesWindow +import Settings +from pygtkutils import * cmdEspeak = '/usr/bin/espeak' -cmdPlayer = 'aplay' -argsEspeak = '--stdout -a %d -p %d -s %d -g %d -v %s -f %s' +argsEspeak = '-a %v -p %p -s %s -g %d -v %l -f %f' +iconLogo = 'gespeaker.svg' class gespeakerUI(object): def __init__(self, app_name, app_title, app_version): - print 'starting gespeaker' + print 'starting %s' % app_name self.espeak = EspeakFrontend() # Create temporary filename - self.tempFilename = tempfile.mkstemp(prefix='gespeaker')[1] + self.tempFilename = tempfile.mkstemp(prefix=app_name)[1] gladeUI = 'gespeaker.glade' self.app_name = app_name self.app_title = app_title self.app_version = app_version self.timeoutCheck = None + self.recordToFile = None + self.variants = ((), ()) print 'loading interface from %s' % gladeUI self.gladeFile = gtk.glade.XML(fname=gladeUI, domain=self.app_name) # Signals handler - segnali = { + signals = { 'on_imgmenuFileQuit_activate': self.on_imgmenuFileQuit_activate, 'on_imgmenuEditPlay_activate': self.on_imgmenuEditPlay_activate, 'on_imgmenuFileNew_activate': self.on_imgmenuFileNew_activate, @@ -48,16 +53,31 @@ def __init__(self, app_name, app_title, app_version): 'on_imgmenuEditStop_activate': self.on_imgmenuEditStop_activate, 'on_btnPlayStop_toggled': self.on_btnPlayStop_toggled, 'on_btnPause_toggled': self.on_btnPause_toggled, + 'on_tlbRecord_toggled': self.on_tlbRecord_toggled, 'on_imgmenuEditPause_activate': self.on_imgmenuEditPause_activate, + 'on_imgmenuEditRec_activate': self.on_imgmenuEditRec_activate, 'on_imgmenuEditResetSettings_activate': self.on_imgmenuEditResetSettings_activate, - 'on_imgmenuHelpAbout_activate': self.on_imgmenuHelpAbout_activate + 'on_imgmenuHelpAbout_activate': self.on_imgmenuHelpAbout_activate, + 'on_imgmenuEditPreferences_activate': self.on_imgmenuEditPreferences_activate, + 'on_radioVoice_toggled': self.on_radioVoice_toggled } - self.gladeFile.signal_autoconnect(segnali) + self.gladeFile.signal_autoconnect(signals) + # Load user settings + Settings.load() # Load window and controls self.loadControls() + self.loadSettings(True) self.winMain.show() - # Play default message - self.btnPlayStop.set_active(True) + + # Play welcome message if PlayWelcomeText is set + if Settings.get('PlayWelcomeText'): + if Settings.get('UseCustomWelcome'): + # Play customized welcome message + self.txvBuffer.set_text(Settings.get('WelcomeText')) + else: + # Play default welcome message + self.txvBuffer.set_text(Settings.default('WelcomeText')) + self.btnPlayStop.set_active(True) gtk.main() def loadControls(self): @@ -67,9 +87,12 @@ def loadControls(self): gw = self.gladeFile.get_widget self.winMain = gw('winMain') self.winMain.set_title(self.app_title) - self.winMain.set_icon_from_file('gespeaker.svg') - self.winMain.set_focus(gw('txvText')) - self.txvBuffer = gw('txvText').get_buffer() + self.winMain.set_icon_from_file(iconLogo) + + self.txvText = gw('txvText') + self.txvBuffer = self.txvText.get_buffer() + self.winMain.set_focus(self.txvText) + self.expSettings = gw('expSettings') self.hscVolume = gw('hscVolume') self.hscPitch = gw('hscPitch') self.hscSpeed = gw('hscSpeed') @@ -77,37 +100,114 @@ def loadControls(self): self.cboLanguages = gw('cboLanguages') self.radioVoiceMale = gw('radioVoiceMale') self.radioVoiceFemale = gw('radioVoiceFemale') + self.lblVariants = gw('lblVariants') + self.cboVariants = gw('cboVariants') self.imgmenuEditPlay = gw('imgmenuEditPlay') self.imgmenuEditStop = gw('imgmenuEditStop') + self.imgmenuEditRec = gw('imgmenuEditRec') self.tlbStop = gw('tlbStop') self.btnPlayStop = gw('btnPlayStop') self.btnPause = gw('btnPause') + self.tlbRecord = gw('tlbRecord') + self.stbStatus = gw('stbStatus') + self.statusContextId = self.stbStatus.get_context_id(self.app_name) self.imgmenuEditPause = gw('imgmenuEditPause') - # Useful lambda to get txvBuffer's text - self.getText = lambda buffer=self.txvBuffer: buffer.get_text( - buffer.get_start_iter(), buffer.get_end_iter() - ) # Create model for cboLanguages by (language, shortname) - listLanguages = gtk.ListStore(str, str) - self.cboLanguages.set_model(listLanguages) + self.listLanguages = gtk.ListStore(str, str) + self.cboLanguages.set_model(self.listLanguages) cell = gtk.CellRendererText() self.cboLanguages.pack_start(cell, True) self.cboLanguages.add_attribute(cell, 'text', 0) # Load languages list from espeak --voices - self.defaultLanguage = 0 + self.defaultLanguageIndex = 0 + defaultLanguage = _('default language') + if defaultLanguage == 'default language': + defaultLanguage = 'default' for langs in self.espeak.loadLanguages(cmdEspeak): lang = langs[22:52].rsplit(None, 1) - listLanguages.append(lang) - if lang[0] == _('default language'): - self.defaultLanguage = listLanguages.iter_n_children(None) - 1 - # Sets default language - self.cboLanguages.set_active(self.defaultLanguage) - + self.listLanguages.append(lang) + if lang[0] == defaultLanguage: + self.defaultLanguageIndex = self.listLanguages.iter_n_children(None) - 1 + # Prepare sorted model for voice variants + self.listVariants = gtk.ListStore(str, str) + self.listVariants.set_sort_column_id(1, gtk.SORT_ASCENDING) + self.cboVariants.set_model(self.listVariants) + cell = gtk.CellRendererText() + self.cboVariants.pack_start(cell, True) + self.cboVariants.add_attribute(cell, 'text', 1) + # Restore window size + if Settings.get('SaveWindowSize'): + self.winMain.set_default_size( + Settings.get('MainWindowWidth'), + Settings.get('MainWindowHeight') + ) + else: + self.winMain.set_default_size( + Settings.default('MainWindowWidth'), + Settings.default('MainWindowHeight') + ) + self.expSettings.set_expanded(Settings.get('SettingsExpander')) + + def loadSettings(self, loadEverything): + if loadEverything: + # Restore voice settings + self.hscVolume.set_value(Settings.get('VoiceVolume')) + self.hscPitch.set_value(Settings.get('VoicePitch')) + self.hscSpeed.set_value(Settings.get('VoiceSpeed')) + self.hscDelay.set_value(Settings.get('VoiceDelay')) + if Settings.get('VoiceTypeMale'): + self.radioVoiceMale.set_active(True) + else: + self.radioVoiceFemale.set_active(True) + # Sets default language + language = Settings.get('VoiceLanguage') + if language == -1: + language = self.defaultLanguageIndex + self.cboLanguages.set_active(language) + # Load standard settings + self.txvText.set_wrap_mode( + Settings.get('WordWrap') and gtk.WRAP_WORD or gtk.WRAP_NONE) + players = ('aplay', 'paplay', '', Settings.get('PlayCommand')) + self.cmdPlayer = players[Settings.get('PlayMethod')] + # Load voice variants + if Settings.get('LoadVariants'): + self.variants = self.espeak.loadVariants(cmdEspeak) + self.lblVariants.show() + self.cboVariants.show() + else: + self.variants = ((), ()) + self.lblVariants.hide() + self.cboVariants.hide() + # Reload list + voicebutton = Radio_get_active(self.radioVoiceMale.get_group()) + self.on_radioVoice_toggled(voicebutton, None) + def on_imgmenuFileQuit_activate(self, widget, data=None): "Close the program" print 'quitting' if self.tempFilename and os.path.exists(self.tempFilename): os.remove(self.tempFilename) + # Save window size if SaveWindowSize is set + if Settings.get('SaveWindowSize'): + sizes = self.winMain.get_size() + Settings.set('MainWindowWidth', sizes[0]) + Settings.set('MainWindowHeight', sizes[1]) + Settings.set('SettingsExpander', self.expSettings.get_expanded()) + # Save voice settings if SaveVoiceSettings is set + if Settings.get('SaveVoiceSettings'): + Settings.set('VoiceVolume', int(self.hscVolume.get_value())) + Settings.set('VoicePitch', int(self.hscPitch.get_value())) + Settings.set('VoiceSpeed', int(self.hscSpeed.get_value())) + Settings.set('VoiceDelay', int(self.hscDelay.get_value())) + Settings.set('VoiceTypeMale', self.radioVoiceMale.get_active()) + # Save language only if different from defaultLanguageIndex + language = self.cboLanguages.get_active() + if language == self.defaultLanguageIndex: + language = -1 + Settings.set('VoiceLanguage', language) + # Save settings + print 'saving settings' + Settings.save(clearDefaults=True) gtk.main_quit() return 0 @@ -117,12 +217,12 @@ def on_imgmenuEditPlay_activate(self, widget, data=None): def on_imgmenuFileNew_activate(self, widget, data=None): "Clears the whole text" - if self.getText(self.txvBuffer): + if TextBuffer_get_text(self.txvBuffer): dialog = DialogYesNo( message=_('Do you want to delete the current text?'), default_button=gtk.RESPONSE_NO ) - dialog.set_icon_from_file('gespeaker.svg') + dialog.set_icon_from_file(iconLogo) dialog.show() if dialog.responseIsYes(): self.txvBuffer.set_text('') @@ -130,8 +230,12 @@ def on_imgmenuFileNew_activate(self, widget, data=None): def on_imgmenuFileOpen_activate(self, widget, data=None): "Loads an external file" - dialog = DialogFileOpen(title=_('Please select the file to open')) - dialog.set_icon_from_file('gespeaker.svg') + dialog = DialogFileOpen( + title=_('Please select the text file to open'), + initialDir=os.path.expanduser('~')) + dialog.set_icon_from_file(iconLogo) + dialog.addFilter(_('Text files (*.txt)'), ['*.txt'], None) + dialog.addFilter(_('All files'), ['*'], None) if dialog.show(): file = None try: @@ -143,7 +247,7 @@ def on_imgmenuFileOpen_activate(self, widget, data=None): text=_('Error opening the file') + '\n\n%s' % strerror, showOk=True ) - print "unable to load %s (I/O error %s: %s)" % ( + print 'unable to load %s (I/O error %s: %s)' % ( dialog.filename, errno, strerror ) except: @@ -154,21 +258,25 @@ def on_imgmenuFileOpen_activate(self, widget, data=None): def on_imgmenuFileSaveAs_activate(self, widget, data=None): "Saves the whole text in the specified filename" - dialog = DialogFileSave(title=_('Please select where to save the file')) - dialog.set_icon_from_file('gespeaker.svg') + dialog = DialogFileSave( + title=_('Please select where to save the text file'), + initialDir=os.path.expanduser('~')) + dialog.addFilter(_('Text files (*.txt)'), ['*.txt'], None) + dialog.addFilter(_('All files'), ['*'], None) + dialog.set_icon_from_file(iconLogo) if dialog.show(): print 'saving text in %s' % dialog.filename file = None try: file = open(dialog.filename, 'w') - file.write(self.getText(self.txvBuffer)) + file.write(TextBuffer_get_text(self.txvBuffer)) print 'file %s saved' % dialog.filename except IOError, (errno, strerror): ShowDialogError( text=_('Error saving the file') + '\n\n%s' % strerror, showOk=True ) - print "unable to save %s (I/O error %s: %s)" % ( + print 'unable to save %s (I/O error %s: %s)' % ( dialog.filename, errno, strerror ) except: @@ -183,20 +291,21 @@ def on_imgmenuEditResetSettings_activate(self, widget, data=None): message=_('Do you want to reset the default settings?'), default_button=gtk.RESPONSE_NO ) - dialog.set_icon_from_file('gespeaker.svg') + dialog.set_icon_from_file(iconLogo) dialog.show() if dialog.responseIsYes(): - self.hscVolume.set_value(100) - self.hscPitch.set_value(50) - self.hscSpeed.set_value(170) - self.hscDelay.set_value(10) - self.radioVoiceMale.set_active(True) - if self.defaultLanguage: - self.cboLanguages.set_active(self.defaultLanguage) + if self.defaultLanguageIndex: + self.cboLanguages.set_active(self.defaultLanguageIndex) print 'restored default settings' + if os.path.exists(Settings.conffile): + os.remove(Settings.conffile) + print 'removed user settings file: %s' % Settings.conffile + # Reload default settings + Settings.load() + self.loadSettings(True) def on_imgmenuHelpAbout_activate(self, widget, data=None): - "Shows the about dialog" + "Show the about dialog" print 'show about dialog' DialogAbout( name=self.app_title, @@ -208,8 +317,8 @@ def on_imgmenuHelpAbout_activate(self, widget, data=None): website_label='Ubuntu Trucchi', authors=['Muflone '], translation=_('translation'), - logo='gespeaker.svg', - icon='gespeaker.svg' + logo=iconLogo, + icon=iconLogo ) def on_imgmenuEditStop_activate(self, widget, data=None): @@ -220,6 +329,10 @@ def on_imgmenuEditPause_activate(self, widget, data=None): "Press button to pause or continue" self.btnPause.set_active(not self.btnPause.get_active()) + def on_imgmenuEditRec_activate(self, widget, data=None): + "Press button to record or disable recording" + self.tlbRecord.set_active(not self.tlbRecord.get_active()) + def checkIfPlaying(self): "Check if a process is still running" if self.espeak.isPlaying(): @@ -240,9 +353,11 @@ def setStopCheck(self, active): def on_btnPlayStop_toggled(self, widget, data=None): "Play and stop by pressing and releasing the button" - if self.btnPlayStop.get_active(): + if self.btnPlayStop.get_active() and TextBuffer_get_text(self.txvBuffer): # Button active so we have to start to play self.startPlaying() + elif self.btnPlayStop.get_active(): + self.btnPlayStop.set_active(False) else: # If Pause button is active then we have to continue before to kill if self.btnPause.get_active(): @@ -256,7 +371,7 @@ def on_btnPause_toggled(self, widget, data=None): def startPlaying(self): "Play whole text" - self.playText(self.getText(self.txvBuffer)) + self.playText(TextBuffer_get_text(self.txvBuffer)) def playText(self, text): if text: @@ -264,24 +379,33 @@ def playText(self, text): tmpFile = open(self.tempFilename, mode='w') tmpFile.write(text) tmpFile.close() - cmd = '%s %s' % (cmdEspeak, argsEspeak % ( - self.hscVolume.get_value(), - self.hscPitch.get_value(), - self.hscSpeed.get_value(), - self.hscDelay.get_value(), - self.cboLanguages.get_model()[self.cboLanguages.get_active()][1] + - (self.radioVoiceFemale.get_active() and '+12' or ''), - self.tempFilename - ) - ) - print cmd - self.espeak.play(cmd, cmdPlayer) + # Replace espeak's arguments with dialog values + language = self.listLanguages[self.cboLanguages.get_active()][1] + # Choose voice variant + if self.cboVariants.get_active() == 0: + # Default voice + if self.radioVoiceFemale.get_active(): + language += '+12' + else: + language += '+%s' % self.listVariants[self.cboVariants.get_active()][0] + args = { + '%v': str(int(self.hscVolume.get_value())), + '%p': str(int(self.hscPitch.get_value())), + '%s': str(int(self.hscSpeed.get_value())), + '%d': str(int(self.hscDelay.get_value())), + '%l': language, + '%f': self.tempFilename + } + cmd = [cmdEspeak] + [args.get(p, p) for p in argsEspeak.split()] + self.espeak.play(cmd, self.cmdPlayer, self.recordToFile) # Enable stop buttons on menu and toolbar self.imgmenuEditPlay.set_sensitive(False) self.imgmenuEditStop.set_sensitive(True) self.imgmenuEditPause.set_sensitive(True) + self.imgmenuEditRec.set_sensitive(False) self.btnPause.set_sensitive(True) self.btnPlayStop.set_label('gtk-media-stop') + self.tlbRecord.set_sensitive(False) # Enable check for running processes self.setStopCheck(True) @@ -292,6 +416,45 @@ def stopPlaying(self): self.imgmenuEditPlay.set_sensitive(True) self.imgmenuEditStop.set_sensitive(False) self.imgmenuEditPause.set_sensitive(False) + self.imgmenuEditRec.set_sensitive(True) self.btnPause.set_sensitive(False) self.btnPlayStop.set_label('gtk-media-play') + if Settings.get('SingleRecord'): + self.tlbRecord.set_active(False) + self.tlbRecord.set_sensitive(True) + + def on_imgmenuEditPreferences_activate(self, widget, data=None): + "Show preferences dialog" + prefsUI = 'preferences.glade' + gladePrefs = gtk.glade.XML(fname=prefsUI, domain=self.app_name) + PreferencesWindow.showPreferencesWindow(gladePrefs, iconLogo) + self.loadSettings(False) + + def on_tlbRecord_toggled(self, widget, data=None): + self.recordToFile = None + if self.tlbRecord.get_active(): + dialog = DialogFileSave( + title=_('Please select where to save the recorded file'), + initialDir=os.path.expanduser('~')) + dialog.set_icon_from_file(iconLogo) + dialog.addFilter(_('Wave files (*.wav)'), ['*.wav'], None) + dialog.addFilter(_('All files'), ['*'], None) + if dialog.show(): + print 'record to %s' % dialog.filename + self.recordToFile = dialog.filename + self.stbStatus.push(self.statusContextId, + _('Recording audio track to: %s' % self.recordToFile)) + else: + self.tlbRecord.set_active(False) + dialog.destroy() + else: + self.stbStatus.pop(self.statusContextId) + def on_radioVoice_toggled(self, widget, data=None): + "Assign variants after voice type change" + if widget.get_active(): + self.listVariants.clear() + self.listVariants.append(None) + for v in self.variants[widget is self.radioVoiceFemale and 1 or 0]: + self.listVariants.append(v) + self.cboVariants.set_active(0) diff --git a/locale/en_US.po b/locale/en_US.po index ae8b1f1..79f3120 100644 --- a/locale/en_US.po +++ b/locale/en_US.po @@ -6,10 +6,10 @@ # msgid "" msgstr "" -"Project-Id-Version: Gespeaker 0.4\n" +"Project-Id-Version: Gespeaker 0.5\n" "Report-Msgid-Bugs-To: Muflone \n" -"POT-Creation-Date: 2009-06-20 12:09+0200\n" -"PO-Revision-Date: 2009-06-20 12:13+0200\n" +"POT-Creation-Date: 2009-06-30 16:12+0200\n" +"PO-Revision-Date: 2009-06-30 16:13+0200\n" "Last-Translator: Muflone \n" "Language-Team: English\n" "MIME-Version: 1.0\n" @@ -17,94 +17,208 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: gespeaker.glade.h:1 +#: ../gespeaker.glade.h:1 msgid "Insert text to play" msgstr "Insert text to play" -#: gespeaker.glade.h:2 +#: ../gespeaker.glade.h:2 msgid "Settings" msgstr "Settings" -#: gespeaker.glade.h:3 +#: ../gespeaker.glade.h:3 msgid "Dela_y:" msgstr "Dela_y:" -#: gespeaker.glade.h:4 +#: ../gespeaker.glade.h:4 msgid "Fem_ale" msgstr "Fem_ale" -#: gespeaker.glade.h:5 +#: ../gespeaker.glade.h:5 msgid "P_itch:" msgstr "P_itch:" -#: gespeaker.glade.h:6 +#: ../gespeaker.glade.h:6 msgid "Spee_d:" msgstr "Spee_d:" -#: gespeaker.glade.h:7 +#: ../gespeaker.glade.h:7 +msgid "Varia_nt:" +msgstr "Varia_nt:" + +#: ../gespeaker.glade.h:8 msgid "Voice:" msgstr "Voice:" -#: gespeaker.glade.h:8 -msgid "Welcome in Gespeaker" -msgstr "Welcome in Gespeaker" - -#: gespeaker.glade.h:9 +#: ../gespeaker.glade.h:9 msgid "_Edit" msgstr "_Edit" -#: gespeaker.glade.h:10 +#: ../gespeaker.glade.h:10 msgid "_File" msgstr "_File" -#: gespeaker.glade.h:11 +#: ../gespeaker.glade.h:11 msgid "_Help" msgstr "_Help" -#: gespeaker.glade.h:12 +#: ../gespeaker.glade.h:12 msgid "_Language:" msgstr "_Language:" -#: gespeaker.glade.h:13 +#: ../gespeaker.glade.h:13 msgid "_Male" msgstr "_Male" -#: gespeaker.glade.h:14 +#: ../gespeaker.glade.h:14 msgid "_Volume:" msgstr "_Volume:" -#: gespeakerUI.py:101 +#: ../preferences.glade.h:1 +msgid "Audio player" +msgstr "Audio player" + +#: ../preferences.glade.h:2 +msgid "Other settings" +msgstr "Other settings" + +#: ../preferences.glade.h:3 +msgid "Recording" +msgstr "Recording" + +#: ../preferences.glade.h:4 +msgid "Saving preferences" +msgstr "Saving preferences" + +#: ../preferences.glade.h:5 +msgid "Welcome message" +msgstr "Welcome message" + +#: ../preferences.glade.h:6 +msgid "Co_mmand:" +msgstr "Co_mmand:" + +#: ../preferences.glade.h:7 +msgid "Custom mess_age:" +msgstr "Custom mess_age:" + +#: ../preferences.glade.h:8 +msgid "Enable te_xt wrapping" +msgstr "Enable te_xt wrapping" + +#: ../preferences.glade.h:9 +msgid "Load voice _variants" +msgstr "Load voice _variants" + +#: ../preferences.glade.h:10 +msgid "Preferences" +msgstr "Preferences" + +#: ../preferences.glade.h:11 +msgid "Save main window s_ize" +msgstr "Save main window s_ize" + +#: ../preferences.glade.h:12 +msgid "Single track _record" +msgstr "Single track _record" + +#: ../preferences.glade.h:13 +msgid "Speak _welcome text on program start" +msgstr "Speak _welcome text on program start" + +#: ../preferences.glade.h:14 +msgid "_Save voice settings automatically" +msgstr "_Save voice settings automatically" + +#: ../preferences.glade.h:15 +msgid "_Use custom welcome message" +msgstr "_Use custom welcome message" + +#: ../gespeakerUI.py:123 msgid "default language" msgstr "english" -#: gespeakerUI.py:122 +#: ../gespeakerUI.py:218 msgid "Do you want to delete the current text?" msgstr "Do you want to delete the current text?" -#: gespeakerUI.py:133 -msgid "Please select the file to open" -msgstr "Please select the file to open" +#: ../gespeakerUI.py:229 +msgid "Please select the text file to open" +msgstr "Please select the text file to open" + +#: ../gespeakerUI.py:231 ../gespeakerUI.py:256 +msgid "Text files (*.txt)" +msgstr "Text files (*.txt)" + +#: ../gespeakerUI.py:232 ../gespeakerUI.py:257 ../gespeakerUI.py:432 +msgid "All files" +msgstr "All files" -#: gespeakerUI.py:143 gespeakerUI.py:150 +#: ../gespeakerUI.py:241 ../gespeakerUI.py:248 msgid "Error opening the file" msgstr "Error opening the file" -#: gespeakerUI.py:157 -msgid "Please select where to save the file" -msgstr "Please select where to save the file" +#: ../gespeakerUI.py:255 +msgid "Please select where to save the text file" +msgstr "Please select where to save the text file" -#: gespeakerUI.py:168 gespeakerUI.py:175 +#: ../gespeakerUI.py:268 ../gespeakerUI.py:275 msgid "Error saving the file" msgstr "Error saving the file" -#: gespeakerUI.py:183 +#: ../gespeakerUI.py:283 msgid "Do you want to reset the default settings?" msgstr "Do you want to reset the default settings?" -#: gespeakerUI.py:204 +#: ../gespeakerUI.py:305 msgid "A GTK frontend for espeak" msgstr "A GTK frontend for espeak" -#: gespeakerUI.py:210 +#: ../gespeakerUI.py:311 msgid "translation" msgstr "English translation by Muflone " + +#: ../gespeakerUI.py:429 +msgid "Please select where to save the recorded file" +msgstr "Please select where to save the recorded file" + +#: ../gespeakerUI.py:431 +msgid "Wave files (*.wav)" +msgstr "Wave files (*.wav)" + +#: ../gespeakerUI.py:437 +#, python-format +msgid "Recording audio track to: %s" +msgstr "Recording audio track to: %s" + +#: ../PreferencesWindow.py:76 +msgid "ALSA - Advanced Linux Sound Architecture" +msgstr "ALSA - Advanced Linux Sound Architecture" + +#: ../PreferencesWindow.py:79 +msgid "PulseAudio sound server" +msgstr "PulseAudio sound server" + +#: ../PreferencesWindow.py:81 +msgid "Custom sound application" +msgstr "Custom sound application" + +#: ../PreferencesWindow.py:83 +msgid "_Test" +msgstr "_Test" + +#: ../PreferencesWindow.py:129 +msgid "Audio testing" +msgstr "Audio testing" + +#: ../PreferencesWindow.py:130 +#, python-format +msgid "" +"There was an error during the test for the audio player.\n" +"Error %s: %s" +msgstr "" +"There was an error during the test for the audio player.\n" +"Error %s: %s" + +#: ../Settings.py:39 +msgid "Welcome in Gespeaker" +msgstr "Welcome in Gespeaker" diff --git a/locale/en_US/LC_MESSAGES/gespeaker.mo b/locale/en_US/LC_MESSAGES/gespeaker.mo index 003dcd66522955e7c2a87c5b7b89251feec00caa..01bfea49ee53066985830cc761896f21808dc5df 100644 GIT binary patch literal 3650 zcmeH}Piz}S6vn5e6fl86DJ>KVQ=o0qvZy9U-HE+qy=%?P z+BN?Ua6#h00U_v#3rL($B@ow&3m2pw5SJnZ2LuvuLtFp}@x9qy2MSW}sH2X5eY3M~ z-h1EMX}{UA?Jb5eg?T^b$6FX%1eb5X4@P?%V|Rf8xCeX*yc>K6yaW6YycfI#j)GUf zUEq(|I=hjvG1z;+TfjN+HgF}gp8?5_1n&WR;7#Bg;6dCAotd>HmB=zu+N9DEPF6}$}Y2EPI+?_WUjI|^sy=K%N!I0KUZXYsQGY=c$s z1(5Rj6vV6S^X&N-Aie)Rh)~(@8QIOLy&WuIeI&DYgAc*po7tzq`(Q7C_`{m`q55oq z6!(kZ02;jpk}g}}jC9!rQhiDw?Oy~*mvbQLqCm>;m2CY2I0pM8kn;E%Bwc>U>|a6h z^Cw8UjN)*l!p6XZU=ch7o&)LJS3&ZBA+s-nwEr`Z>Tx-GvNQr+mYrF_RRDc%P$sjk#32$?;KNp&DisXz8(Qr@H~ z)!V_OyhtOe6KPBJ--=1~q@JL00F(632Wdj}n!tPj^9W`Mb2v^kPgW8?hY@jWca>b1N=BX>ZmnPS z>RB0jaYyow)LOKpbx`4pjVJlKiX$TUQSMO62<+9s+xh|5>49j zcA3>eDYV4FA?jm2T5-uODNILQwWklA?K7O0CaJ8*D7p>ipC13cd+49lHk*Lel2FT3 zk+jZew4PLK*g#y^el$vW8;GpT_iKh`LVt)L;{71<<387J@VsPo6oBGge-lm@cf!Zmf*6qFaIQJeIVy(|~3x z$$A(^lAq|Le>vT2>Y&pNnT|m3Ae!M`TPRe2cBy{GId*LNxKrBPOo8CqbE=US)1_GE$C`mD)WSrG&{>F8 z2VD|%t*K`xXK?${li9I|@0;bN@tFc$!s%CX{bIg;F<@Srzuf_lX delta 747 zcmbW!&npCB9LMoz8DlNGey^Y5K#HcuwySo|I7s=KgOpf9Q$p>wrPi(_$%T4y5El-L zg9Cqn@*g-VIXk+OyuZ8SAMkCz^Ln1?+2@(h%yZ{QxbWU!oGGf6?xf%7KKe4ig|f?( zYR4h0#R+V~MXbau_G2Cg@CKv!g3b7WvhK&%ELW!Nc zIp2K@asSAlYYZ|!$2z>mYJ9{ULOh`aNV1s(m_rG$ij|zN@(d)wAxeUKlmxFR2|iIC z(B$dF2ugw|l0YT=`wPfVt#FY59`aX}_dW1EMhS2#bIw;63?#u7$^mznzz3ACP({l| zvPR0FC253ipc`q~u!feZFHsC34DBy=d1J-mlNBq>Ro=v3 z>73CWoOLr9Z*x7Zzl?5uQn9E5W?YY(?YgYSYFzU+Ts6Dxx=X8$n&0wLuA_Iuj!p$f z195#DoVH?i&rr;ogVHcEql1MPWM;6>pi36e}{gD G$9@4vp;==9 diff --git a/locale/fr.po b/locale/fr.po index ec44dd9..ec6ce1b 100644 --- a/locale/fr.po +++ b/locale/fr.po @@ -2,14 +2,14 @@ # Copyright (C) 2009 Muflone Ubuntu Trucchi # This file is distributed under the GPL v2 license (see copyright file). # Muflone , 2009. -# French translation for gespeaker +# French translation for gespeaker package. # msgid "" msgstr "" -"Project-Id-Version: Gespeaker 0.4\n" +"Project-Id-Version: Gespeaker 0.5\n" "Report-Msgid-Bugs-To: Muflone \n" -"POT-Creation-Date: 2009-06-20 12:09+0200\n" -"PO-Revision-Date: 2009-06-20 12:13+0200\n" +"POT-Creation-Date: 2009-06-30 16:12+0200\n" +"PO-Revision-Date: 2009-06-30 16:13+0200\n" "Last-Translator: Emmanuel \n" "Language-Team: French\n" "MIME-Version: 1.0\n" @@ -17,94 +17,208 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: gespeaker.glade.h:1 +#: ../gespeaker.glade.h:1 msgid "Insert text to play" -msgstr "Insérer le texte à jouer" +msgstr "Insérer le texte à lire" -#: gespeaker.glade.h:2 +#: ../gespeaker.glade.h:2 msgid "Settings" msgstr "Préférences" -#: gespeaker.glade.h:3 +#: ../gespeaker.glade.h:3 msgid "Dela_y:" msgstr "Déla_i:" -#: gespeaker.glade.h:4 +#: ../gespeaker.glade.h:4 msgid "Fem_ale" msgstr "Fémini_ne" -#: gespeaker.glade.h:5 +#: ../gespeaker.glade.h:5 msgid "P_itch:" msgstr "_Tonalité:" -#: gespeaker.glade.h:6 +#: ../gespeaker.glade.h:6 msgid "Spee_d:" msgstr "Vite_sse:" -#: gespeaker.glade.h:7 +#: ../gespeaker.glade.h:7 +msgid "Varia_nt:" +msgstr "Va_riante:" + +#: ../gespeaker.glade.h:8 msgid "Voice:" msgstr "Voix:" -#: gespeaker.glade.h:8 -msgid "Welcome in Gespeaker" -msgstr "Bienvenu dans Gespeaker" - -#: gespeaker.glade.h:9 +#: ../gespeaker.glade.h:9 msgid "_Edit" msgstr "É_dition" -#: gespeaker.glade.h:10 +#: ../gespeaker.glade.h:10 msgid "_File" msgstr "_Fichier" -#: gespeaker.glade.h:11 +#: ../gespeaker.glade.h:11 msgid "_Help" msgstr "Aid_e" -#: gespeaker.glade.h:12 +#: ../gespeaker.glade.h:12 msgid "_Language:" msgstr "Lang_ue:" -#: gespeaker.glade.h:13 +#: ../gespeaker.glade.h:13 msgid "_Male" msgstr "_Masculine" -#: gespeaker.glade.h:14 +#: ../gespeaker.glade.h:14 msgid "_Volume:" msgstr "_Volume:" -#: gespeakerUI.py:101 +#: ../preferences.glade.h:1 +msgid "Audio player" +msgstr "Lecteur audio" + +#: ../preferences.glade.h:2 +msgid "Other settings" +msgstr "Autres paramètres" + +#: ../preferences.glade.h:3 +msgid "Recording" +msgstr "Enregistrement" + +#: ../preferences.glade.h:4 +msgid "Saving preferences" +msgstr "Enregistrer les préférences" + +#: ../preferences.glade.h:5 +msgid "Welcome message" +msgstr "Message de bienvenu" + +#: ../preferences.glade.h:6 +msgid "Co_mmand:" +msgstr "_Commande:" + +#: ../preferences.glade.h:7 +msgid "Custom mess_age:" +msgstr "Message p_ersonnalisé" + +#: ../preferences.glade.h:8 +msgid "Enable te_xt wrapping" +msgstr "_Activer le retour à la ligne" + +#: ../preferences.glade.h:9 +msgid "Load voice _variants" +msgstr "_Charger les variantes des voix" + +#: ../preferences.glade.h:10 +msgid "Preferences" +msgstr "Préférences" + +#: ../preferences.glade.h:11 +msgid "Save main window s_ize" +msgstr "Enregistrer les _dimensions de la fenêtre principale" + +#: ../preferences.glade.h:12 +msgid "Single track _record" +msgstr "En_registrement piste unique" + +#: ../preferences.glade.h:13 +msgid "Speak _welcome text on program start" +msgstr "Lire le _message de bienvenu au lancement du programme" + +#: ../preferences.glade.h:14 +msgid "_Save voice settings automatically" +msgstr "Enreg_istrer les paramètres de la voix automatiquement" + +#: ../preferences.glade.h:15 +msgid "_Use custom welcome message" +msgstr "_Utiliser le message de bienvenu personnalisé" + +#: ../gespeakerUI.py:123 msgid "default language" msgstr "french" -#: gespeakerUI.py:122 +#: ../gespeakerUI.py:218 msgid "Do you want to delete the current text?" msgstr "Voulez-vous effacer le texte courant?" -#: gespeakerUI.py:133 -msgid "Please select the file to open" -msgstr "Choisir le fichier à ouvrir" +#: ../gespeakerUI.py:229 +msgid "Please select the text file to open" +msgstr "Choisir le fichier texte à ouvrir" + +#: ../gespeakerUI.py:231 ../gespeakerUI.py:256 +msgid "Text files (*.txt)" +msgstr "Fichiers texte (*.txt)" + +#: ../gespeakerUI.py:232 ../gespeakerUI.py:257 ../gespeakerUI.py:432 +msgid "All files" +msgstr "Tout les fichiers" -#: gespeakerUI.py:143 gespeakerUI.py:150 +#: ../gespeakerUI.py:241 ../gespeakerUI.py:248 msgid "Error opening the file" msgstr "Erreur en ouvrant le fichier" -#: gespeakerUI.py:157 -msgid "Please select where to save the file" -msgstr "Choisir où enregistrer le fichier" +#: ../gespeakerUI.py:255 +msgid "Please select where to save the text file" +msgstr "Choisir où enregistrer le fichier texte" -#: gespeakerUI.py:168 gespeakerUI.py:175 +#: ../gespeakerUI.py:268 ../gespeakerUI.py:275 msgid "Error saving the file" msgstr "Erreur en enregistrant le fichier" -#: gespeakerUI.py:183 +#: ../gespeakerUI.py:283 msgid "Do you want to reset the default settings?" msgstr "Voulez-vous rétablir les paramètres par défaut?" -#: gespeakerUI.py:204 +#: ../gespeakerUI.py:305 msgid "A GTK frontend for espeak" msgstr "Une interface GTK pour espeak" -#: gespeakerUI.py:210 +#: ../gespeakerUI.py:311 msgid "translation" msgstr "Traduction française par Emmanuel " + +#: ../gespeakerUI.py:429 +msgid "Please select where to save the recorded file" +msgstr "Choisir où sauvegarder le fichier enregistré" + +#: ../gespeakerUI.py:431 +msgid "Wave files (*.wav)" +msgstr "Fichiers Wave (*.wav)" + +#: ../gespeakerUI.py:437 +#, python-format +msgid "Recording audio track to: %s" +msgstr "Enregistrement piste audio sous: %s" + +#: ../PreferencesWindow.py:76 +msgid "ALSA - Advanced Linux Sound Architecture" +msgstr "ALSA - Advanced Linux Sound Architecture" + +#: ../PreferencesWindow.py:79 +msgid "PulseAudio sound server" +msgstr "Serveur audio PulseAudio" + +#: ../PreferencesWindow.py:81 +msgid "Custom sound application" +msgstr "Application sonore personnalisée" + +#: ../PreferencesWindow.py:83 +msgid "_Test" +msgstr "Veri_fier" + +#: ../PreferencesWindow.py:129 +msgid "Audio testing" +msgstr "Vérifier l'audio" + +#: ../PreferencesWindow.py:130 +#, python-format +msgid "" +"There was an error during the test for the audio player.\n" +"Error %s: %s" +msgstr "" +"Une erreur s'est produite pendant l'exécution du lecteur audio.\n" +"Erreur %s: %s" + +#: ../Settings.py:39 +msgid "Welcome in Gespeaker" +msgstr "Bienvenu dans Gespeaker" diff --git a/locale/fr/LC_MESSAGES/gespeaker.mo b/locale/fr/LC_MESSAGES/gespeaker.mo index f43395d4bb0db5e99cb10ac8d5c63f8da5fa932f..4f186b86b9183673c8a4f484e16e14202f73ca3f 100644 GIT binary patch literal 3910 zcmb7`O>87b8HNkk1egRumY;<{LP4_edPC3JUhNWQcfC9Dj+X_SSoW+VfuJaN*Nltp zscNdKXY2q%+yWO)0WL@!A_a4ZIB*E323B@a^Dt!3FU9;92kukmmh6 zNaM2ytM)07`X}J~zzcQzGvJeGZ-WUq1{c9sz=y!!f~UYgg0${`fHdwS7>vew8hi@8 z1k(6l#>Yu;AMAl&18F_K0P!mOb^ZJAL3;nsAVOvTtjXR{wI2jqc>ZwRJ_UXp?Z@l( zHSoh|uY>qwd-x!IZi5u}*TH}sy#&%c|3(lTJc&Um59dMBX%nRQQ;_<-1XBKf2tE$J z4xR!306q%-r{<%W1Yg;cAnDNtKL++dOv#4eX|MoS!0&-ifWHDs$G?Kq|AB|AaTdUj zqP+s*C$S$4^1>#hW1c;4dKMj~-qCo&st7&x04i2}t_C22z}_gP#L` z2U7e`yt~qS5hOj%ft2qaNbh|SjOzg@Pet7xgY^D4!B2wU0jd8l!8Z6CklyirGbbi{fZ5(rl@2JX4d_N86Ts zx`>;6MB07jTol32s<6YEQb5cBJoHanpLqi*!AW`)vGH zeUR5EucQ(A;T-N|+_UTQ-fFkZwB3p}U;d{jR+KRqAzmE&H8 zpv}-XPq$TSU4|#kgB>|Wix*A}lv5^Ev#vXLz50U6Q#(?8q`a3y6$j|@8~xAnfwLwk zlktIdT=_!D+pN2>)8z^8W@Cv#GrplsdBAsUiEdq&?(3k^P&&oBdCmtqSDsZ149Zi) zY|V<%NSds})=D4jD9$S|@$7+*gUO=Ebt;3lhFw>=6o(yl-SR_Q@`*H2mQ3X;C=Nk* zS~{$XbcWH!%CVV&xQu=bPNugJS%;tY3}%8q zq&9q_O=c(D3;m*EI}nG$k6lF-9or$Ba51S}6{D~QMzljGN8AVL0(DXX7U+|~qf7Xi zv+ZyY7Fj#C1%PY?;;R!k>+iI+7;`{eIU-jFNJ|z7*aO*m}M|-?fIlrvU zz+S5+PjV_2ZB(1pRwHWCS8~+h>r|umTbnmGd-Ihpx0hOLu>@i8!vax~o6aHO+Fau4 zzI2fP%B}u-^6b1H1%Z;6^h|20Aa?k(dpfkX^3usXS+{NkhnONZ{gstVsJ!&cl{1E~ z^5w-#Evmm85M7n7a#&MRQIw}g4#hXtivv`i>5q7>T~#t;B@ZYyypS;Z^vCqQd9`Pp z8fuS6BUGt-pVF9k(M^vAG{y09y>-8bn^mpmnc{m|nXxiu9P}1)u2HkyK%xp!4KFN~ z@&DHDzAZzHXrNKiVLY~ru=D_5dA<<09TRId)^S+4iKYfs~3~8Ej?EQ3jUbNDVBg*di9Q8P$i&p>sqeGp7QHK}nOy+t9>= zbu%J$pFO{`J8d0>qu`ju*bdeH#^!u}G~iS`?pI#Gx=p#osZo{Kd7ml=BGWK8l?qxm zX*^J7`V)8_#?~g)1r^Vp!9g+K3iZ&X(O)fbf?_jK21H#YkNX>Y5o2O!&<^5R*_)D(sv@LLy&{F*Zogg@kvJ!8>kS2>sT~G(pqqL-dH)wD=rDw{- zvxQo-!$ri?9TVboIXE_LJY_IzJYSxxcP7USeqOfO^xKds{$GP*ChjlR)tSKZaRi7G zqvD+LX^Cn{dO;O* delta 772 zcmXxh&ubGw6u|L`rrXUAV{MH;f~L`03YEoeh(ecA5UK|&SR2SeilvFuvMPz}Zi9zn z(UamqbnqZ}P!B>*9&+&@2nM`(@*)VL7m)?-M*bkj$(IRkgu6$n0#4z6yo^V22?w!_6L=3N@hu+0ub9UzlyU!Jt-VSWY3J~i zQk%-*K?W?Mh1c*PuHXQ+V>e zBeKYfG$iC~cY{CH500!K`?$+l?uOY&j@nfnMSgQFG~3Bh^JHMjB&>?LWEG5WIU}q7 zZLO+zv|hg9sanf#XwUo}^i0FPkf@lBebp(urKz&#PM>zmuA5%C;wSO5S3 diff --git a/locale/gespeaker.pot b/locale/gespeaker.pot index df2fe24..5ce8ff8 100644 --- a/locale/gespeaker.pot +++ b/locale/gespeaker.pot @@ -2,14 +2,14 @@ # Copyright (C) 2009 Muflone Ubuntu Trucchi # This file is distributed under the GPL v2 license (see copyright file). # Muflone , 2009. -# X translation for gespeaker +# X translation for gespeaker package. # #, fuzzy msgid "" msgstr "" -"Project-Id-Version: Gespeaker 0.4\n" +"Project-Id-Version: Gespeaker 0.5\n" "Report-Msgid-Bugs-To: Muflone \n" -"POT-Creation-Date: 2009-06-20 12:09+0200\n" +"POT-Creation-Date: 2009-06-30 16:12+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,94 +17,206 @@ msgstr "" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" -#: gespeaker.glade.h:1 +#: ../gespeaker.glade.h:1 msgid "Insert text to play" msgstr "" -#: gespeaker.glade.h:2 +#: ../gespeaker.glade.h:2 msgid "Settings" msgstr "" -#: gespeaker.glade.h:3 +#: ../gespeaker.glade.h:3 msgid "Dela_y:" msgstr "" -#: gespeaker.glade.h:4 +#: ../gespeaker.glade.h:4 msgid "Fem_ale" msgstr "" -#: gespeaker.glade.h:5 +#: ../gespeaker.glade.h:5 msgid "P_itch:" msgstr "" -#: gespeaker.glade.h:6 +#: ../gespeaker.glade.h:6 msgid "Spee_d:" msgstr "" -#: gespeaker.glade.h:7 -msgid "Voice:" +#: ../gespeaker.glade.h:7 +msgid "Varia_nt:" msgstr "" -#: gespeaker.glade.h:8 -msgid "Welcome in Gespeaker" +#: ../gespeaker.glade.h:8 +msgid "Voice:" msgstr "" -#: gespeaker.glade.h:9 +#: ../gespeaker.glade.h:9 msgid "_Edit" msgstr "" -#: gespeaker.glade.h:10 +#: ../gespeaker.glade.h:10 msgid "_File" msgstr "" -#: gespeaker.glade.h:11 +#: ../gespeaker.glade.h:11 msgid "_Help" msgstr "" -#: gespeaker.glade.h:12 +#: ../gespeaker.glade.h:12 msgid "_Language:" msgstr "" -#: gespeaker.glade.h:13 +#: ../gespeaker.glade.h:13 msgid "_Male" msgstr "" -#: gespeaker.glade.h:14 +#: ../gespeaker.glade.h:14 msgid "_Volume:" msgstr "" -#: gespeakerUI.py:101 +#: ../preferences.glade.h:1 +msgid "Audio player" +msgstr "" + +#: ../preferences.glade.h:2 +msgid "Other settings" +msgstr "" + +#: ../preferences.glade.h:3 +msgid "Recording" +msgstr "" + +#: ../preferences.glade.h:4 +msgid "Saving preferences" +msgstr "" + +#: ../preferences.glade.h:5 +msgid "Welcome message" +msgstr "" + +#: ../preferences.glade.h:6 +msgid "Co_mmand:" +msgstr "" + +#: ../preferences.glade.h:7 +msgid "Custom mess_age:" +msgstr "" + +#: ../preferences.glade.h:8 +msgid "Enable te_xt wrapping" +msgstr "" + +#: ../preferences.glade.h:9 +msgid "Load voice _variants" +msgstr "" + +#: ../preferences.glade.h:10 +msgid "Preferences" +msgstr "" + +#: ../preferences.glade.h:11 +msgid "Save main window s_ize" +msgstr "" + +#: ../preferences.glade.h:12 +msgid "Single track _record" +msgstr "" + +#: ../preferences.glade.h:13 +msgid "Speak _welcome text on program start" +msgstr "" + +#: ../preferences.glade.h:14 +msgid "_Save voice settings automatically" +msgstr "" + +#: ../preferences.glade.h:15 +msgid "_Use custom welcome message" +msgstr "" + +#: ../gespeakerUI.py:123 msgid "default language" msgstr "" -#: gespeakerUI.py:122 +#: ../gespeakerUI.py:218 msgid "Do you want to delete the current text?" msgstr "" -#: gespeakerUI.py:133 -msgid "Please select the file to open" +#: ../gespeakerUI.py:229 +msgid "Please select the text file to open" +msgstr "" + +#: ../gespeakerUI.py:231 ../gespeakerUI.py:256 +msgid "Text files (*.txt)" +msgstr "" + +#: ../gespeakerUI.py:232 ../gespeakerUI.py:257 ../gespeakerUI.py:432 +msgid "All files" msgstr "" -#: gespeakerUI.py:143 gespeakerUI.py:150 +#: ../gespeakerUI.py:241 ../gespeakerUI.py:248 msgid "Error opening the file" msgstr "" -#: gespeakerUI.py:157 -msgid "Please select where to save the file" +#: ../gespeakerUI.py:255 +msgid "Please select where to save the text file" msgstr "" -#: gespeakerUI.py:168 gespeakerUI.py:175 +#: ../gespeakerUI.py:268 ../gespeakerUI.py:275 msgid "Error saving the file" msgstr "" -#: gespeakerUI.py:183 +#: ../gespeakerUI.py:283 msgid "Do you want to reset the default settings?" msgstr "" -#: gespeakerUI.py:204 +#: ../gespeakerUI.py:305 msgid "A GTK frontend for espeak" msgstr "" -#: gespeakerUI.py:210 +#: ../gespeakerUI.py:311 msgid "translation" msgstr "" + +#: ../gespeakerUI.py:429 +msgid "Please select where to save the recorded file" +msgstr "" + +#: ../gespeakerUI.py:431 +msgid "Wave files (*.wav)" +msgstr "" + +#: ../gespeakerUI.py:437 +#, python-format +msgid "Recording audio track to: %s" +msgstr "" + +#: ../PreferencesWindow.py:76 +msgid "ALSA - Advanced Linux Sound Architecture" +msgstr "" + +#: ../PreferencesWindow.py:79 +msgid "PulseAudio sound server" +msgstr "" + +#: ../PreferencesWindow.py:81 +msgid "Custom sound application" +msgstr "" + +#: ../PreferencesWindow.py:83 +msgid "_Test" +msgstr "" + +#: ../PreferencesWindow.py:129 +msgid "Audio testing" +msgstr "" + +#: ../PreferencesWindow.py:130 +#, python-format +msgid "" +"There was an error during the test for the audio player.\n" +"Error %s: %s" +msgstr "" + +#: ../Settings.py:39 +msgid "Welcome in Gespeaker" +msgstr "" diff --git a/locale/it.po b/locale/it.po index 6d05c49..9c462f4 100644 --- a/locale/it.po +++ b/locale/it.po @@ -2,14 +2,14 @@ # Copyright (C) 2009 Muflone Ubuntu Trucchi # This file is distributed under the GPL v2 license (see copyright file). # Muflone , 2009. -# Italian translation for gespeaker +# Italian translation for gespeaker package. # msgid "" msgstr "" -"Project-Id-Version: Gespeaker 0.4\n" +"Project-Id-Version: Gespeaker 0.5\n" "Report-Msgid-Bugs-To: Muflone \n" -"POT-Creation-Date: 2009-06-20 12:09+0200\n" -"PO-Revision-Date: 2009-06-20 12:13+0200\n" +"POT-Creation-Date: 2009-06-30 16:12+0200\n" +"PO-Revision-Date: 2009-06-30 16:13+0200\n" "Last-Translator: Muflone \n" "Language-Team: Italian\n" "MIME-Version: 1.0\n" @@ -17,95 +17,207 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: gespeaker.glade.h:1 +#: ../gespeaker.glade.h:1 msgid "Insert text to play" msgstr "Inserisci il testo da riprodurre" -#: gespeaker.glade.h:2 +#: ../gespeaker.glade.h:2 msgid "Settings" msgstr "Impostazioni" -#: gespeaker.glade.h:3 +#: ../gespeaker.glade.h:3 msgid "Dela_y:" msgstr "Ritar_do:" -#: gespeaker.glade.h:4 +#: ../gespeaker.glade.h:4 msgid "Fem_ale" -msgstr "F_emminile" +msgstr "Femmini_le" -#: gespeaker.glade.h:5 +#: ../gespeaker.glade.h:5 msgid "P_itch:" msgstr "_Tonalità:" -#: gespeaker.glade.h:6 +#: ../gespeaker.glade.h:6 msgid "Spee_d:" msgstr "_Velocità:" -#: gespeaker.glade.h:7 +#: ../gespeaker.glade.h:7 +msgid "Varia_nt:" +msgstr "Variant_e:" + +#: ../gespeaker.glade.h:8 msgid "Voice:" msgstr "Voce:" -#: gespeaker.glade.h:8 -msgid "Welcome in Gespeaker" -msgstr "Benvenuto in Gespeaker" - -#: gespeaker.glade.h:9 +#: ../gespeaker.glade.h:9 msgid "_Edit" msgstr "_Modifica" -#: gespeaker.glade.h:10 +#: ../gespeaker.glade.h:10 msgid "_File" msgstr "_File" -#: gespeaker.glade.h:11 +#: ../gespeaker.glade.h:11 msgid "_Help" msgstr "A_iuto" -#: gespeaker.glade.h:12 +#: ../gespeaker.glade.h:12 msgid "_Language:" msgstr "Li_ngua:" -#: gespeaker.glade.h:13 +#: ../gespeaker.glade.h:13 msgid "_Male" msgstr "M_aschile" -#: gespeaker.glade.h:14 +#: ../gespeaker.glade.h:14 msgid "_Volume:" msgstr "V_olume:" -#: gespeakerUI.py:101 +#: ../preferences.glade.h:1 +msgid "Audio player" +msgstr "Riproduttore audio" + +#: ../preferences.glade.h:2 +msgid "Other settings" +msgstr "Altre impostazioni" + +#: ../preferences.glade.h:3 +msgid "Recording" +msgstr "Registrazione" + +#: ../preferences.glade.h:4 +msgid "Saving preferences" +msgstr "Salvataggio delle preferenze" + +#: ../preferences.glade.h:5 +msgid "Welcome message" +msgstr "Messaggio di benvenuto" + +#: ../preferences.glade.h:6 +msgid "Co_mmand:" +msgstr "_Comando:" + +#: ../preferences.glade.h:7 +msgid "Custom mess_age:" +msgstr "Messaggio p_ersonalizzato:" + +#: ../preferences.glade.h:8 +msgid "Enable te_xt wrapping" +msgstr "Attiva a capo del _testo" + +#: ../preferences.glade.h:9 +msgid "Load voice _variants" +msgstr "Carica _varianti delle voci" + +#: ../preferences.glade.h:10 +msgid "Preferences" +msgstr "Preferenze" + +#: ../preferences.glade.h:11 +msgid "Save main window s_ize" +msgstr "Salva _dimensioni della finestra principale" + +#: ../preferences.glade.h:12 +msgid "Single track _record" +msgstr "_Registrazione traccia singola" + +#: ../preferences.glade.h:13 +msgid "Speak _welcome text on program start" +msgstr "Riproduci _messaggio di benvenuto all'avvio del programma" + +#: ../preferences.glade.h:14 +msgid "_Save voice settings automatically" +msgstr "Salva _impostazioni della voce automaticamente" + +#: ../preferences.glade.h:15 +msgid "_Use custom welcome message" +msgstr "_Utilizza messaggio di benvenuto personalizzato" + +#: ../gespeakerUI.py:123 msgid "default language" msgstr "italian" -#: gespeakerUI.py:122 +#: ../gespeakerUI.py:218 msgid "Do you want to delete the current text?" msgstr "Vuoi cancellare il testo corrente?" -#: gespeakerUI.py:133 -msgid "Please select the file to open" -msgstr "Scegli il file da aprire" +#: ../gespeakerUI.py:229 +msgid "Please select the text file to open" +msgstr "Scegliere il file di testo da aprire" + +#: ../gespeakerUI.py:231 ../gespeakerUI.py:256 +msgid "Text files (*.txt)" +msgstr "Files di testo (*.txt)" + +#: ../gespeakerUI.py:232 ../gespeakerUI.py:257 ../gespeakerUI.py:432 +msgid "All files" +msgstr "Tutti i files" -#: gespeakerUI.py:143 gespeakerUI.py:150 +#: ../gespeakerUI.py:241 ../gespeakerUI.py:248 msgid "Error opening the file" msgstr "Errore nell'apertura del file" -#: gespeakerUI.py:157 -msgid "Please select where to save the file" -msgstr "Scegli dove salvare il file" +#: ../gespeakerUI.py:255 +msgid "Please select where to save the text file" +msgstr "Scegliere dove salvare il file di testo" -#: gespeakerUI.py:168 gespeakerUI.py:175 +#: ../gespeakerUI.py:268 ../gespeakerUI.py:275 msgid "Error saving the file" msgstr "Errore nel salvataggio del file" -#: gespeakerUI.py:183 +#: ../gespeakerUI.py:283 msgid "Do you want to reset the default settings?" -msgstr "Vuoi ripristinare le impostazioni predefinite?" +msgstr "Ripristinare le impostazioni predefinite?" -#: gespeakerUI.py:204 +#: ../gespeakerUI.py:305 msgid "A GTK frontend for espeak" msgstr "Un'interfaccia in GTK per espeak" -#: gespeakerUI.py:210 +#: ../gespeakerUI.py:311 msgid "translation" msgstr "Traduzione italiana di Muflone " +#: ../gespeakerUI.py:429 +msgid "Please select where to save the recorded file" +msgstr "Scegliere dove salvare il file registrato" + +#: ../gespeakerUI.py:431 +msgid "Wave files (*.wav)" +msgstr "Files Wave (*.wav)" + +#: ../gespeakerUI.py:437 +#, python-format +msgid "Recording audio track to: %s" +msgstr "Registrazione traccia audio su: %s" + +#: ../PreferencesWindow.py:76 +msgid "ALSA - Advanced Linux Sound Architecture" +msgstr "ALSA - Advanced Linux Sound Architecture" + +#: ../PreferencesWindow.py:79 +msgid "PulseAudio sound server" +msgstr "Server audio PulseAudio" + +#: ../PreferencesWindow.py:81 +msgid "Custom sound application" +msgstr "Applicazione sonora personalizzata" + +#: ../PreferencesWindow.py:83 +msgid "_Test" +msgstr "_Prova" + +#: ../PreferencesWindow.py:129 +msgid "Audio testing" +msgstr "Prova dell'audio" + +#: ../PreferencesWindow.py:130 +#, python-format +msgid "" +"There was an error during the test for the audio player.\n" +"Error %s: %s" +msgstr "Si è verificato un errore durante la prova del riproduttore audio.\n" +"Errore %s: %s" + +#: ../Settings.py:39 +msgid "Welcome in Gespeaker" +msgstr "Benvenuto in Gespeaker" diff --git a/locale/it/LC_MESSAGES/gespeaker.mo b/locale/it/LC_MESSAGES/gespeaker.mo index a8240f6978067dcab11c8a6d8fdf6387547fdc4c..86fd37d5a667b6189fa9cb6753c326c028d1e9e9 100644 GIT binary patch literal 3871 zcmb7`OKc=Z8OI9}5-@o{0&EC*R0tdIZfLK)s}0HQ!n!faaR2^Oj9mdY?!p7t-rbBn3~KOE@F(Dx!8gD!fWHI33cd?I z2>u=X3ixsJo_&U~6KFpQehyp#?*})V_V+=WM}d!k6YyT}=iof}EASNfE=cSC6Quds zJ-K}hr11s#CGcF+eg%9Q?H*Ww6YwPX7WjGaui!E8A0X}f-yqHVASR=Eo&moBo(F0E zAL8*4xCgF+uYZ0AVWoPeb7D)E>n)h|n{wYX${stt!{RO1?Z-7sNciorw`7}uTSpd<+ zUI9thZIHfy9VGkT24M<&A0)qg0Mfeu0-psRhLKNz%is&(4?vpl4Uqiy7Wf_T4Vp2f*h(eL6=_{e4FojXQQ$e z-*uj=Fjn#!>u&VByx`qxA~9*jH?*y<^S-Mwtn14?9aR}?uUOX@zN?K2EN?KXKo+wV zCq^S_s}5VKLv*9GuE4_67a>h1$77>Q8MU+QvNBQ}bl7Fb4_wXnrA@L_%BZL~1mR`v zvCFL3@~z{%f?R1>rFLa);#9t6wrb^$!5m6J>V1z@$;egjv1K<_mPDilXe-U@kfoiz zT~i|=(YxVf#V1aeii?T#8de6jC3GzJI&8}*859;a&?n89oJ-S^hiR!>#_Yq-sSoSr zP5R_yh@OnOdB#tUp3cvMCl_9QUW0`pa4%%!cUx9 zh}YvuHb~pvmw`*mRq{hs`_>H99MWO0(H5pF z?aRqY)&@SdbtOkPbP%hRj!dkPyT!}OjG5Swc37tX6`SN|k>tpZZu1bfAeIrWr8MS% zi2>|n;wn5|<|uFVXtIonZD;Bc3~NKuG^;SkX@kjuzvbPJ5HH1gRctFCkPDret$cCe z++0tMosY$480xBcsUC)60H1BvyT)0?FO2d(FHUxX9*vD!uqs}f+j@0Staz2yC@#yW zI{eJy;tR#%bH&+3zVuvY>CCf>c!PmOPfau}eEV@{^SBKeVlik8cm9qBw2~GBB}W~; z9;HFL%x$i3uFf{Pw6Hk0k}449J{ZGD3Z~QWx3=ebxhFl;zj$@9Ry;o&M>e416|1&% zR1Z7+`5hhSwoL7%Db}1HAwcXnHN(X-=TUg6=i&*=pSsAGPM)8m`rFfp*Q$=uAq7*I zwRJUBW*th+wShgTV7!vt=kcgP?YORq_!OEuMEoK2(``>r4RwH%>E(2IUz&-GayZ0M zfU<_HYAg5QbjT z_M6iO)x=F?GIBmC!^8?AA7!D#X4Z@a!qr*0_3%)lim+}j=V{X%J*C?$QQnep6Kp0vYmTc{;6W8V&4?b*-?P% zeupD8NnSafC|EU}B`>w9m-1|Onrxy7ksZy6(iIx% z$u_j0BLxW~WWaAG#84^#T-+4KR0t$~QQ!x~?0A9v5ob`!LYy#Brxa^`y?sK+n^MfN bZPA=MNHwas3^lu|b5b_1kOKM+=Lh>ADUS)> delta 818 zcmXxh&ubGw6u|L`rrZ3`Xj^|qZB|jLmX&RYh3-WtiXej8N)8$bOEQ*)Z8junyc7$1 z(UX*+2T`yn2znAccvC@7-o%TdcvA4hLAYC#D&h?8z>ByaYdDI1oWfgp5})B7{DiylH_EtwiPl!7CTSP&s8Van z;Y9{4poQ0P7y3AY{lwM8+nA&OZqhcGq5S}N;uFl{E9|j}w>=`fnnis5>Ypa1XP%ne@Lve(EI;Dfl&J zSzo-%xHrCXtEdBZ)LAJ1vmor0hxx+(t@_#SDs&layj*UJ0fggluFl zS&5tR-45S5u|aTUgV@ef?s6DrHC@Uq>RvBsEp^S`bjjQwshN~jF&C_&2`p#gMi6SX z*w(t<^i(wp8rm~IM?KTXoJ&>A^UM{e?AkMB&z+lg%dVTde92kR{h%8}E$6J?)1FQ5 zoa4^MM&}=6I3Iq-7U