Merge pull request #1391 from davvid/macos/hotkeys
[git-cola.git] / cola / i18n.py
blobb44c251604a826dee2f2de0788eba674378ad1b4
1 """i18n and l10n support for git-cola"""
2 import locale
3 import os
5 try:
6 import polib
7 except ImportError:
8 from . import polib
9 import sys
11 from . import core
12 from . import resources
15 class NullTranslation:
16 """This is a pass-through object that does nothing"""
18 def gettext(self, value):
19 return value
22 class State:
23 """The application-wide current translation state"""
25 translation = NullTranslation()
27 @classmethod
28 def reset(cls):
29 cls.translation = NullTranslation()
31 @classmethod
32 def update(cls, lang):
33 cls.translation = Translation(lang)
35 @classmethod
36 def gettext(cls, value):
37 """Return a translated value"""
38 return cls.translation.gettext(value)
41 class Translation:
42 def __init__(self, lang):
43 self.lang = lang
44 self.messages = {}
45 self.filename = get_filename_for_locale(lang)
46 if self.filename:
47 self.load()
49 def load(self):
50 """Read the .po file content into memory"""
51 po = polib.pofile(self.filename, encoding='utf-8')
52 messages = self.messages
53 for entry in po.translated_entries():
54 messages[entry.msgid] = entry.msgstr
56 def gettext(self, value):
57 return self.messages.get(value, value)
60 def gettext(value):
61 """Translate a string"""
62 txt = State.gettext(value)
63 # handle @@verb / @@noun
64 if txt[-6:-4] == '@@':
65 txt = txt.replace('@@verb', '').replace('@@noun', '')
66 return txt
69 def N_(value):
70 """Marker function for translated values
72 N_("Some string value") is used to mark strings for translation.
73 """
74 return gettext(value)
77 def get_filename_for_locale(name):
78 """Return the .po file for the specified locale"""
79 # When <name> is "foo_BAR.UTF-8", the name is truncated to "foo_BAR".
80 # When <name> is "foo_BAR", the <short_name> is "foo"
81 # Try the following locations:
82 # cola/i18n/<name>.po
83 # cola/i18n/<short_name>.po
84 if not name: # If no locale was specified then try the current locale.
85 name = locale.getdefaultlocale()[0]
87 if not name:
88 return None
90 name = name.split('.', 1)[0] # foo_BAR.UTF-8 -> foo_BAR
92 filename = resources.i18n('%s.po' % name)
93 if os.path.exists(filename):
94 return filename
96 short_name = name.split('_', 1)[0]
97 filename = resources.i18n('%s.po' % short_name)
98 if os.path.exists(filename):
99 return filename
100 return None
103 def install(lang):
104 if sys.platform == 'win32' and not lang:
105 lang = _get_win32_default_locale()
106 lang = _install_custom_language(lang)
107 State.update(lang)
110 def uninstall():
111 State.reset()
114 def _install_custom_language(lang):
115 """Allow a custom language to be set in ~/.config/git-cola/language"""
116 lang_file = resources.config_home('language')
117 if not core.exists(lang_file):
118 return lang
119 try:
120 lang = core.read(lang_file).strip()
121 except OSError:
122 return lang
123 return lang
126 def _get_win32_default_locale():
127 """Get the default locale on Windows"""
128 for name in ('LANGUAGE', 'LC_ALL', 'LC_MESSAGES', 'LANG'):
129 lang = os.environ.get(name)
130 if lang:
131 return lang
132 try:
133 import ctypes
134 except ImportError:
135 # use only user's default locale
136 return locale.getdefaultlocale()[0]
137 # using ctypes to determine all locales
138 lcid_user = ctypes.windll.kernel32.GetUserDefaultLCID()
139 lcid_system = ctypes.windll.kernel32.GetSystemDefaultLCID()
140 lang_user = locale.windows_locale.get(lcid_user)
141 lang_system = locale.windows_locale.get(lcid_system)
142 if lang_user:
143 lang = lang_user
144 else:
145 lang = lang_system
146 return lang