merge upstream

This commit is contained in:
Nikolai Prokoschenko
2009-01-25 18:19:17 +01:00
42 changed files with 68858 additions and 22500 deletions

View File

@@ -0,0 +1,57 @@
# Copyright 2007 Javier Kohen
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation
import unicodedata
def iswbound(char):
"""Returns whether the given character is a word boundary."""
category = unicodedata.category(char)
# If it's a space separator or punctuation
return 'Zs' == category or 'Sk' == category or 'P' == category[0]
def utitle(string):
"""Title-case a string using a less destructive method than str.title."""
new_string = string[0].capitalize()
cap = False
for i in xrange(1, len(string)):
s = string[i]
# Special case apostrophe in the middle of a word.
if u"'" == s and string[i-1].isalpha(): cap = False
elif iswbound(s): cap = True
elif cap and s.isalpha():
cap = False
s = s.capitalize()
else: cap = False
new_string += s
return new_string
def title(string, locale="utf-8"):
"""Title-case a string using a less destructive method than str.title."""
if not string: return u""
# if the string is all uppercase, lowercase it - Erich/Javier
# Lots of Japanese songs use entirely upper-case English titles,
# so I don't like this change... - JoeW
#if string == string.upper(): string = string.lower()
if not isinstance(string, unicode):
string = string.decode(locale)
return utitle(string)
PLUGIN_NAME = "Title Case"
PLUGIN_API_VERSIONS = ["0.9", "0.10", "0.11"]
PLUGIN_DESCRIPTION = "Capitalize First Character In Every Word Of A Title"
from picard.metadata import (
register_track_metadata_processor,
register_album_metadata_processor,
)
def title_case(tagger, metadata, release, track=None):
for name, value in metadata.rawitems():
if name in ["title", "album", "artist"]:
metadata[name] = [title(x) for x in value]
register_track_metadata_processor(title_case)
register_album_metadata_processor(title_case)

View File

@@ -301,3 +301,39 @@ RELEASE_COUNTRIES = {
u'XW': N_('[Worldwide]'),
u'YU': N_('Yugoslavia (historical, 1918-1992)'),
}
# List of available user interface languages
UI_LANGUAGES = [
(u'ca', u'Català', N_(u'Catalan')),
(u'cs', u'Čeština', N_(u'Czech')),
(u'cy', u'Cymraeg', N_(u'Welsh')),
(u'da', u'Dansk', N_(u'Danish')),
(u'de', u'Deutsch', N_(u'German')),
(u'en', u'English', N_(u'English')),
(u'en_CA', u'English (Canada)', N_(u'English (Canada)')),
(u'en_GB', u'English (UK)', N_(u'English (UK)')),
(u'es', u'Español', N_(u'Spanish')),
(u'fa', u'فارسی', N_(u'Persian')),
(u'fi', u'Suomi', N_(u'Finnish')),
(u'fr', u'Français', N_(u'French')),
(u'fy', u'Frysk', N_(u'Frisian')),
(u'he', u'עברית', N_(u'Hebrew')),
(u'hu', u'Magyar', N_(u'Hungarian')),
(u'is', u'Íslenska', N_(u'Islandic')),
(u'it', u'Italiano', N_(u'Italian')),
(u'kn', u'ಕನ್ನಡ ', N_(u'Kannada')),
(u'ko', u'한국어', N_(u'Korean')),
(u'lt', u'Lietuvių', N_(u'Lithuanian')),
(u'nb', u'Norsk bokmål', N_(u'Norwegian Bokmal')),
(u'nl', u'Nederlands', N_(u'Dutch')),
(u'pl', u'Polski', N_(u'Polish')),
(u'pt', u'Português', N_(u'Portuguese')),
(u'pt_BR', u'Português do Brasil', N_(u'Brazilian Portuguese')),
(u'ro', u'Română', N_(u'Romanian')),
(u'ru', u'Pyccĸий', N_(u'Russian')),
(u'sco', u'Scots leid', N_(u'Scots')),
(u'sk', u'Slovenčina', N_(u'Slovak')),
(u'sl', u'Slovenščina', N_(u'Slovenian')),
(u'sv', u'Svenska', N_(u'Swedish')),
(u'zh_CN', u'中文', N_(u'Chinese')),
]

View File

@@ -52,6 +52,14 @@ class APEv2File(File):
metadata = Metadata()
if file.tags:
for origname, values in file.tags.items():
if origname.lower().startswith("cover art") and values.kind == mutagen.apev2.BINARY:
if '\0' in values.value:
descr, data = values.value.split('\0', 1)
if data.startswith('\xff\xd8\xff\xe0'):
mime = 'image/jpeg'
else:
mime = 'image/png'
metadata.add_image(mime, data)
# skip EXTERNAL and BINARY values
if values.kind != mutagen.apev2.TEXT:
continue
@@ -89,6 +97,10 @@ class APEv2File(File):
tags = mutagen.apev2.APEv2()
if settings["clear_existing_tags"]:
tags.clear()
elif settings['save_images_to_tags']:
for name, value in tags.items():
if name.lower().startswith('cover art') and value.kind == mutagen.apev2.BINARY:
del tags[name]
temp = {}
for name, value in metadata.items():
if name.startswith("~"):
@@ -122,6 +134,16 @@ class APEv2File(File):
temp.setdefault(name, []).append(value)
for name, values in temp.items():
tags[str(name)] = values
if settings['save_images_to_tags']:
for mime, data in metadata.images:
cover_filename = 'Cover Art (Front).'
if mime == 'image/jpeg':
cover_filename += 'jpg'
else:
cover_filename += 'png'
tags['Cover Art (Front)'] = cover_filename + '\0' + data
break # can't save more than one item with the same name
# (mp3tags does this, but it's against the specs)
tags.save(encode_filename(filename))
class MusepackFile(APEv2File):

View File

@@ -49,9 +49,10 @@ def _decamelcase(text):
return re.sub(r'([A-Z])', r' \1', text).strip()
_REPLACE_MAP = {'TurntableS': 'Turntable(s)'}
_EXTRA_ATTRS = ['Guest', 'Additional', 'Minor']
def _parse_attributes(attrs):
attrs = map(_decamelcase, attrs)
attrs = [_decamelcase(_REPLACE_MAP.get(a, a)) for a in attrs]
prefix = ' '.join([a for a in attrs if a in _EXTRA_ATTRS])
attrs = [a for a in attrs if a not in _EXTRA_ATTRS]
if len(attrs) > 1:

View File

@@ -204,6 +204,9 @@ class Tagger(QtGui.QApplication):
def setup_gettext(self, localedir):
"""Setup locales, load translations, install gettext functions."""
if self.config.setting["ui_language"]:
os.environ['LANGUAGE'] = ''
os.environ['LANG'] = self.config.setting["ui_language"]
if sys.platform == "win32":
try:
locale.setlocale(locale.LC_ALL, os.environ["LANG"])

View File

@@ -17,9 +17,12 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from picard.config import BoolOption
from PyQt4 import QtCore, QtGui
from picard.config import BoolOption, TextOption
from picard.ui.options import OptionsPage, register_options_page
from picard.ui.ui_options_interface import Ui_InterfaceOptionsPage
from picard.const import UI_LANGUAGES
import operator
class InterfaceOptionsPage(OptionsPage):
@@ -34,23 +37,39 @@ class InterfaceOptionsPage(OptionsPage):
BoolOption("setting", "toolbar_show_labels", True),
BoolOption("setting", "toolbar_multiselect", False),
BoolOption("setting", "use_adv_search_syntax", False),
TextOption("setting", "ui_language", u""),
]
def __init__(self, parent=None):
super(InterfaceOptionsPage, self).__init__(parent)
self.ui = Ui_InterfaceOptionsPage()
self.ui.setupUi(self)
self.ui.ui_language.addItem(_('System default'), QtCore.QVariant(''))
language_list = [(l[0], l[1], _(l[2])) for l in UI_LANGUAGES]
for lang_code, native, translation in sorted(language_list, key=operator.itemgetter(2)):
if native and native != translation:
name = u'%s (%s)' % (translation, native)
else:
name = translation
self.ui.ui_language.addItem(name, QtCore.QVariant(lang_code))
def load(self):
self.ui.toolbar_show_labels.setChecked(self.config.setting["toolbar_show_labels"])
self.ui.toolbar_multiselect.setChecked(self.config.setting["toolbar_multiselect"])
self.ui.use_adv_search_syntax.setChecked(self.config.setting["use_adv_search_syntax"])
current_ui_language = QtCore.QVariant(self.config.setting["ui_language"])
self.ui.ui_language.setCurrentIndex(self.ui.ui_language.findData(current_ui_language))
def save(self):
self.config.setting["toolbar_show_labels"] = self.ui.toolbar_show_labels.isChecked()
self.config.setting["toolbar_multiselect"] = self.ui.toolbar_multiselect.isChecked()
self.config.setting["use_adv_search_syntax"] = self.ui.use_adv_search_syntax.isChecked()
self.tagger.window.update_toolbar_style()
new_language = self.ui.ui_language.itemData(self.ui.ui_language.currentIndex()).toString()
if new_language != self.config.setting["ui_language"]:
self.config.setting["ui_language"] = self.ui.ui_language.itemData(self.ui.ui_language.currentIndex()).toString()
dialog = QtGui.QMessageBox(QtGui.QMessageBox.Information, _('Language changed'), _('You have changed the interface language. You have to restart Picard in order for the change to take effect.'), QtGui.QMessageBox.Ok, self)
dialog.exec_()
register_options_page(InterfaceOptionsPage)

View File

@@ -49,8 +49,9 @@ class MetadataOptionsPage(OptionsPage):
self.ui.setupUi(self)
self.connect(self.ui.va_name_default, QtCore.SIGNAL("clicked()"), self.set_va_name_default)
self.connect(self.ui.nat_name_default, QtCore.SIGNAL("clicked()"), self.set_nat_name_default)
self.ui.preferred_release_country.addItem(N_("None"), QtCore.QVariant(""))
for country, name in sorted(RELEASE_COUNTRIES.items(), key=operator.itemgetter(1)):
self.ui.preferred_release_country.addItem(_("None"), QtCore.QVariant(""))
country_list = [(c[0], _(c[1])) for c in RELEASE_COUNTRIES.items()]
for country, name in sorted(country_list, key=operator.itemgetter(1)):
self.ui.preferred_release_country.addItem(name, QtCore.QVariant(country))
def load(self):

View File

@@ -2,8 +2,8 @@
# Form implementation generated from reading ui file 'ui/options_interface.ui'
#
# Created: Fri Mar 28 08:55:16 2008
# by: PyQt4 UI code generator 4.3
# Created: Sat Jan 24 18:12:02 2009
# by: PyQt4 UI code generator 4.4.3
#
# WARNING! All changes made in this file will be lost!
@@ -12,32 +12,36 @@ from PyQt4 import QtCore, QtGui
class Ui_InterfaceOptionsPage(object):
def setupUi(self, InterfaceOptionsPage):
InterfaceOptionsPage.setObjectName("InterfaceOptionsPage")
InterfaceOptionsPage.resize(QtCore.QSize(QtCore.QRect(0,0,276,196).size()).expandedTo(InterfaceOptionsPage.minimumSizeHint()))
InterfaceOptionsPage.resize(287, 200)
self.vboxlayout = QtGui.QVBoxLayout(InterfaceOptionsPage)
self.vboxlayout.setObjectName("vboxlayout")
self.groupBox_2 = QtGui.QGroupBox(InterfaceOptionsPage)
self.groupBox_2.setObjectName("groupBox_2")
self.vboxlayout1 = QtGui.QVBoxLayout(self.groupBox_2)
self.vboxlayout1.setObjectName("vboxlayout1")
self.toolbar_show_labels = QtGui.QCheckBox(self.groupBox_2)
self.toolbar_show_labels.setObjectName("toolbar_show_labels")
self.vboxlayout1.addWidget(self.toolbar_show_labels)
self.toolbar_multiselect = QtGui.QCheckBox(self.groupBox_2)
self.toolbar_multiselect.setObjectName("toolbar_multiselect")
self.vboxlayout1.addWidget(self.toolbar_multiselect)
self.use_adv_search_syntax = QtGui.QCheckBox(self.groupBox_2)
self.use_adv_search_syntax.setObjectName("use_adv_search_syntax")
self.vboxlayout1.addWidget(self.use_adv_search_syntax)
self.label = QtGui.QLabel(self.groupBox_2)
self.label.setObjectName("label")
self.vboxlayout1.addWidget(self.label)
self.horizontalLayout = QtGui.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.ui_language = QtGui.QComboBox(self.groupBox_2)
self.ui_language.setObjectName("ui_language")
self.horizontalLayout.addWidget(self.ui_language)
spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem)
self.vboxlayout1.addLayout(self.horizontalLayout)
self.vboxlayout.addWidget(self.groupBox_2)
spacerItem = QtGui.QSpacerItem(220,61,QtGui.QSizePolicy.Minimum,QtGui.QSizePolicy.Expanding)
self.vboxlayout.addItem(spacerItem)
spacerItem1 = QtGui.QSpacerItem(220, 61, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.vboxlayout.addItem(spacerItem1)
self.retranslateUi(InterfaceOptionsPage)
QtCore.QMetaObject.connectSlotsByName(InterfaceOptionsPage)
@@ -47,4 +51,5 @@ class Ui_InterfaceOptionsPage(object):
self.toolbar_show_labels.setText(_("Show text labels under icons"))
self.toolbar_multiselect.setText(_("Allow selection of multiple directories"))
self.use_adv_search_syntax.setText(_("Use advanced query syntax"))
self.label.setText(_("User interface language:"))

2417
po/ca.po

File diff suppressed because it is too large Load Diff

2764
po/cs.po

File diff suppressed because it is too large Load Diff

2437
po/cy.po

File diff suppressed because it is too large Load Diff

3013
po/da.po

File diff suppressed because it is too large Load Diff

2987
po/de.po

File diff suppressed because it is too large Load Diff

3097
po/en.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2975
po/es.po

File diff suppressed because it is too large Load Diff

2451
po/fa.po

File diff suppressed because it is too large Load Diff

3022
po/fi.po

File diff suppressed because it is too large Load Diff

3009
po/fr.po

File diff suppressed because it is too large Load Diff

2643
po/fy.po

File diff suppressed because it is too large Load Diff

2743
po/he.po

File diff suppressed because it is too large Load Diff

2595
po/hu.po

File diff suppressed because it is too large Load Diff

2633
po/is.po

File diff suppressed because it is too large Load Diff

2904
po/it.po

File diff suppressed because it is too large Load Diff

2466
po/kn.po

File diff suppressed because it is too large Load Diff

2598
po/ko.po

File diff suppressed because it is too large Load Diff

2469
po/lt.po

File diff suppressed because it is too large Load Diff

2863
po/nb.po

File diff suppressed because it is too large Load Diff

3013
po/nl.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2926
po/pl.po

File diff suppressed because it is too large Load Diff

2756
po/pt.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2951
po/ro.po

File diff suppressed because it is too large Load Diff

2939
po/ru.po

File diff suppressed because it is too large Load Diff

2445
po/sco.po

File diff suppressed because it is too large Load Diff

2739
po/sk.po

File diff suppressed because it is too large Load Diff

2733
po/sl.po

File diff suppressed because it is too large Load Diff

2904
po/sv.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -5,8 +5,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>276</width>
<height>196</height>
<width>287</width>
<height>200</height>
</rect>
</property>
<layout class="QVBoxLayout" >
@@ -37,6 +37,33 @@
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label" >
<property name="text" >
<string>User interface language:</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout" >
<item>
<widget class="QComboBox" name="ui_language" />
</item>
<item>
<spacer name="horizontalSpacer" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</item>
@@ -45,7 +72,7 @@
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<property name="sizeHint" stdset="0" >
<size>
<width>220</width>
<height>61</height>