~bzr-pqm/bzr/bzr.dev

5875.2.1 by INADA Naoki
Add bzrlib.i18n module.
1
# -*- coding: utf-8 -*-
2
#
3
# Copyright (C) 2007 Lukáš Lalinský <lalinsky@gmail.com>
4
# Copyright (C) 2007,2009 Alexander Belchenko <bialix@ukr.net>
5
# Copyright (C) 2011 Canonical Ltd
6
#
5875.2.11 by Vincent Ladeuil
Slightly different wrapping of the GPL header broke test_source :-/
7
# This program is free software; you can redistribute it and/or modify
8
# it under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 2 of the License, or
10
# (at your option) any later version.
5875.2.1 by INADA Naoki
Add bzrlib.i18n module.
11
#
12
# This program is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with this program; if not, write to the Free Software
5875.2.11 by Vincent Ladeuil
Slightly different wrapping of the GPL header broke test_source :-/
19
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
5875.2.1 by INADA Naoki
Add bzrlib.i18n module.
20
21
# This module is copied from Bazaar Explorer and modified for bzr.
22
23
"""i18n and l10n support for Bazaar."""
24
25
import gettext as _gettext
26
import os
27
import sys
28
6162.4.7 by Jonathan Riddell
two empty lines between top level items
29
6133.3.10 by Jonathan Riddell
default _translations back to None so we can tell if it gets installed
30
_translations = None
5875.2.1 by INADA Naoki
Add bzrlib.i18n module.
31
32
5875.2.7 by INADA Naoki
Change order of functions.
33
def gettext(message):
34
    """Translate message. 
5875.2.9 by Vincent Ladeuil
Cleanup some PEP8 issues and move test code in test module, test_multiline still failing.
35
    
36
    :returns: translated message as unicode.
37
    """
6131.2.1 by Jonathan Riddell
install translations whenever they are used
38
    install()
5875.3.25 by Vincent Ladeuil
Fix test failures and make sure we don't rely on a default translation.
39
    return _translations.ugettext(message)
5875.2.7 by INADA Naoki
Change order of functions.
40
5875.2.9 by Vincent Ladeuil
Cleanup some PEP8 issues and move test code in test module, test_multiline still failing.
41
5971.1.24 by Jonathan Riddell
fix translations for plural forms
42
def ngettext(singular, plural, number):
43
    """Translate message with plural forms based on `number`.
44
45
    :param singular: English language message in singular form
46
    :param plural: English language message in plural form
47
    :param number: the number this message should be translated for
5875.2.9 by Vincent Ladeuil
Cleanup some PEP8 issues and move test code in test module, test_multiline still failing.
48
49
    :returns: translated message as unicode.
50
    """
6131.2.1 by Jonathan Riddell
install translations whenever they are used
51
    install()
5971.1.77 by Jonathan Riddell
merge in trunk
52
    return _translations.ungettext(singular, plural, number)
5875.2.7 by INADA Naoki
Change order of functions.
53
5875.2.9 by Vincent Ladeuil
Cleanup some PEP8 issues and move test code in test module, test_multiline still failing.
54
5875.2.7 by INADA Naoki
Change order of functions.
55
def N_(msg):
56
    """Mark message for translation but don't translate it right away."""
57
    return msg
58
5875.2.9 by Vincent Ladeuil
Cleanup some PEP8 issues and move test code in test module, test_multiline still failing.
59
5875.2.7 by INADA Naoki
Change order of functions.
60
def gettext_per_paragraph(message):
61
    """Translate message per paragraph.
62
5875.2.9 by Vincent Ladeuil
Cleanup some PEP8 issues and move test code in test module, test_multiline still failing.
63
    :returns: concatenated translated message as unicode.
64
    """
6133.3.14 by Jonathan Riddell
install() translations for per_paragraph too
65
    install()
5875.2.7 by INADA Naoki
Change order of functions.
66
    paragraphs = message.split(u'\n\n')
5875.3.25 by Vincent Ladeuil
Fix test failures and make sure we don't rely on a default translation.
67
    ugettext = _translations.ugettext
5875.2.7 by INADA Naoki
Change order of functions.
68
    # Be careful not to translate the empty string -- it holds the
69
    # meta data of the .po file.
70
    return u'\n\n'.join(ugettext(p) if p else u'' for p in paragraphs)
71
72
6131.2.3 by Jonathan Riddell
rename to disable_i18n() to follow convention
73
def disable_i18n():
6131.2.2 by Jonathan Riddell
add disableI18n() function so bzrlib users can chose not to use i18n
74
    """Do not allow i18n to be enabled.  Useful for third party users
75
    of bzrlib."""
6133.3.13 by Jonathan Riddell
vila sorts it out, fix disable_i18n() and use it in tests.__init__
76
    global _translations
6133.3.10 by Jonathan Riddell
default _translations back to None so we can tell if it gets installed
77
    _translations = _gettext.NullTranslations()
6131.2.2 by Jonathan Riddell
add disableI18n() function so bzrlib users can chose not to use i18n
78
6133.3.13 by Jonathan Riddell
vila sorts it out, fix disable_i18n() and use it in tests.__init__
79
5875.3.25 by Vincent Ladeuil
Fix test failures and make sure we don't rely on a default translation.
80
def installed():
6133.3.10 by Jonathan Riddell
default _translations back to None so we can tell if it gets installed
81
    """Returns whether translations are in use or not."""
82
    return _translations is not None
5875.3.25 by Vincent Ladeuil
Fix test failures and make sure we don't rely on a default translation.
83
84
5875.2.1 by INADA Naoki
Add bzrlib.i18n module.
85
def install(lang=None):
6162.4.1 by Jonathan Riddell
alter code to make it more usable by plugins, add install_translations()
86
    """Enables gettext translations in bzr."""
5875.3.25 by Vincent Ladeuil
Fix test failures and make sure we don't rely on a default translation.
87
    global _translations
6112.1.1 by Jonathan Riddell
check for installed i18n before doing install
88
    if installed():
89
        return
6162.4.1 by Jonathan Riddell
alter code to make it more usable by plugins, add install_translations()
90
    _translations = install_translations(lang)
91
6162.4.7 by Jonathan Riddell
two empty lines between top level items
92
6162.4.1 by Jonathan Riddell
alter code to make it more usable by plugins, add install_translations()
93
def install_translations(lang=None, domain='bzr', locale_base=None):
94
    """Create a gettext translation object.
95
    
96
    :param lang: language to install.
97
    :param domain: translation domain to install.
98
    :param locale_base: plugins can specify their own directory.
99
100
    :returns: a gettext translations object to use
101
    """
5875.2.1 by INADA Naoki
Add bzrlib.i18n module.
102
    if lang is None:
103
        lang = _get_current_locale()
6025.1.1 by Jelmer Vernooij
Fix i18n use when no environment variables are set.
104
    if lang is not None:
105
        languages = lang.split(':')
106
    else:
107
        languages = None
6162.4.1 by Jonathan Riddell
alter code to make it more usable by plugins, add install_translations()
108
    translation = _gettext.translation(
109
            domain,
110
            localedir=_get_locale_dir(locale_base),
6025.1.1 by Jelmer Vernooij
Fix i18n use when no environment variables are set.
111
            languages=languages,
5875.2.1 by INADA Naoki
Add bzrlib.i18n module.
112
            fallback=True)
6162.4.1 by Jonathan Riddell
alter code to make it more usable by plugins, add install_translations()
113
    return translation
5875.2.7 by INADA Naoki
Change order of functions.
114
6162.4.7 by Jonathan Riddell
two empty lines between top level items
115
6162.4.2 by Jonathan Riddell
add add_fallback() method to i18n
116
def add_fallback(fallback):
117
    """
118
    Add a fallback translations object.  Typically used by plugins.
119
120
    :param fallback: gettext.GNUTranslations object
121
    """
122
    install()
123
    _translations.add_fallback(fallback)
124
6162.4.7 by Jonathan Riddell
two empty lines between top level items
125
5875.2.1 by INADA Naoki
Add bzrlib.i18n module.
126
def uninstall():
6133.3.10 by Jonathan Riddell
default _translations back to None so we can tell if it gets installed
127
    """Disables gettext translations."""
5875.3.25 by Vincent Ladeuil
Fix test failures and make sure we don't rely on a default translation.
128
    global _translations
6133.3.10 by Jonathan Riddell
default _translations back to None so we can tell if it gets installed
129
    _translations = None
5875.2.1 by INADA Naoki
Add bzrlib.i18n module.
130
131
6162.4.1 by Jonathan Riddell
alter code to make it more usable by plugins, add install_translations()
132
def _get_locale_dir(base):
133
    """Returns directory to find .mo translations file in, either local or system
134
135
    :param base: plugins can specify their own local directory
136
    """
5875.2.1 by INADA Naoki
Add bzrlib.i18n module.
137
    if hasattr(sys, 'frozen'):
6162.4.1 by Jonathan Riddell
alter code to make it more usable by plugins, add install_translations()
138
        if base is None:
139
            base = os.path.dirname(
5875.2.1 by INADA Naoki
Add bzrlib.i18n module.
140
                unicode(sys.executable, sys.getfilesystemencoding()))
141
        return os.path.join(base, u'locale')
142
    else:
6162.4.1 by Jonathan Riddell
alter code to make it more usable by plugins, add install_translations()
143
        if base is None:
144
            base = os.path.dirname(unicode(__file__, sys.getfilesystemencoding()))
5875.2.4 by INADA Naoki
Search '/usr/share/locale' when bzrlib/locale does not exist.
145
        dirpath = os.path.realpath(os.path.join(base, u'locale'))
146
        if os.path.exists(dirpath):
147
            return dirpath
148
        else:
149
            return '/usr/share/locale'
5875.2.1 by INADA Naoki
Add bzrlib.i18n module.
150
151
152
def _check_win32_locale():
153
    for i in ('LANGUAGE','LC_ALL','LC_MESSAGES','LANG'):
154
        if os.environ.get(i):
155
            break
156
    else:
157
        lang = None
158
        import locale
159
        try:
160
            import ctypes
161
        except ImportError:
162
            # use only user's default locale
163
            lang = locale.getdefaultlocale()[0]
164
        else:
165
            # using ctypes to determine all locales
166
            lcid_user = ctypes.windll.kernel32.GetUserDefaultLCID()
167
            lcid_system = ctypes.windll.kernel32.GetSystemDefaultLCID()
168
            if lcid_user != lcid_system:
169
                lcid = [lcid_user, lcid_system]
170
            else:
171
                lcid = [lcid_user]
172
            lang = [locale.windows_locale.get(i) for i in lcid]
173
            lang = ':'.join([i for i in lang if i])
174
        # set lang code for gettext
175
        if lang:
176
            os.environ['LANGUAGE'] = lang
177
178
179
def _get_current_locale():
180
    if not os.environ.get('LANGUAGE'):
181
        from bzrlib import config
6056.2.3 by Vincent Ladeuil
Migrate language.
182
        lang = config.GlobalStack().get('language')
5875.2.1 by INADA Naoki
Add bzrlib.i18n module.
183
        if lang:
184
            os.environ['LANGUAGE'] = lang
185
            return lang
186
    if sys.platform == 'win32':
187
        _check_win32_locale()
188
    for i in ('LANGUAGE','LC_ALL','LC_MESSAGES','LANG'):
189
        lang = os.environ.get(i)
190
        if lang:
191
            return lang
192
    return None
6189.1.1 by Jelmer Vernooij
Add a load_plugin_translations method.
193
194
195
def load_plugin_translations(domain):
196
    """Load the translations for a specific plugin.
197
198
    :param domain: Gettext domain name (usually 'bzr-PLUGINNAME')
199
    """
200
    locale_base = os.path.dirname(
201
        unicode(__file__, sys.getfilesystemencoding()))
202
    translation = install_translations(domain=domain,
203
        locale_base=locale_base)
204
    add_fallback(translation)
205
    return translation