widgets.remote: retain focus when showing remote messages
[git-cola.git] / cola / i18n.py
blobfdc5ea1b3a104179bf5bbb942a227aea2b484396
1 """i18n and l10n support for git-cola"""
2 import locale
3 import os
4 import sys
6 from . import core
7 from . import polib
8 from . import resources
11 class NullTranslation:
12 """This is a pass-through object that does nothing"""
14 def gettext(self, value):
15 return value
18 class State:
19 """The application-wide current translation state"""
21 translation = NullTranslation()
23 @classmethod
24 def reset(cls):
25 cls.translation = NullTranslation()
27 @classmethod
28 def update(cls, lang):
29 cls.translation = Translation(lang)
31 @classmethod
32 def gettext(cls, value):
33 """Return a translated value"""
34 return cls.translation.gettext(value)
37 class Translation:
38 def __init__(self, lang):
39 self.lang = lang
40 self.messages = {}
41 self.filename = get_filename_for_locale(lang)
42 if self.filename:
43 self.load()
45 def load(self):
46 """Read the pofile content into memory"""
47 po = polib.pofile(self.filename, encoding='utf-8')
48 messages = self.messages
49 for entry in po.translated_entries():
50 messages[entry.msgid] = entry.msgstr
52 def gettext(self, value):
53 return self.messages.get(value, value)
56 def gettext(value):
57 """Translate a string"""
58 txt = State.gettext(value)
59 # handle @@verb / @@noun
60 if txt[-6:-4] == '@@':
61 txt = txt.replace('@@verb', '').replace('@@noun', '')
62 return txt
65 def N_(value):
66 """Marker function for translated values
68 N_("Some string value") is used to mark strings for translation.
69 """
70 return gettext(value)
73 def get_filename_for_locale(name):
74 """Return the .po file for the specified locale"""
75 # When <name> is "foo_BAR.UTF-8", the name is truncated to "foo_BAR".
76 # When <name> is "foo_BAR", the <short_name> is "foo"
77 # Try the following locations:
78 # cola/i18n/<name>.po
79 # cola/i18n/<short_name>.po
80 if not name: # If no locale was specified then try the current locale.
81 name = locale.getdefaultlocale()[0]
83 if not name:
84 return None
86 name = name.split('.', 1)[0] # foo_BAR.UTF-8 -> foo_BAR
88 filename = resources.i18n('%s.po' % name)
89 if os.path.exists(filename):
90 return filename
92 short_name = name.split('_', 1)[0]
93 filename = resources.i18n('%s.po' % short_name)
94 if os.path.exists(filename):
95 return filename
96 return None
99 def install(lang):
100 # pylint: disable=global-statement
101 if sys.platform == 'win32' and not lang:
102 lang = _get_win32_default_locale()
103 lang = _install_custom_language(lang)
104 State.update(lang)
107 def uninstall():
108 # pylint: disable=global-statement
109 State.reset()
112 def _install_custom_language(lang):
113 """Allow a custom language to be set in ~/.config/git-cola/language"""
114 lang_file = resources.config_home('language')
115 if not core.exists(lang_file):
116 return lang
117 try:
118 lang = core.read(lang_file).strip()
119 except OSError:
120 return lang
121 return lang
124 def _get_win32_default_locale():
125 """Get the default locale on Windows"""
126 for name in ('LANGUAGE', 'LC_ALL', 'LC_MESSAGES', 'LANG'):
127 lang = os.environ.get(name)
128 if lang:
129 return lang
130 try:
131 import ctypes # pylint: disable=all
132 except ImportError:
133 # use only user's default locale
134 return locale.getdefaultlocale()[0]
135 # using ctypes to determine all locales
136 lcid_user = ctypes.windll.kernel32.GetUserDefaultLCID()
137 lcid_system = ctypes.windll.kernel32.GetSystemDefaultLCID()
138 lang_user = locale.windows_locale.get(lcid_user)
139 lang_system = locale.windows_locale.get(lcid_system)
140 if lang_user:
141 lang = lang_user
142 else:
143 lang = lang_system
144 return lang