summaryrefslogtreecommitdiffstats
path: root/deluge/i18n/util.py
blob: 81530c2eeab804b82fab7aed1046e9b200799633 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007,2008 Andrew Resch <andrewresch@gmail.com>
#
# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with
# the additional special exception to link portions of this program with the OpenSSL library.
# See LICENSE for more details.
#

from __future__ import unicode_literals

import ctypes
import gettext
import locale
import logging
import os
import sys
from glob import glob

from six.moves import builtins

import deluge.common

from .languages import LANGUAGES

log = logging.getLogger(__name__)

I18N_DOMAIN = 'deluge'


def get_translations_path():
    """Get the absolute path to the directory containing translation files"""
    return deluge.common.resource_filename('deluge', 'i18n')


def get_languages():
    lang = []

    translations_path = get_translations_path()
    lc_messages_path = os.path.join('LC_MESSAGES', I18N_DOMAIN + '.mo')
    for root, dirs, files in os.walk(translations_path):
        # Get the dirs
        lang_dirs = [
            lang_dir
            for lang_dir in dirs
            if glob(os.path.join(translations_path, lang_dir, lc_messages_path))
        ]
        break
    else:
        return lang

    for i, lang_code in enumerate(lang_dirs):
        name = '%s (Language name missing)' % lang_code
        if lang_code in LANGUAGES:
            name = LANGUAGES[lang_code]
        lang.append([lang_code, _(name)])

    lang = sorted(lang, key=lambda l: l[1])
    return lang


def set_language(lang):
    """
    Set the language to use.

    gettext and GtkBuilder will load the translations from the specified
    language.

    :param lang: the language, e.g. "en", "de" or "en_GB"
    :type lang: str
    """
    # Necessary to set these environment variables for GtkBuilder
    deluge.common.set_env_variable('LANGUAGE', lang)  # Windows/Linux
    deluge.common.set_env_variable('LANG', lang)  # For OSX

    translations_path = get_translations_path()
    try:
        ro = gettext.translation(
            'deluge', localedir=translations_path, languages=[lang]
        )
        ro.install()
    except IOError as ex:
        log.warning('IOError when loading translations: %s', ex)


def setup_mock_translation(warn_msg=None):
    def _func(*txt):
        if warn_msg:
            log.warning(
                '"%s" has been marked for translation, but translation is unavailable.',
                txt[0],
            )
        return txt[0]

    builtins.__dict__['_'] = _func
    builtins.__dict__['ngettext'] = builtins.__dict__['_n'] = _func


# Initialize gettext
def setup_translation():
    translations_path = get_translations_path()
    log.info('Setting up translations from %s', translations_path)

    try:
        if hasattr(locale, 'bindtextdomain'):
            locale.bindtextdomain(I18N_DOMAIN, translations_path)
        if hasattr(locale, 'textdomain'):
            locale.textdomain(I18N_DOMAIN)

        gettext.bindtextdomain(I18N_DOMAIN, translations_path)
        gettext.textdomain(I18N_DOMAIN)

        # Workaround for Python 2 unicode gettext (keyword removed in Py3).
        kwargs = {} if not deluge.common.PY2 else {'unicode': True}

        gettext.install(I18N_DOMAIN, translations_path, names=['ngettext'], **kwargs)
        builtins.__dict__['_n'] = builtins.__dict__['ngettext']

        def load_libintl(libintls):
            errors = []
            for library in libintls:
                try:
                    libintl = ctypes.cdll.LoadLibrary(library)
                except OSError as ex:
                    errors.append(ex)
                else:
                    break

            if not libintl:
                log.debug(
                    'Unable to initialize gettext/locale:\n  %s', '\n  '.join(errors)
                )
                setup_mock_translation()
                return

            return libintl

        libintl = None
        if deluge.common.windows_check():
            libintl = load_libintl(['libintl-8.dll', 'intl.dll'])
        elif deluge.common.osx_check():
            libintl = load_libintl(['libintl.8.dylib', 'libintl.dylib'])

        if libintl:
            libintl.bindtextdomain(
                I18N_DOMAIN, translations_path.encode(sys.getfilesystemencoding())
            )
            libintl.textdomain(I18N_DOMAIN)
            libintl.gettext.restype = ctypes.c_char_p

    except Exception as ex:
        log.error('Unable to initialize gettext/locale!')
        log.exception(ex)
        setup_mock_translation()

    deluge.common.translate_size_units()