Passed
Push — master ( 694e2f...150a8e )
by Dean
09:10 queued 06:18
created

Environment.setup_translation()   D

Complexity

Conditions 8

Size

Total Lines 44

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 65.1556

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 44
ccs 1
cts 27
cp 0.037
rs 4
cc 8
crap 65.1556
1 1
from plugin.core.constants import PLUGIN_IDENTIFIER
2
3 1
import gettext
4 1
import locale
5 1
import logging
6 1
import os
7 1
import platform
8
9 1
DEFAULT_LOCALE = 'en_US'
10
11 1
log = logging.getLogger(__name__)
12
13
14 1
class PathEnvironment(object):
15
    # TODO confirm validity of this on *nix and OS X
16
17 1
    def __init__(self, core):
18 1
        self._core = core
19
20 1
        self._plugin_support = None
21
22 1
    @property
23
    def contents(self):
24 1
        return os.path.abspath(os.path.join(self.code, '..'))
25
26 1
    @property
27
    def code(self):
28 1
        return self._core.code_path
29
30 1
    @property
31
    def libraries(self):
32 1
        return os.path.join(self.contents, 'Libraries')
33
34 1
    @property
35
    def locale(self):
36
        return os.path.join(self.contents, 'Locale')
37
38 1
    @property
39
    def plugin_caches(self):
40 1
        return os.path.join(self.plugin_support, 'Caches', PLUGIN_IDENTIFIER)
41
42 1
    @property
43
    def plugin_data(self):
44 1
        return os.path.join(self.plugin_support, 'Data', PLUGIN_IDENTIFIER)
45
46 1
    @property
47
    def plugin_database(self):
48 1
        return os.path.join(self.plugin_support, 'Databases', '%s.db' % PLUGIN_IDENTIFIER)
49
50 1
    @property
51
    def plugin_support(self):
52 1
        if self._plugin_support is not None:
53 1
            return self._plugin_support
54
55
        base_path = self.code[:self.code.index(os.path.sep + 'Plug-ins')]
56
57
        return os.path.join(base_path, 'Plug-in Support')
58
59 1
    @plugin_support.setter
60
    def plugin_support(self, path):
61 1
        self._plugin_support = path
62
63
64 1
class PlatformEnvironment(object):
65 1
    def __init__(self, platform):
66 1
        self._platform = platform
67
68 1
    @property
69
    def machine_identifier(self):
70
        return self._platform.MachineIdentifier
71
72 1
    @property
73
    def server_version(self):
74
        return self._platform.ServerVersion
75
76
77 1
class Environment(object):
78 1
    dict = None
79 1
    path = None
80 1
    platform = None
81 1
    prefs = None
82
83 1
    language = None
84 1
    translation = None
85
86 1
    @classmethod
87
    def setup(cls, core, dict, platform, prefs):
88 1
        cls.path = PathEnvironment(core)
89 1
        cls.dict = dict
90 1
        cls.platform = PlatformEnvironment(platform)
91 1
        cls.prefs = prefs
92
93 1
    @classmethod
94
    def setup_locale(cls):
95
        # Use language defined in preferences (if available)
96
        language = cls.get_pref('language') or ''
97
98
        # Initialize locale
99
        try:
100
            locale.setlocale(locale.LC_ALL, language)
101
        except Exception, ex:
102
            log.warn('Unable to set locale: %s', ex, exc_info=True)
103
            return False
104
105
        # Default to the "en_US" locale
106
        code, _ = locale.getlocale()
107
108
        if not code:
109
            locale.setlocale(locale.LC_ALL, DEFAULT_LOCALE)
110
111
        log.info('Using locale: %r', locale.getlocale())
112
        return True
113
114 1
    @classmethod
115
    def setup_translation(cls):
116
        # Retrieve preferred language
117
        try:
118
            cls.language = cls._get_language()
119
        except Exception, ex:
120
            log.warn('Unable to retrieve preferred language: %s', ex, exc_info=True)
121
            cls.language = None
122
            return
123
124
        if not cls.language:
125
            log.warn('Unable to determine preferred language (system: %r)', platform.system())
126
            return
127
128
        # Build list of languages
129
        languages = [cls.language]
130
131
        if '_' in cls.language:
132
            languages.append(cls.language.split('_', 1)[0])
133
134
        # Check if language exists
135
        found = False
136
137
        for lang in languages:
138
            if os.path.exists(os.path.join(cls.path.locale, lang)):
139
                found = True
140
                break
141
142
        if not found:
143
            log.info('No translation available for %r', languages)
144
            return
145
146
        # Setup gettext
147
        try:
148
            cls.translation = gettext.translation(
149
                domain='channel',
150
                localedir=os.path.join(cls.path.locale),
151
                languages=languages
152
            )
153
        except Exception, ex:
154
            log.warn('Unable to initialize languages: %r - %s', languages, ex, exc_info=True)
155
            return
156
157
        log.info('Using languages: %r (translation: %r)', languages, cls.translation)
158
159 1
    @classmethod
160
    def get_pref(cls, key):
161 1
        try:
162 1
            return cls.prefs[key]
163
        except:
164
            return None
165
166 1
    @classmethod
167
    def _get_language(cls):
168
        # Use language defined in preferences (if available)
169
        language = cls.get_pref('language')
170
171
        if language:
172
            return language.lower()
173
174
        # Use system language
175
        if platform.system() == 'Windows':
176
            # Retrieve windows user language
177
            return cls._get_windows_default_language()
178
179
        # Retrieve current locale
180
        code, _ = locale.getdefaultlocale()
181
182
        # Ensure language code is valid
183
        if not code or type(code) is not str:
184
            log.info('Unable to detect system language, defaulting to the "%s" locale', DEFAULT_LOCALE)
185
            return DEFAULT_LOCALE.lower()
186
187
        # Parse language code
188
        if len(code) == 2:
189
            return code.lower()
190
        elif len(code) > 2 and code[2] == '_':
191
            return code[:5].lower()
192
193
        log.warn('Unknown language code: %r', code)
194
        return None
195
196 1
    @classmethod
197
    def _get_windows_default_language(cls):
198
        try:
199
            import ctypes
200
            lang_id = ctypes.windll.kernel32.GetUserDefaultUILanguage()
201
        except Exception, ex:
202
            log.warn('Unable to determine preferred language: %s', ex, exc_info=True)
203
            return None
204
205
        if lang_id not in locale.windows_locale:
206
            log.warn('Unknown language: %r', lang_id)
207
            return None
208
209
        return locale.windows_locale[lang_id].lower()
210
211
212 1
def translate(message):
213 1
    if Environment.translation:
214
        return Environment.translation.ugettext(message)
215
216
    return message
217