Passed
Push — master ( 150a8e...ce647f )
by Dean
02:55
created

Environment.setup_locale()   B

Complexity

Conditions 4

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 17.1835

Importance

Changes 4
Bugs 0 Features 0
Metric Value
c 4
b 0
f 0
dl 0
loc 24
ccs 1
cts 16
cp 0.0625
rs 8.6845
cc 4
crap 17.1835
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
            try:
110
                locale.setlocale(locale.LC_ALL, DEFAULT_LOCALE)
111
            except Exception, ex:
112
                log.warn('Unable to set locale: %s', ex, exc_info=True)
113
                return False
114
115
        log.info('Using locale: %r', locale.getlocale())
116
        return True
117
118 1
    @classmethod
119
    def setup_translation(cls):
120
        # Retrieve preferred language
121
        try:
122
            cls.language = cls._get_language()
123
        except Exception, ex:
124
            log.warn('Unable to retrieve preferred language: %s', ex, exc_info=True)
125
            cls.language = None
126
            return
127
128
        if not cls.language:
129
            log.warn('Unable to determine preferred language (system: %r)', platform.system())
130
            return
131
132
        # Build list of languages
133
        languages = [cls.language]
134
135
        if '_' in cls.language:
136
            languages.append(cls.language.split('_', 1)[0])
137
138
        # Check if language exists
139
        found = False
140
141
        for lang in languages:
142
            if os.path.exists(os.path.join(cls.path.locale, lang)):
143
                found = True
144
                break
145
146
        if not found:
147
            log.info('No translation available for %r', languages)
148
            return
149
150
        # Setup gettext
151
        try:
152
            cls.translation = gettext.translation(
153
                domain='channel',
154
                localedir=os.path.join(cls.path.locale),
155
                languages=languages
156
            )
157
        except Exception, ex:
158
            log.warn('Unable to initialize languages: %r - %s', languages, ex, exc_info=True)
159
            return
160
161
        log.info('Using languages: %r (translation: %r)', languages, cls.translation)
162
163 1
    @classmethod
164
    def get_pref(cls, key):
165 1
        try:
166 1
            return cls.prefs[key]
167
        except:
168
            return None
169
170 1
    @classmethod
171
    def _get_language(cls):
172
        # Use language defined in preferences (if available)
173
        language = cls.get_pref('language')
174
175
        if language:
176
            return language.lower()
177
178
        # Use system language
179
        if platform.system() == 'Windows':
180
            # Retrieve windows user language
181
            return cls._get_windows_default_language()
182
183
        # Retrieve current locale
184
        code, _ = locale.getdefaultlocale()
185
186
        # Ensure language code is valid
187
        if not code or type(code) is not str:
188
            log.info('Unable to detect system language, defaulting to the "%s" locale', DEFAULT_LOCALE)
189
            return DEFAULT_LOCALE.lower()
190
191
        # Parse language code
192
        if len(code) == 2:
193
            return code.lower()
194
        elif len(code) > 2 and code[2] == '_':
195
            return code[:5].lower()
196
197
        log.warn('Unknown language code: %r', code)
198
        return None
199
200 1
    @classmethod
201
    def _get_windows_default_language(cls):
202
        try:
203
            import ctypes
204
            lang_id = ctypes.windll.kernel32.GetUserDefaultUILanguage()
205
        except Exception, ex:
206
            log.warn('Unable to determine preferred language: %s', ex, exc_info=True)
207
            return None
208
209
        if lang_id not in locale.windows_locale:
210
            log.warn('Unknown language: %r', lang_id)
211
            return None
212
213
        return locale.windows_locale[lang_id].lower()
214
215
216 1
def translate(message):
217 1
    if Environment.translation:
218
        return Environment.translation.ugettext(message)
219
220
    return message
221