mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Open with: On Linux when reading names from .desktop files, use the first matching language
Fixes #1901276 [Name of Gnome Image viewer not visible in the Open cover with dialog](https://bugs.launchpad.net/calibre/+bug/1901276)
This commit is contained in:
parent
723fbbbd80
commit
0bb47ed9fe
@ -13,16 +13,14 @@ from calibre.constants import filesystem_encoding, cache_dir
|
|||||||
from calibre.utils.icu import numeric_sort_key as sort_key
|
from calibre.utils.icu import numeric_sort_key as sort_key
|
||||||
from calibre.utils.localization import canonicalize_lang, get_lang
|
from calibre.utils.localization import canonicalize_lang, get_lang
|
||||||
from calibre.utils.serialize import msgpack_dumps, msgpack_loads
|
from calibre.utils.serialize import msgpack_dumps, msgpack_loads
|
||||||
from polyglot.builtins import iteritems, itervalues, string_or_bytes, unicode_type
|
from polyglot.builtins import iteritems, itervalues, string_or_bytes
|
||||||
|
|
||||||
|
|
||||||
def parse_localized_key(key):
|
def parse_localized_key(key):
|
||||||
name, rest = key.partition('[')[0::2]
|
name, rest = key.partition('[')[0::2]
|
||||||
if not rest:
|
if not rest:
|
||||||
return name, None
|
return name, None
|
||||||
rest = rest[:-1]
|
return name, rest[:-1]
|
||||||
lang = re.split(r'[_.@]', rest)[0]
|
|
||||||
return name, canonicalize_lang(lang)
|
|
||||||
|
|
||||||
|
|
||||||
def unquote_exec(val):
|
def unquote_exec(val):
|
||||||
@ -30,6 +28,10 @@ def unquote_exec(val):
|
|||||||
return shlex.split(val)
|
return shlex.split(val)
|
||||||
|
|
||||||
|
|
||||||
|
def known_localized_items():
|
||||||
|
return {'Name': {}, 'GenericName': {}, 'Comment': {}, 'Icon': {}}
|
||||||
|
|
||||||
|
|
||||||
def parse_desktop_file(path):
|
def parse_desktop_file(path):
|
||||||
gpat = re.compile(r'^\[(.+?)\]\s*$')
|
gpat = re.compile(r'^\[(.+?)\]\s*$')
|
||||||
kpat = re.compile(r'^([-a-zA-Z0-9\[\]@_.]+)\s*=\s*(.+)$')
|
kpat = re.compile(r'^([-a-zA-Z0-9\[\]@_.]+)\s*=\s*(.+)$')
|
||||||
@ -41,6 +43,7 @@ def parse_desktop_file(path):
|
|||||||
group = None
|
group = None
|
||||||
ans = {}
|
ans = {}
|
||||||
ans['desktop_file_path'] = path
|
ans['desktop_file_path'] = path
|
||||||
|
localized_items = known_localized_items()
|
||||||
for line in raw.splitlines():
|
for line in raw.splitlines():
|
||||||
m = gpat.match(line)
|
m = gpat.match(line)
|
||||||
if m is not None:
|
if m is not None:
|
||||||
@ -62,15 +65,17 @@ def parse_desktop_file(path):
|
|||||||
ans[k] = cmdline
|
ans[k] = cmdline
|
||||||
elif k == 'MimeType':
|
elif k == 'MimeType':
|
||||||
ans[k] = frozenset(x.strip() for x in v.split(';'))
|
ans[k] = frozenset(x.strip() for x in v.split(';'))
|
||||||
elif k in {'Name', 'GenericName', 'Comment', 'Icon'} or '[' in k:
|
elif k in localized_items or '[' in k:
|
||||||
name, lang = parse_localized_key(k)
|
name, lang = parse_localized_key(k)
|
||||||
if name not in ans:
|
vals = localized_items.setdefault(name, {})
|
||||||
ans[name] = {}
|
vals[lang] = v
|
||||||
if isinstance(ans[name], unicode_type):
|
if name in ans:
|
||||||
ans[name] = {None:ans[name]}
|
vals[None] = ans.pop(name)
|
||||||
ans[name][lang] = v
|
|
||||||
else:
|
else:
|
||||||
ans[k] = v
|
ans[k] = v
|
||||||
|
for k, vals in localized_items.items():
|
||||||
|
if vals:
|
||||||
|
ans[k] = dict(vals)
|
||||||
if 'Exec' in ans and 'MimeType' in ans and 'Name' in ans:
|
if 'Exec' in ans and 'MimeType' in ans and 'Name' in ans:
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
@ -168,7 +173,32 @@ def find_icons():
|
|||||||
|
|
||||||
def localize_string(data):
|
def localize_string(data):
|
||||||
lang = canonicalize_lang(get_lang())
|
lang = canonicalize_lang(get_lang())
|
||||||
return data.get(lang, data.get(None)) or ''
|
|
||||||
|
def key_matches(key):
|
||||||
|
if key is None:
|
||||||
|
return True
|
||||||
|
base = re.split(r'[_.@]', key)[0]
|
||||||
|
return canonicalize_lang(base) == lang
|
||||||
|
|
||||||
|
matches = tuple(filter(key_matches, data))
|
||||||
|
return data[matches[0]] if matches else ''
|
||||||
|
|
||||||
|
|
||||||
|
def process_desktop_file(data):
|
||||||
|
icon = data.get('Icon', {}).get(None)
|
||||||
|
if icon and not os.path.isabs(icon):
|
||||||
|
icon = find_icons().get(icon)
|
||||||
|
if icon:
|
||||||
|
data['Icon'] = icon
|
||||||
|
else:
|
||||||
|
data.pop('Icon')
|
||||||
|
if not isinstance(data.get('Icon'), string_or_bytes):
|
||||||
|
data.pop('Icon', None)
|
||||||
|
for k in ('Name', 'GenericName', 'Comment'):
|
||||||
|
val = data.get(k)
|
||||||
|
if val:
|
||||||
|
data[k] = localize_string(val)
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
def find_programs(extensions):
|
def find_programs(extensions):
|
||||||
@ -194,20 +224,7 @@ def find_programs(extensions):
|
|||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
continue
|
continue
|
||||||
if data is not None and mime_types.intersection(data['MimeType']):
|
if data is not None and mime_types.intersection(data['MimeType']):
|
||||||
icon = data.get('Icon', {}).get(None)
|
ans.append(process_desktop_file(data))
|
||||||
if icon and not os.path.isabs(icon):
|
|
||||||
icon = find_icons().get(icon)
|
|
||||||
if icon:
|
|
||||||
data['Icon'] = icon
|
|
||||||
else:
|
|
||||||
data.pop('Icon')
|
|
||||||
if not isinstance(data.get('Icon'), string_or_bytes):
|
|
||||||
data.pop('Icon', None)
|
|
||||||
for k in ('Name', 'GenericName', 'Comment'):
|
|
||||||
val = data.get(k)
|
|
||||||
if val:
|
|
||||||
data[k] = localize_string(val)
|
|
||||||
ans.append(data)
|
|
||||||
ans.sort(key=lambda d:sort_key(d.get('Name')))
|
ans.sort(key=lambda d:sort_key(d.get('Name')))
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user