GrampsLocale: Refactor/clean up initialization

Includes moving encoding to be a class variable.

svn: r21961
This commit is contained in:
John Ralls 2013-04-12 22:26:55 +00:00
parent 25315ceece
commit a422b30fd6

View File

@ -144,6 +144,8 @@ class GrampsLocale(object):
subidrectries in the localedir, e.g. "fr" or "zh_CN". subidrectries in the localedir, e.g. "fr" or "zh_CN".
""" """
__first_instance = None __first_instance = None
encoding = None
def __new__(cls, localedir=None, lang=None, domain=None, languages=None): def __new__(cls, localedir=None, lang=None, domain=None, languages=None):
if not GrampsLocale.__first_instance: if not GrampsLocale.__first_instance:
cls.__first_instance = super(GrampsLocale, cls).__new__(cls) cls.__first_instance = super(GrampsLocale, cls).__new__(cls)
@ -315,16 +317,21 @@ class GrampsLocale(object):
except WindowsError: except WindowsError:
LOG.warning("Localization library libintl not on %PATH%, localization will be incomplete") LOG.warning("Localization library libintl not on %PATH%, localization will be incomplete")
def __init_first_instance(self, localedir): def __init_first_instance(self):
"""
Initialize the primary locale from whatever might be
available. We only do this once, and the resulting
GrampsLocale is returned by default.
"""
global _hdlr global _hdlr
_hdlr = logging.StreamHandler() _hdlr = logging.StreamHandler()
_hdlr.setFormatter(logging.Formatter(fmt="%(name)s.%(levelname)s: %(message)s")) _hdlr.setFormatter(logging.Formatter(fmt="%(name)s.%(levelname)s: %(message)s"))
LOG.addHandler(_hdlr) LOG.addHandler(_hdlr)
#First, globally set the locale to what's in the environment: # Even the first instance can be overridden by passing lang
# and languages to the constructor. If it isn't (which is the
if not (hasattr(self, 'lang') and self.lang # expected behavior), do platform-specific setup:
and hasattr(self, 'language') and self.language): if not (self.lang and self.language):
if sys.platform == 'darwin': if sys.platform == 'darwin':
from . import maclocale from . import maclocale
maclocale.mac_setup_localization(self) maclocale.mac_setup_localization(self)
@ -339,15 +346,15 @@ class GrampsLocale(object):
self.lang = 'en_US.UTF-8' self.lang = 'en_US.UTF-8'
if not self.language: if not self.language:
self.language.append('en') self.language.append('en')
if not self.have_localedir and not self.lang.startswith('en'): if not self.localedir and not self.lang.startswith('en'):
LOG.warning("No translations for %s were found, setting localization to U.S. English", self.localedomain) LOG.warning("No translations for %s were found, setting localization to U.S. English", self.localedomain)
self.lang = 'en_US.UTF-8' self.lang = 'en_US.UTF-8'
self.language = ['en'] self.language = ['en']
#Next, we need to know what is the encoding from the native #Next, we need to know what is the encoding from the native
#environment. This is used by python standard library funcions which #environment. This is used by python standard library funcions which
#localize their output, e.g. time.strftime(): #localize their output, e.g. time.strftime(). NB: encoding is a class variable.
if not (hasattr(self, 'encoding') and self.encoding): if not self.encoding:
self.encoding = (locale.getpreferredencoding() self.encoding = (locale.getpreferredencoding()
or sys.getdefaultencoding()) or sys.getdefaultencoding())
#Ensure that output is encoded correctly to stdout and stderr. This is #Ensure that output is encoded correctly to stdout and stderr. This is
@ -366,27 +373,64 @@ class GrampsLocale(object):
'backslashreplace') 'backslashreplace')
#GtkBuilder depends on reading Glade files as UTF-8 and crashes if it # Make sure that self.lang and self.language are reflected
#doesn't, so set $LANG to have a UTF-8 locale. NB: This does *not* # back into the environment for Gtk to use when its
#affect locale.getpreferredencoding() or sys.getfilesystemencoding() # initialized. If self.lang isn't 'C', make sure that it has a
#which are set by python long before we get here. # 'UTF-8' suffix, because that's all that GtkBuilder can
check_lang = self.lang.split('.') # digest.
if len(check_lang) < 2 or check_lang[1] not in ["utf-8", "UTF-8"]:
self.lang = '.'.join((check_lang[0], 'UTF-8')) # Linux note: You'll get unsupported locale errors from Gtk
if self.lang == 'C.UTF-8': # and untranslated strings if the requisite UTF-8 locale isn't
os.environ["LANG"] = 'C' # installed. This is particularly a problem on Debian and
else: # Debian-derived distributions which by default don't install
os.environ["LANG"] = self.lang # a lot of locales.
os.environ["LANGUAGE"] = ':'.join(['C' if l.startswith('en') else l for l in self.language]) if self.lang != 'C':
check_lang = self.lang.split('.')
if len(check_lang) < 2 or check_lang[1] not in ["utf-8", "UTF-8"]:
self.lang = '.'.join((check_lang[0], 'UTF-8'))
os.environ["LANG"] = self.lang
os.environ["LANGUAGE"] = ':'.join(['C' if l in ('en', 'en_US') else l
for l in self.language])
# GtkBuilder uses GLib's g_dgettext wrapper, which oddly is bound # GtkBuilder uses GLib's g_dgettext wrapper, which oddly is bound
# with locale instead of gettext. Win32 doesn't support bindtextdomain. # with locale instead of gettext. Win32 doesn't support bindtextdomain.
if self.have_localedir: if self.localedir:
if not sys.platform == 'win32': if not sys.platform == 'win32':
locale.bindtextdomain(self.localedomain, self.localedir) locale.bindtextdomain(self.localedomain, self.localedir)
else: else:
self._win_bindtextdomain(self.localedomain, self.localedir) self._win_bindtextdomain(self.localedomain, self.localedir)
def _init_secondary_locale(self):
"""
Init a secondary locale. Secondary locales are used to provide
an alternate localization to the one used for the UI; for
example, some reports offer the option to use a different
language.
"""
if not self.localedir:
LOG.warning("No Localedir provided, unable to find translations")
if not self.localedomain:
if _firstlocaledomain:
self.localedomain = _first.localedomain
else:
self.localedomain = "gramps"
_first = self._GrampsLocale__first_instance
if not self.lang and _first.lang:
self.lang = _first.lang
if not self.language:
if self.lang:
trans = self.check_available_translations(self.lang)
if trans:
self.language = [trans]
if not self.language and _first.language:
self.language = _first.language
self.calendar = self.collation = self.lang
def __init__(self, localedir=None, lang=None, domain=None, languages=None): def __init__(self, localedir=None, lang=None, domain=None, languages=None):
""" """
@ -395,53 +439,39 @@ class GrampsLocale(object):
otherwise if called without arguments. otherwise if called without arguments.
""" """
global _hdlr global _hdlr
#initialized is special, used only for the "first instance",
#and created by __new__(). It's used to prevent re-__init__ing
#__first_instance when __new__() returns its pointer.
if hasattr(self, 'initialized') and self.initialized: if hasattr(self, 'initialized') and self.initialized:
return return
_first = self._GrampsLocale__first_instance _first = self._GrampsLocale__first_instance
self.have_localedir = True
if domain: # Everything breaks without localedir, so get that set up
self.localedomain = domain # first. Warnings are logged in _init_first_instance or
elif hasattr(_first, 'localedomain'): # _init_secondary_locale if this comes up empty.
self.localedomain = _first.localedomain if localedir and os.path.exists(os.path.abspath(localedir)):
else:
self.localedomain = "gramps"
if localedir and os.path.exists(localedir):
self.localedir = localedir self.localedir = localedir
elif hasattr(_first, 'localedir'): elif _first and _first.localedir:
self.localedir = _first.localedir self.localedir = _first.localedir
else: else:
self.localedir = None self.localedir = None
if localedir:
LOG.warning("Localedir %s doesn't exist, unable to set localization", localedir);
else:
LOG.warning("No Localedir provided, unable to set localization")
self.have_localedir = False
if lang: self.lang = lang
self.lang = lang self.localedomain = domain or 'gramps'
elif hasattr(_first, 'lang'):
self.lang = _first.lang
self.language = []
if languages: if languages:
self.language = [x for x in [self.check_available_translations(l) self.language = [x for x in [self.check_available_translations(l)
for l in languages] for l in languages.split(":")]
if x] if x]
elif hasattr(self, 'lang') and self.lang:
trans = self.check_available_translations(lang)
if trans:
self.language.append(trans)
if not self.language and hasattr(_first, 'language'):
self.language = _first.language
if self == _first:
self._GrampsLocale__init_first_instance(localedir)
else: else:
self.calendar = self.collation = self.lang self.language = None
_first = self._GrampsLocale__first_instance
if self == _first:
self._GrampsLocale__init_first_instance()
else:
self._init_secondary_locale()
self.icu_locales = {} self.icu_locales = {}
@ -692,7 +722,7 @@ class GrampsLocale(object):
Test a locale for having a translation available Test a locale for having a translation available
locale -- string with standard language code, locale code, or name locale -- string with standard language code, locale code, or name
""" """
if not self.have_localedir: if not self.localedir:
return None return None
if not hasattr(self, 'languages'): if not hasattr(self, 'languages'):
self.languages = self.get_available_translations() self.languages = self.get_available_translations()