##// END OF EJS Templates
i18n: cache the result of every gettext call...
Augie Fackler -
r23031:3c0983cc default
parent child Browse files
Show More
@@ -1,86 +1,90 b''
1 # i18n.py - internationalization support for mercurial
1 # i18n.py - internationalization support for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 import encoding
8 import encoding
9 import gettext as gettextmod, sys, os, locale
9 import gettext as gettextmod, sys, os, locale
10
10
11 # modelled after templater.templatepath:
11 # modelled after templater.templatepath:
12 if getattr(sys, 'frozen', None) is not None:
12 if getattr(sys, 'frozen', None) is not None:
13 module = sys.executable
13 module = sys.executable
14 else:
14 else:
15 module = __file__
15 module = __file__
16
16
17
17
18 _languages = None
18 _languages = None
19 if (os.name == 'nt'
19 if (os.name == 'nt'
20 and 'LANGUAGE' not in os.environ
20 and 'LANGUAGE' not in os.environ
21 and 'LC_ALL' not in os.environ
21 and 'LC_ALL' not in os.environ
22 and 'LC_MESSAGES' not in os.environ
22 and 'LC_MESSAGES' not in os.environ
23 and 'LANG' not in os.environ):
23 and 'LANG' not in os.environ):
24 # Try to detect UI language by "User Interface Language Management" API
24 # Try to detect UI language by "User Interface Language Management" API
25 # if no locale variables are set. Note that locale.getdefaultlocale()
25 # if no locale variables are set. Note that locale.getdefaultlocale()
26 # uses GetLocaleInfo(), which may be different from UI language.
26 # uses GetLocaleInfo(), which may be different from UI language.
27 # (See http://msdn.microsoft.com/en-us/library/dd374098(v=VS.85).aspx )
27 # (See http://msdn.microsoft.com/en-us/library/dd374098(v=VS.85).aspx )
28 try:
28 try:
29 import ctypes
29 import ctypes
30 langid = ctypes.windll.kernel32.GetUserDefaultUILanguage()
30 langid = ctypes.windll.kernel32.GetUserDefaultUILanguage()
31 _languages = [locale.windows_locale[langid]]
31 _languages = [locale.windows_locale[langid]]
32 except (ImportError, AttributeError, KeyError):
32 except (ImportError, AttributeError, KeyError):
33 # ctypes not found or unknown langid
33 # ctypes not found or unknown langid
34 pass
34 pass
35
35
36 _ugettext = None
36 _ugettext = None
37
37
38 def setdatapath(datapath):
38 def setdatapath(datapath):
39 localedir = os.path.join(datapath, 'locale')
39 localedir = os.path.join(datapath, 'locale')
40 t = gettextmod.translation('hg', localedir, _languages, fallback=True)
40 t = gettextmod.translation('hg', localedir, _languages, fallback=True)
41 global _ugettext
41 global _ugettext
42 _ugettext = t.ugettext
42 _ugettext = t.ugettext
43
43
44 _msgcache = {}
45
44 def gettext(message):
46 def gettext(message):
45 """Translate message.
47 """Translate message.
46
48
47 The message is looked up in the catalog to get a Unicode string,
49 The message is looked up in the catalog to get a Unicode string,
48 which is encoded in the local encoding before being returned.
50 which is encoded in the local encoding before being returned.
49
51
50 Important: message is restricted to characters in the encoding
52 Important: message is restricted to characters in the encoding
51 given by sys.getdefaultencoding() which is most likely 'ascii'.
53 given by sys.getdefaultencoding() which is most likely 'ascii'.
52 """
54 """
53 # If message is None, t.ugettext will return u'None' as the
55 # If message is None, t.ugettext will return u'None' as the
54 # translation whereas our callers expect us to return None.
56 # translation whereas our callers expect us to return None.
55 if message is None or not _ugettext:
57 if message is None or not _ugettext:
56 return message
58 return message
57
59
58 if type(message) is unicode:
60 if message not in _msgcache:
59 # goofy unicode docstrings in test
61 if type(message) is unicode:
60 paragraphs = message.split(u'\n\n')
62 # goofy unicode docstrings in test
61 else:
63 paragraphs = message.split(u'\n\n')
62 paragraphs = [p.decode("ascii") for p in message.split('\n\n')]
64 else:
63 # Be careful not to translate the empty string -- it holds the
65 paragraphs = [p.decode("ascii") for p in message.split('\n\n')]
64 # meta data of the .po file.
66 # Be careful not to translate the empty string -- it holds the
65 u = u'\n\n'.join([p and _ugettext(p) or '' for p in paragraphs])
67 # meta data of the .po file.
66 try:
68 u = u'\n\n'.join([p and _ugettext(p) or '' for p in paragraphs])
67 # encoding.tolocal cannot be used since it will first try to
69 try:
68 # decode the Unicode string. Calling u.decode(enc) really
70 # encoding.tolocal cannot be used since it will first try to
69 # means u.encode(sys.getdefaultencoding()).decode(enc). Since
71 # decode the Unicode string. Calling u.decode(enc) really
70 # the Python encoding defaults to 'ascii', this fails if the
72 # means u.encode(sys.getdefaultencoding()).decode(enc). Since
71 # translated string use non-ASCII characters.
73 # the Python encoding defaults to 'ascii', this fails if the
72 return u.encode(encoding.encoding, "replace")
74 # translated string use non-ASCII characters.
73 except LookupError:
75 _msgcache[message] = u.encode(encoding.encoding, "replace")
74 # An unknown encoding results in a LookupError.
76 except LookupError:
75 return message
77 # An unknown encoding results in a LookupError.
78 _msgcache[message] = message
79 return _msgcache[message]
76
80
77 def _plain():
81 def _plain():
78 if 'HGPLAIN' not in os.environ and 'HGPLAINEXCEPT' not in os.environ:
82 if 'HGPLAIN' not in os.environ and 'HGPLAINEXCEPT' not in os.environ:
79 return False
83 return False
80 exceptions = os.environ.get('HGPLAINEXCEPT', '').strip().split(',')
84 exceptions = os.environ.get('HGPLAINEXCEPT', '').strip().split(',')
81 return 'i18n' not in exceptions
85 return 'i18n' not in exceptions
82
86
83 if _plain():
87 if _plain():
84 _ = lambda message: message
88 _ = lambda message: message
85 else:
89 else:
86 _ = gettext
90 _ = gettext
General Comments 0
You need to be logged in to leave comments. Login now