Author: reinhard
Date: 2009-10-02 08:06:16 -0500 (Fri, 02 Oct 2009)
New Revision: 9922
Modified:
trunk/gnue-common/src/apps/CommandOption.py
trunk/gnue-common/src/apps/GConfig.py
trunk/gnue-common/src/apps/i18n.py
trunk/gnue-common/src/base/errors.py
trunk/gnue-common/src/base/i18n.py
trunk/gnue-common/src/utils/plugin.py
trunk/gnue-common/src/utils/tree.py
Log:
Cleanup of i18n code.
Modified: trunk/gnue-common/src/apps/CommandOption.py
===================================================================
--- trunk/gnue-common/src/apps/CommandOption.py 2009-10-02 10:46:00 UTC (rev 9921)
+++ trunk/gnue-common/src/apps/CommandOption.py 2009-10-02 13:06:16 UTC (rev 9922)
@@ -80,6 +80,6 @@
# FIXME: only for compatibility, remove in some later version!
if isinstance (self.help, str):
- self.help = unicode (self.help, i18n.get_encoding())
+ self.help = i18n.inconv(self.help)
if isinstance (self.argumentName, str):
- self.argumentName = unicode (self.argumentName, i18n.get_encoding())
+ self.argumentName = i18n.inconv(self.argumentName)
Modified: trunk/gnue-common/src/apps/GConfig.py
===================================================================
--- trunk/gnue-common/src/apps/GConfig.py 2009-10-02 10:46:00 UTC (rev 9921)
+++ trunk/gnue-common/src/apps/GConfig.py 2009-10-02 13:06:16 UTC (rev 9922)
@@ -30,7 +30,7 @@
import ConfigParser
from gnue import paths
-from gnue.common.base import i18n, errors
+from gnue.common.base import errors, i18n
from gnue.common import GCConfig
@@ -509,11 +509,11 @@
(output_width - len(nameString + defaultString)),
defaultString)
+ description = option['Description']
# FIXME: This allows for non-unicode descriptions. Remove at some
# point.
- description = option['Description']
if isinstance(description, str):
- description = unicode(description, i18n.get_encoding())
+ description = i18n.inconv(description)
output += "%s\n" % textwrap.fill(description, output_width)
else:
Modified: trunk/gnue-common/src/apps/i18n.py
===================================================================
--- trunk/gnue-common/src/apps/i18n.py 2009-10-02 10:46:00 UTC (rev 9921)
+++ trunk/gnue-common/src/apps/i18n.py 2009-10-02 13:06:16 UTC (rev 9922)
@@ -30,27 +30,159 @@
@var encoding: Encoding of the current locale
"""
+import locale
+import os
+import sys
+
from gnue.common.base import i18n
-__all__ = ['language', 'encoding', 'outconv', 'utranslate', 'translate',
- 'getlanguage', 'getencoding', 'getuserlocale', 'setcurrentlocale']
+__all__ = ['language', 'encoding', 'getlanguage', 'getuserlocale',
+ 'setcurrentlocale']
# -----------------------------------------------------------------------------
-# Global variables
+# Global variables - DEPRECATED.
# -----------------------------------------------------------------------------
-language = i18n.language
-encoding = i18n.encoding
+language = None
+encoding = None
# -----------------------------------------------------------------------------
-# Functions
+# Get the current language - DEPRECATED.
# -----------------------------------------------------------------------------
-outconv = i18n.outconv
+def getlanguage():
+ """
+ Returns the language of the currently active locale. This can be changed
+ with L{set_current_locale}.
+
+ @return: language of the current locale.
+ """
+ return language
+
+
+# -----------------------------------------------------------------------------
+# Get the locale string of the current user
+# -----------------------------------------------------------------------------
+
+def getuserlocale():
+ """
+ Try to find out which locale the user is using. This is always the locale
+ of the user running the program and is not touched by
+ L{set_current_locale}.
+
+ @return: localestring of the user's locale, i.e. de_AT@euro.
+ """
+
+ # *Actually* the following is very much what locale.getdefaultlocale should
+ # do anyway. However, that function is broken for $LANGUAGE containing a
+ # list of locales, separated with ":". So we have to manually rebuild it...
+ items = ['LANGUAGE', 'LC_ALL', 'LC_MESSAGES', 'LANG']
+ for key in items:
+ if os.environ.has_key(key):
+ # Some systems (most notably Debian...) set $LANGUAGE to a *list*
+ # of locales, separated by a ":".
+ env_lang = (os.environ[key]).split(':')[0]
+ return locale.locale_alias.get(env_lang, env_lang)
+
+ # On Mac OS X getdefaultlocale always returns 'C', so we will query the
+ # system preferences here.
+ if sys.platform == 'darwin':
+ pipe = os.popen('defaults read -g AppleLocale')
+ result = pipe.read().strip() + '.UTF-8'
+ pipe.close()
+
+ else:
+ # Now this should only happen on Windows, where getdefaultlocale seems
+ # to work ok.
+ try:
+ result = locale.getdefaultlocale()[0]
+ except locale.Error:
+ result = ''
+
+ return result or 'C'
+
+
+# -----------------------------------------------------------------------------
+# Update global variables
+# -----------------------------------------------------------------------------
+
+def __updateglobals():
+
+ global language, encoding
+
+ # On win32, getlocale is broken - it returns strings like Hungarian_Hungary
+ # instead of hu_HU.
+ if sys.platform in ['win32', 'Pocket PC']:
+ (language, encoding) = locale.getdefaultlocale()
+ else:
+ (language, encoding) = locale.getlocale()
+
+ # Make sure language and encoding are not None
+ if not language:
+ language = 'C'
+ if not encoding:
+ encoding = 'ascii'
+
+
+# -----------------------------------------------------------------------------
+# Change the current locale - DEPRECATED.
+# -----------------------------------------------------------------------------
+
+def setcurrentlocale(new_locale):
+ """
+ Set the current locale.
+
+ If it fails it tries to succeed using a more general form of the requested
+ locale, i.e. if 'de_AT@euro' fails, 'de_AT' will be tried next. If that
+ fails too, 'de' will be tried.
+
+ @param new_locale: string of the locale to be set, e.g. de_AT.ISO88591@euro
+ (full blown) or 'de_AT' or 'en_AU'
+ """
+ # Setting a locale different than the current locale doesn't work on
+ # Windows.
+ if sys.platform == 'win32':
+ return
+
+ if new_locale is None:
+ new_locale = ''
+
+ new_locale = new_locale.encode()
+
+ parts = []
+ add = []
+ normal = locale.normalize(new_locale) # lc_CC.ENCODING@variant
+ next = normal.split('@')[0] # lc_CC.ENCODING
+ lang = next.split('.')[0] # lc_CC
+
+ alias = locale.locale_alias.get(lang.split('_')[0].lower())
+ if alias:
+ add = [alias.split('@')[0]]
+ add.append(add[-1].split('.')[0])
+ add.append(locale.locale_alias.get(add[-1].split('_')[0].lower()))
+
+ for item in [normal, next, lang] + add:
+ if item is not None and item not in parts:
+ parts.append(item)
+
+ for item in parts:
+ try:
+ locale.setlocale(locale.LC_ALL, item)
+
+ except locale.Error:
+ pass
+
+ else:
+ break
+
+ __updateglobals()
+
+
+# -----------------------------------------------------------------------------
+# Module initialization
+# -----------------------------------------------------------------------------
+
utranslate = i18n.utranslate
-translate = i18n.translate
-getlanguage = i18n.get_language
-getencoding = i18n.get_encoding
-getuserlocale = i18n.get_user_locale
-setcurrentlocale = i18n.set_current_locale
+
+__updateglobals()
Modified: trunk/gnue-common/src/base/errors.py
===================================================================
--- trunk/gnue-common/src/base/errors.py 2009-10-02 10:46:00 UTC (rev 9921)
+++ trunk/gnue-common/src/base/errors.py 2009-10-02 13:06:16 UTC (rev 9922)
@@ -27,6 +27,7 @@
import sys
import traceback
+import types
import exceptions
from gnue.common.base import i18n
@@ -82,10 +83,17 @@
@return: Name of the exception.
@rtype: Unicode
"""
- rep = self.name or "%s" % (sys.exc_info()[0] or exc_type)
- return _unicode(rep.split('.')[-1])
+ if self.name is not None:
+ return self.name
+ t = sys.exc_info()[0] or exc_type
+ if issubclass(t, Exception):
+ return unicode(t.__name__)
+ else:
+ return unicode(t)
+
+
# -------------------------------------------------------------------------
# Get the detail of an exception
# -------------------------------------------------------------------------
@@ -103,21 +111,22 @@
@rtype: Unicode
"""
if self.detail is not None:
- return _unicode(self.detail, i18n.get_encoding())
+ return self.detail
(stype, svalue, strace) = sys.exc_info()
stype = stype or etype
svalue = svalue or evalue
strace = strace or etrace
- tStack = traceback.format_exception(stype, svalue, strace)
+ stack = traceback.format_exception(stype, svalue, strace)
if count is not None:
- del tStack[1:count + 1]
+ del stack[1:count + 1]
- return _unicode("%s" % ''.join(tStack), i18n.get_encoding())
+ # sys.exc_info() and traceback.format_exception() return 8-bit strings
+ # in the current encoding, so we have to convert them back to Unicode.
+ return i18n.inconv(''.join(stack))
-
# =============================================================================
# System Error
# =============================================================================
@@ -226,35 +235,14 @@
if count is not None:
del lines[1:count + 1]
- name = unicode("%s" % exc_type, i18n.get_encoding(), 'replace')
+ if isinstance(exc_type, types.InstanceType):
+ name = unicode(exc_type)
+ else:
+ name = unicode(exc_type.__name__)
name = name.split('.')[-1]
- message = unicode("%s" % exc_value, i18n.get_encoding(), 'replace')
+ message = unicode(exc_value)
detail = ''.join(lines)
if isinstance(detail, str):
- detail = unicode(detail, i18n.get_encoding(), 'replace')
+ detail = i18n.inconv(detail)
return ('system', name, message, detail)
-
-
-# -----------------------------------------------------------------------------
-# Create a unicode string using a given encoding
-# -----------------------------------------------------------------------------
-
-def _unicode(text, encoding=None):
- """
- Convert the given text into unicode using the optionally passed encoding.
- If no encoding is specified the systems' default encoding will be used.
-
- @returns: the text in unicode
- @rtype: unicode
- """
-
- result = text
-
- if isinstance(text, str):
- if encoding is not None:
- result = unicode(text, encoding, 'replace')
- else:
- result = unicode(text, errors='replace')
-
- return result
Modified: trunk/gnue-common/src/base/i18n.py
===================================================================
--- trunk/gnue-common/src/base/i18n.py 2009-10-02 10:46:00 UTC (rev 9921)
+++ trunk/gnue-common/src/base/i18n.py 2009-10-02 13:06:16 UTC (rev 9922)
@@ -23,57 +23,109 @@
"""
Internationalization support.
-
-@var language: Language of the current locale
-@var encoding: Encoding of the current locale
"""
import gettext
import locale
import os
-import os.path
import sys
from gnue import paths
from gnue.common.lib import modules
-__all__ = ['language', 'encoding', 'outconv', 'utranslate', 'translate',
- 'get_language', 'get_encoding', 'get_user_locale',
- 'set_current_locale']
+__all__ = ['outconv', 'inconv', 'utranslate', 'translate']
+# =============================================================================
+# Locale initialization
+# =============================================================================
+
+def init_locale():
+ """
+ Initialize locale support. This is called automatically in module
+ initialization, no need to call it manually.
+ """
+
+ # On Mac, locale.setlocale() does not set the default locale. Instead we
+ # have to query the system preferences for the AppleLocale.
+ if sys.platform == 'darwin':
+ pipe = os.popen('defaults read -g AppleLocale')
+ deflc = pipe.read().strip() + '.UTF-8'
+ pipe.close()
+ else:
+ deflc = ''
+
+ locale.setlocale(locale.LC_ALL, deflc)
+
+
+# =============================================================================
+# Character set support
+# =============================================================================
+
# -----------------------------------------------------------------------------
-# Global variables
+# Convert Unicode to String, using the current encoding
# -----------------------------------------------------------------------------
-language = None
-encoding = None
+def outconv(text):
+ """
+ Encode a text to the current encoding. This function is available as
+ the builtin function "o()".
+ """
+ checktype(text, unicode)
+ encoding = locale.getlocale()[1]
+ if encoding is None:
+ encoding = 'ascii'
+ return text.encode(encoding, 'replace')
+
+
# -----------------------------------------------------------------------------
-# Convert Unicode to String, let everything else untouched. This is o().
+# Convert String to Unicode, using the current encoding
# -----------------------------------------------------------------------------
-def outconv(message):
+def inconv(text):
"""
- Encodes a message to L{encoding} (the current locale's encoding). This
- function is available as the builtin function "o()".
+ Encode a text to the current encoding. This function is available as
+ the builtin function "o()".
"""
- if isinstance(message, unicode):
- return message.encode(encoding, 'replace')
- else:
- return message
+ checktype(text, str)
+ encoding = locale.getlocale()[1]
+ if encoding is None:
+ encoding = 'ascii'
+ return unicode(text, encoding, 'replace')
+
+
+# =============================================================================
+# Language translation support
+# =============================================================================
+
# -----------------------------------------------------------------------------
+# Cache variables
+# -----------------------------------------------------------------------------
+
+__DOMAINS = {} # Domains by module name
+__CATALOGS = {} # Message catalogs by domain:language
+
+
+# -----------------------------------------------------------------------------
# Translate a message and return unicode
# -----------------------------------------------------------------------------
def utranslate(message):
"""
- Translates a message and returns a unicode string. This function is
+ Translate a message and return a unicode string. This function is
available as the builtin function "u_()".
"""
+
+ # TODO: with 0.8, deprecate non-unicode input, with 0.9 throw an error on
+ # non-unicode input.
+ language = locale.getlocale()[0]
+ if language is None:
+ return message
+
caller_module = modules.caller_module()
if not __DOMAINS.has_key(caller_module):
@@ -83,10 +135,12 @@
if domain is None:
# For gnue.common.foo.bar, try gnue-common-foo-bar,
# gnue-common-foo, gnue-common and gnue (in that order).
+ # TODO: deprecate with 0.8, remove with 0.9 - all modules should
+ # define __gettext_domain__.
parts = caller_module.split('.')
while parts:
try_domain = '-'.join(parts)
- if __find_catalog(try_domain) is not None:
+ if __find_catalog(try_domain, language) is not None:
domain = try_domain
break
del parts[-1]
@@ -97,7 +151,7 @@
if domain is None:
return message
- catalog = __find_catalog(domain)
+ catalog = __find_catalog(domain, language)
if catalog is None:
return message
@@ -105,7 +159,7 @@
# -----------------------------------------------------------------------------
-def __find_catalog(domain):
+def __find_catalog(domain, language):
if __CATALOGS.has_key(domain + ':' + language):
return __CATALOGS[domain + ':' + language]
@@ -113,7 +167,7 @@
try:
catalog = gettext.translation(domain, paths.data + '/share/locale',
[language])
- except:
+ except IOError:
catalog = None
__CATALOGS[domain + ':' + language] = catalog
@@ -127,189 +181,22 @@
def translate(message):
"""
- Translates a message and returns an 8 bit string, encoded with L{encoding}
- (the current locale's encoding). This function is available as the builtin
- function "_()".
+ Translate a message and return an 8 bit string, encoded with the current
+ encoding. This function is available as the builtin function "_()".
"""
+
+ # TODO: deprecate with 0.8, remove with 0.9, make _() an alias of u_() with
+ # 1.0
return outconv(utranslate(message))
-# -----------------------------------------------------------------------------
-# Cache variables
-# -----------------------------------------------------------------------------
-
-__DOMAINS = {} # Domains by module name
-__CATALOGS = {} # Message catalogs by domain:language
-
-
-# -----------------------------------------------------------------------------
-# Get the current language
-# -----------------------------------------------------------------------------
-
-def get_language():
- """
- Returns the language of the currently active locale. This can be changed
- with L{set_current_locale}.
-
- @return: language of the current locale.
- """
- return language
-
-
-# -----------------------------------------------------------------------------
-# Get the current encoding
-# -----------------------------------------------------------------------------
-
-def get_encoding():
- """
- Returns the encoding of the currently active locale. This can be changed
- with L{set_current_locale}.
-
- @return: encoding of the current locale.
- """
- return encoding
-
-
-# -----------------------------------------------------------------------------
-# Get the locale string of the current user
-# -----------------------------------------------------------------------------
-
-def get_user_locale():
- """
- Try to find out which locale the user is using. This is always the locale
- of the user running the program and is not touched by
- L{set_current_locale}.
-
- @return: localestring of the user's locale, i.e. de_AT@euro.
- """
-
- # *Actually* the following is very much what locale.getdefaultlocale should
- # do anyway. However, that function is broken for $LANGUAGE containing a
- # list of locales, separated with ":". So we have to manually rebuild it...
- items = ['LANGUAGE', 'LC_ALL', 'LC_MESSAGES', 'LANG']
- for key in items:
- if os.environ.has_key(key):
- # Some systems (most notably Debian...) set $LANGUAGE to a *list*
- # of locales, separated by a ":".
- env_lang = (os.environ[key]).split(':')[0]
- return locale.locale_alias.get(env_lang, env_lang)
-
- # On Mac OS X getdefaultlocale always returns 'C', so we will query the
- # system preferences here.
- if sys.platform == 'darwin':
- pipe = os.popen('defaults read -g AppleLocale')
- result = pipe.read().strip() + '.UTF-8'
- pipe.close()
-
- else:
- # Now this should only happen on Windows, where getdefaultlocale seems
- # to work ok.
- try:
- result = locale.getdefaultlocale()[0]
- except locale.Error:
- result = ''
-
- return result or 'C'
-
-
-# -----------------------------------------------------------------------------
-# Update global variables
-# -----------------------------------------------------------------------------
-
-def __updateglobals():
-
- global language, encoding
-
- # On win32, getlocale is broken - it returns strings like Hungarian_Hungary
- # instead of hu_HU.
- if sys.platform in ['win32', 'Pocket PC']:
- (language, encoding) = locale.getdefaultlocale()
- else:
- (language, encoding) = locale.getlocale()
-
- # Make sure language and encoding are not None
- if not language:
- language = 'C'
- if not encoding:
- encoding = 'ascii'
-
-
-# -----------------------------------------------------------------------------
-# Change the current locale
-# -----------------------------------------------------------------------------
-
-def set_current_locale(new_locale):
- """
- Set the current locale.
-
- If it fails it tries to succeed using a more general form of the requested
- locale, i.e. if 'de_AT@euro' fails, 'de_AT' will be tried next. If that
- fails too, 'de' will be tried.
-
- @param new_locale: string of the locale to be set, e.g. de_AT.ISO88591@euro
- (full blown) or 'de_AT' or 'en_AU'
- """
- # Setting a locale different than the current locale doesn't work on
- # Windows.
- if sys.platform == 'win32':
- return
-
- if new_locale is None:
- new_locale = ''
-
- new_locale = new_locale.encode()
-
- parts = []
- add = []
- normal = locale.normalize(new_locale) # lc_CC.ENCODING@variant
- next = normal.split('@')[0] # lc_CC.ENCODING
- lang = next.split('.')[0] # lc_CC
-
- alias = locale.locale_alias.get(lang.split('_')[0].lower())
- if alias:
- add = [alias.split('@')[0]]
- add.append(add[-1].split('.')[0])
- add.append(locale.locale_alias.get(add[-1].split('_')[0].lower()))
-
- for item in [normal, next, lang] + add:
- if item is not None and item not in parts:
- parts.append(item)
-
- for item in parts:
- try:
- locale.setlocale(locale.LC_ALL, item)
-
- except locale.Error:
- pass
-
- else:
- break
-
- __updateglobals()
-
-
-# -----------------------------------------------------------------------------
+# =============================================================================
# Module initialization
-# -----------------------------------------------------------------------------
+# =============================================================================
-# Initialize locale. On Mac locale.setlocale() does not return the default
-# locale. Instead we have to query the system preferences for the AppleLocale
-if sys.platform == 'darwin':
- pipe = os.popen('defaults read -g AppleLocale')
- deflc = pipe.read().strip() + '.UTF-8'
- pipe.close()
-else:
- deflc = ''
-
-try:
- locale.setlocale(locale.LC_ALL, deflc)
-except:
- pass
-
-__updateglobals()
-
-# Now define the new builtin stuff
import __builtin__
__builtin__.__dict__['o'] = outconv
__builtin__.__dict__['u_'] = utranslate
__builtin__.__dict__['_'] = translate
+
+init_locale()
Modified: trunk/gnue-common/src/utils/plugin.py
===================================================================
--- trunk/gnue-common/src/utils/plugin.py 2009-10-02 10:46:00 UTC (rev 9921)
+++ trunk/gnue-common/src/utils/plugin.py 2009-10-02 13:06:16 UTC (rev 9922)
@@ -57,10 +57,9 @@
import os
import sys
-import traceback
from types import ModuleType
-from gnue.common.base import errors, i18n
+from gnue.common.base import errors
__all__ = ['LoadError', 'list_plugins', 'find']
@@ -90,10 +89,7 @@
message = u_("Cannot load plugin '%s'") % self.name
detail = u_("The following plugins failed:\n")
for (name, exc) in self.exceptions.items():
- tlist = traceback.format_exception_only(exc[0], exc[1])
- del tlist[1:2]
- msg = unicode(''.join(tlist), i18n.get_encoding())
- detail += "* %s: %s" % (name, msg)
+ detail += "* %s: %s: %s" % (name, exc[1], exc[2])
else:
message = u_("Cannot find plugin '%s'") % self.name
detail = None
@@ -241,7 +237,7 @@
try:
mod = __import__(base, None, None, '*')
except:
- __failed[base] = sys.exc_info()
+ __failed[base] = errors.get_exception()
return {base: __failed[base]}
if hasattr(mod, '__noplugin__'):
@@ -255,7 +251,7 @@
try:
mod.__initplugin__()
except:
- __failed[base] = sys.exc_info()
+ __failed[base] = errors.get_exception()
return {base: __failed[base]}
return {base: mod}
@@ -282,7 +278,7 @@
try:
mod = __import__(base, None, None, '*')
except:
- __failed[base] = sys.exc_info()
+ __failed[base] = errors.get_exception()
return {base: __failed[base]}
if hasattr(mod, '__noplugin__'):
@@ -295,7 +291,7 @@
try:
mod.__initplugin__()
except:
- __failed[base] = sys.exc_info()
+ __failed[base] = errors.get_exception()
return {base: __failed[base]}
return mod
@@ -323,7 +319,7 @@
try:
mod = __import__(base, None, None, '*')
except:
- __failed[base] = sys.exc_info()
+ __failed[base] = errors.get_exception()
return {base: __failed[base]}
if hasattr(mod, '__noplugin__'):
@@ -344,7 +340,7 @@
except ImportError:
pass
except:
- __failed[base + '.' + name] = sys.exc_info()
+ __failed[base + '.' + name] = errors.get_exception()
return {base + '.' + name: __failed[base + '.' + name]}
else:
return __first(base + '.' + name, identifier)
@@ -376,8 +372,7 @@
if isinstance(iresult, ModuleType):
print "ok"
else:
- data = traceback.format_exception_only(iresult[0], iresult[1])
- print ''.join(data),
+ print iresult[1] + ": " + iresult[2]
elif sys.argv[1] == 'test':
Modified: trunk/gnue-common/src/utils/tree.py
===================================================================
--- trunk/gnue-common/src/utils/tree.py 2009-10-02 10:46:00 UTC (rev 9921)
+++ trunk/gnue-common/src/utils/tree.py 2009-10-02 13:06:16 UTC (rev 9922)
@@ -1,3 +1,4 @@
+# encoding:utf-8
# GNU Enterprise Common Library - Tree structure classes
#
# Copyright 2001-2009 Free Software Foundation
@@ -27,11 +28,9 @@
TODO: This module is work in progress.
"""
-import locale
+from gnue.common.base import errors, i18n
+from gnue.common.base.i18n import utranslate as u_ # for epydoc
-from gnue.common.apps import errors
-from gnue.common.apps.i18n import utranslate as u_ # for epydoc
-
__all__ = ['CircularReferenceError', 'DuplicateChildNameError',
'DuplicateDescendantNameError', 'NodeDictNotAvailableError',
'Node', 'NamedNode', 'AttribNode']
@@ -374,7 +373,7 @@
return "<unnamed " + self._node_type_ + ">"
elif isinstance(self.__node_name, unicode):
- return self.__node_name.encode(locale.getlocale()[0], 'replace')
+ return i18n.outconv(self.__node_name)
else:
return self.__node_name
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.