Rename trans.py and mactrans.py to grampslocale.py and maclocale.py

Reflecting discussion on gramps-devel about their affecting more than
just translations.

Provide for a master GrampsLocale instance to be retrieved from
const.py, set by grampsapp.

svn: r21142
This commit is contained in:
John Ralls 2013-01-17 19:41:58 +00:00
parent 7bb5c75d6a
commit eecf57a0f6
13 changed files with 288 additions and 388 deletions

View File

@ -351,3 +351,6 @@ def need_to_update_const():
if need_to_update_const():
print("Outdated gramps.gen.const; please run 'python setup.py build'")
GRAMPS_LOCALE = 0

View File

@ -44,7 +44,7 @@ import traceback
#-------------------------------------------------------------------------
from ..const import VERSION as GRAMPSVERSION, VERSION_TUPLE
from ..const import IMAGE_DIR
from ..utils.trans import get_addon_translator
from ..utils.grampslocale import get_addon_translator
from ..ggettext import gettext as _
from ..constfunc import STRTYPE

View File

@ -0,0 +1,273 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2006 Donald N. Allingham
# Copyright (C) 2009 Brian G. Matherly
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
#------------------------------------------------------------------------
#
# python modules
#
#------------------------------------------------------------------------
import gettext
import sys
import os
import locale
import logging
#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
from ..const import ROOT_DIR
from ..constfunc import mac, UNITYPE
class GrampsLocale(locale):
"""
Encapsulate a locale
"""
def __init__(self):
def _get_prefix(self):
"""
Find the root path for share/locale
"""
if sys.platform == "win32":
if sys.prefix == os.path.dirname(os.getcwd()):
return sys.prefix
else:
return os.path.join(os.path.dirname(__file__), os.pardir)
elif sys.platform == "darwin" and sys.prefix != sys.exec_prefix:
return sys.prefix
else:
return os.path.join(os.path.dirname(__file__), os.pardir)
def _init_gettext(self):
"""
Set up the gettext domain
"""
#the order in which bindtextdomain on gettext and on locale is called
#appears important, so we refrain from doing first all gettext.
#
#setup_gettext()
gettext.bindtextdomain(self.localedomain, self.localedir)
try:
locale.setlocale(locale.LC_ALL,'')
except:
logging.warning(_("WARNING: Setting locale failed. Please fix"
" the LC_* and/or the LANG environment "
"variables to prevent this error"))
try:
# It is probably not necessary to set the locale to 'C'
# because the locale will just stay at whatever it was,
# which at startup is "C".
# however this is done here just to make sure that the locale
# functions are working
locale.setlocale(locale.LC_ALL,'C')
except:
logging.warning(_("ERROR: Setting the 'C' locale didn't "
"work either"))
# FIXME: This should propagate the exception,
# if that doesn't break Gramps under Windows
raise
gettext.textdomain(slef.localedomain)
if sys.version_info[0] < 3:
gettext.install(self.localedomain, localedir=None, unicode=1) #None is sys default locale
else:
gettext.install(self.localedomain, localedir=None) #None is sys default locale
if hasattr(os, "uname"):
operating_system = os.uname()[0]
else:
operating_system = sys.platform
if win(): # Windows
setup_windows_gettext()
elif operating_system == 'FreeBSD':
try:
gettext.bindtextdomain(self.localedomain, self.localedir)
except locale.Error:
logging.warning('No translation in some Gtk.Builder strings, ')
elif operating_system == 'OpenBSD':
pass
else: # normal case
try:
locale.bindtextdomain(self.localedomain, self.localedir)
#locale.textdomain(self.localedomain)
except locale.Error:
logging.warning('No translation in some Gtk.Builder strings, ')
prefixdir = self._get_prefix()
if "GRAMPSI18N" in os.environ:
if os.path.exists(os.environ["GRAMPSI18N"]):
self.localedir = os.environ["GRAMPSI18N"]
else:
self.localedir = None
elif os.path.exists( os.path.join(ROOT_DIR, "lang") ):
self.localedir = os.path.join(ROOT_DIR, "lang")
elif os.path.exists(os.path.join(prefixdir, "share/locale")):
self.localedir = os.path.join(prefixdir, "share/locale")
else:
self.lang = os.environ.get('LANG', 'en')
if self.lang and self.lang[:2] == 'en':
pass # No need to display warning, we're in English
else:
logging.warning('Locale dir does not exist at ' +
os.path.join(prefixdir, "share/locale"))
logging.warning('Running python setup.py install --prefix=YourPrefixDir might fix the problem')
self.localedir = None
self.localedomain = 'gramps'
if mac():
from . import maclocale
maclocale.mac_setup_localization(self.localedir, self.localedomain)
else:
self.lang = ' '
try:
self.lang = os.environ["LANG"]
except KeyError:
self.lang = locale.getlocale()[0]
if not self.lang:
try:
self.lang = locale.getdefaultlocale()[0] + '.UTF-8'
except TypeError:
logging.warning('Unable to determine your Locale, using English')
self.lang = 'en.UTF-8'
os.environ["LANG"] = self.lang
os.environ["LANGUAGE"] = self.lang
self._init_gettext()
#-------------------------------------------------------------------------
#
# Public Functions
#
#-------------------------------------------------------------------------
def get_localedomain(self):
"""
Get the LOCALEDOMAIN used for the Gramps application.
"""
return self.localedomain
def get_addon_translator(self, filename=None, domain="addon",
languages=None):
"""
Get a translator for an addon.
filename - filename of a file in directory with full path, or
None to get from running code
domain - the name of the .mo file under the LANG/LC_MESSAGES dir
languages - a list of languages to force
returns - a gettext.translation object
Example:
_ = get_addon_translator(languages=["fr_BE.utf8"]).gettext
The return object has the following properties and methods:
.gettext
.info
.lgettext
.lngettext
.ngettext
.output_charset
.plural
.set_output_charset
.ugettext
.ungettext
Assumes path/filename
path/locale/LANG/LC_MESSAGES/addon.mo.
"""
if filename is None:
filename = sys._getframe(1).f_code.co_filename
gramps_translator = gettext.translation(LOCALEDOMAIN, LOCALEDIR,
fallback=True)
path = os.path.dirname(os.path.abspath(filename))
# Check if path is of type str. Do import and conversion if so.
# The import cannot be done at the top as that will conflict with the translation system.
if not isinstance(path, UNITYPE) == str:
from .file import get_unicode_path_from_env_var
path = get_unicode_path_from_env_var(path)
if languages:
addon_translator = gettext.translation(domain,
os.path.join(path, "locale"),
languages=languages,
fallback=True)
else:
addon_translator = gettext.translation(domain,
os.path.join(path, "locale"),
fallback=True)
gramps_translator.add_fallback(addon_translator)
return gramps_translator # with a language fallback
def get_available_translations(self):
"""
Get a list of available translations.
:returns: A list of translation languages.
:rtype: unicode[]
"""
languages = ["en"]
if slef.localedir is None:
return languages
for langdir in os.listdir(self.localedir):
mofilename = os.path.join(self.localedir, langdir,
"LC_MESSAGES", "%s.mo" % self.localedomain )
if os.path.exists(mofilename):
languages.append(langdir)
languages.sort()
return languages
def trans_objclass(self, objclass_str):
"""
Translates objclass_str into "... %s", where objclass_str
is 'Person', 'person', 'Family', 'family', etc.
"""
from ..ggettext import gettext as _
objclass = objclass_str.lower()
if objclass == "person":
return _("the person")
elif objclass == "family":
return _("the family")
elif objclass == "place":
return _("the place")
elif objclass == "event":
return _("the event")
elif objclass == "repository":
return _("the repository")
elif objclass == "note":
return _("the note")
elif objclass in ["media", "mediaobject"]:
return _("the media")
elif objclass == "source":
return _("the source")
elif objclass == "filter":
return _("the filter")
else:
return _("See details")

View File

@ -1,328 +0,0 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2006 Donald N. Allingham
# Copyright (C) 2009 Brian G. Matherly
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
"""
Provide translation assistance
"""
#------------------------------------------------------------------------
#
# python modules
#
#------------------------------------------------------------------------
import gettext
import sys
import os
import locale
import logging
#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
from ..const import LOCALE_DIR
from ..constfunc import mac, UNITYPE
#-------------------------------------------------------------------------
#
# Public Constants
#
#-------------------------------------------------------------------------
if "GRAMPSI18N" in os.environ:
LOCALEDIR = os.environ["GRAMPSI18N"]
else:
LOCALEDIR = LOCALE_DIR
if not os.path.exists(LOCALEDIR):
lang = os.environ.get('LANG', 'en')
if lang and lang[:2] == 'en':
pass # No need to display warning, we're in English
else:
logging.warning('Locale dir does not exist at ' + LOCALEDIR)
LOCALEDIR = None
LOCALEDOMAIN = 'gramps'
if mac():
from . import mactrans
mactrans.mac_setup_localization(LOCALEDIR, LOCALEDOMAIN)
else:
lang = ' '
try:
lang = os.environ["LANG"]
except KeyError:
lang = locale.getlocale()[0]
if not lang:
try:
lang = locale.getdefaultlocale()[0] + '.UTF-8'
except TypeError:
logging.warning('Unable to determine your Locale, using English')
lang = 'en.UTF-8'
os.environ["LANG"] = lang
os.environ["LANGUAGE"] = lang
#-------------------------------------------------------------------------
#
# Public Functions
#
#-------------------------------------------------------------------------
def setup_gettext():
"""
Setup the gettext environment.
:returns: Nothing.
"""
gettext.bindtextdomain(LOCALEDOMAIN, LOCALEDIR)
gettext.textdomain(LOCALEDOMAIN)
try:
locale.bindtextdomain(LOCALEDOMAIN, LOCALEDIR)
except ValueError:
logging.warning('Failed to bind text domain, Gtk.Builder() has no translation')
#following installs _ as a python function, we avoid this as this module is
#used sometimes:
#gettext.install(LOCALEDOMAIN, LOCALEDIR, unicode=1)
def find_intl(fname):
"""
Routine for finding if fname is in path
Returns path to fname or None
"""
os_path = os.environ['PATH']
for subpath in os_path.split(';'):
path2file = subpath + '\\' + fname
if os.path.isfile(path2file):
return path2file
return None
def test_trans(str2trans,libintl):
"""
Routine to see if translation works
Returns translated string
"""
transstr = libintl.gettext(str2trans, LOCALEDOMAIN)
return transstr
def init_windows_gettext(intl_path):
"""
Help routine for loading and setting up libintl attributes
Returns libintl
"""
import ctypes
libintl = ctypes.cdll.LoadLibrary(intl_path)
libintl.bindtextdomain(LOCALEDOMAIN,
LOCALEDIR.encode(sys.getfilesystemencoding()))
libintl.textdomain(LOCALEDOMAIN)
libintl.bind_textdomain_codeset(LOCALEDOMAIN, "UTF-8")
libintl.gettext.restype = ctypes.c_char_p
return libintl
def setup_windows_gettext():
"""
Windows specific function for migrating from LibGlade to GtkBuilder
Glade had a Gtk.glade.bindtextdomain() function to define the directory
where to look for translations (.mo-files). It is now replaced with call
to locale.bindtextdomain() which exposes the C librarys gettext
interface on systems that provide this interface.
As MS Standard Runtime C library have not such interface call to
Python's locale.bindtextdomain() is not supported on Windows systems.
To get translation to work we must use gettext runtime library directly
using ctypes.
SEE: https://bugzilla.gnome.org/show_bug.cgi?id=574520
NOTE: officially GTK is built in a way that allows deployment without
gettext runtime library in addition to that for historic reason and
compability libraries are built with MS name style convention like
"intl.dll" but private builds may use posix/ld-linker tradition like
"libintlX-X.dll" which in recent gettext version would be libintl-8.dll
"""
# 0. See if there is a libintl-8.dll in working directory
intl_path = os.path.join(os.getcwd(), 'libintl-8.dll')
if os.path.isfile(intl_path) and not LOCALEDIR is None:
libintl = init_windows_gettext(intl_path)
return
str2translate = "Family Trees - Gramps"
translated = ""
# 1. See if there is a intl.dll in Windows/system
os_path = os.environ['PATH']
intl_path = 'c:\\WINDOWS\\system\\intl.dll'
if os.path.isfile(intl_path) and not LOCALEDIR is None:
libintl = init_windows_gettext(intl_path)
# Now check for translation.
translated = test_trans(str2translate,libintl)
if str2translate != translated:
#Translation complete
return
#2. See if there is a libintl-8.dll in the current path
intl_path = find_intl('\\libintl-8.dll')
if intl_path and not LOCALEDIR is None:
libintl = init_windows_gettext(intl_path)
# Now check for translation.
translated = test_trans(str2translate,libintl)
if str2translate != translated:
#Translation complete
return
#3. See if there is another intl.dll in current path
intl_path = find_intl('\\intl.dll')
if intl_path and not LOCALEDIR is None:
libintl = init_windows_gettext(intl_path)
# Now check for translation.
translated = test_trans(str2translate,libintl)
if str2translate != translated:
#Translation complete
return
# 4. If strings are equal, see if we have English as language
lang = ' '
try:
lang = os.environ["LANG"]
except KeyError:
# if LANG is not set
lang = locale.getlocale()[0]
if not lang:
# if lang is empty/None
lang = locale.getdefaultlocale()[0]
# See if lang begins with en_, English_ or english_
enlang = lang.split('_')[0].lower()
if enlang in ('en', 'english', 'c'):
return
# No complete/working translation found
logging.warning("Translation might not be complete, "
"not working for your locale")
def get_localedomain():
"""
Get the LOCALEDOMAIN used for the Gramps application.
"""
return LOCALEDOMAIN
def get_addon_translator(filename=None, domain="addon", languages=None):
"""
Get a translator for an addon.
filename - filename of a file in directory with full path, or
None to get from running code
domain - the name of the .mo file under the LANG/LC_MESSAGES dir
languages - a list of languages to force
returns - a gettext.translation object
Example:
_ = get_addon_translator(languages=["fr_BE.utf8"]).gettext
The return object has the following properties and methods:
.gettext
.info
.lgettext
.lngettext
.ngettext
.output_charset
.plural
.set_output_charset
.ugettext
.ungettext
Assumes path/filename
path/locale/LANG/LC_MESSAGES/addon.mo.
"""
if filename is None:
filename = sys._getframe(1).f_code.co_filename
gramps_translator = gettext.translation(LOCALEDOMAIN, LOCALEDIR,
fallback=True)
path = os.path.dirname(os.path.abspath(filename))
# Check if path is of type str. Do import and conversion if so.
# The import cannot be done at the top as that will conflict with the translation system.
if not isinstance(path, UNITYPE):
from .file import get_unicode_path_from_env_var
path = get_unicode_path_from_env_var(path)
if languages:
addon_translator = gettext.translation(domain,
os.path.join(path, "locale"),
languages=languages,
fallback=True)
else:
addon_translator = gettext.translation(domain,
os.path.join(path, "locale"),
fallback=True)
gramps_translator.add_fallback(addon_translator)
return gramps_translator # with a language fallback
def get_available_translations():
"""
Get a list of available translations.
:returns: A list of translation languages.
:rtype: unicode[]
"""
languages = ["en"]
if LOCALEDIR is None:
return languages
for langdir in os.listdir(LOCALEDIR):
mofilename = os.path.join( LOCALEDIR, langdir,
"LC_MESSAGES", "%s.mo" % LOCALEDOMAIN )
if os.path.exists(mofilename):
languages.append(langdir)
languages.sort()
return languages
def trans_objclass(objclass_str):
"""
Translates objclass_str into "... %s", where objclass_str
is 'Person', 'person', 'Family', 'family', etc.
"""
from ..ggettext import gettext as _
objclass = objclass_str.lower()
if objclass == "person":
return _("the person")
elif objclass == "family":
return _("the family")
elif objclass == "place":
return _("the place")
elif objclass == "event":
return _("the event")
elif objclass == "repository":
return _("the repository")
elif objclass == "note":
return _("the note")
elif objclass in ["media", "mediaobject"]:
return _("the media")
elif objclass == "source":
return _("the source")
elif objclass == "filter":
return _("the filter")
else:
return _("See details")

View File

@ -53,7 +53,7 @@ from subprocess import Popen, PIPE
# GRAMPS modules
#
#-------------------------------------------------------------------------
from .gen.const import APP_GRAMPS, USER_DIRLIST, HOME_DIR, VERSION_TUPLE
from .gen.const import APP_GRAMPS, USER_DIRLIST, HOME_DIR, VERSION_TUPLE, GRAMPS_LOCALE
from .gen.constfunc import win
#-------------------------------------------------------------------------
#
@ -113,62 +113,14 @@ def exc_hook(type, value, tb):
sys.excepthook = exc_hook
from .gen.mime import mime_type_is_defined
from .gen.utils.trans import LOCALEDOMAIN, LOCALEDIR, setup_windows_gettext
from .gen.utils.grampslocale import GrampsLocale
#-------------------------------------------------------------------------
#
# Load internationalization setup
#
#-------------------------------------------------------------------------
#the order in which bindtextdomain on gettext and on locale is called
#appears important, so we refrain from doing first all gettext.
#
#setup_gettext()
gettext.bindtextdomain(LOCALEDOMAIN, LOCALEDIR)
try:
locale.setlocale(locale.LC_ALL,'')
except:
logging.warning(_("WARNING: Setting locale failed. Please fix the "
"LC_* and/or the LANG environment variables to prevent this error"))
try:
# It is probably not necessary to set the locale to 'C'
# because the locale will just stay at whatever it was,
# which at startup is "C".
# however this is done here just to make sure that the locale
# functions are working
locale.setlocale(locale.LC_ALL,'C')
except:
logging.warning(_("ERROR: Setting the 'C' locale didn't work either"))
# FIXME: This should propagate the exception,
# if that doesn't break Gramps under Windows
# raise
gettext.textdomain(LOCALEDOMAIN)
if sys.version_info[0] < 3:
gettext.install(LOCALEDOMAIN, localedir=None, unicode=1) #None is sys default locale
else:
gettext.install(LOCALEDOMAIN, localedir=None) #None is sys default locale
if hasattr(os, "uname"):
operating_system = os.uname()[0]
else:
operating_system = sys.platform
if win(): # Windows
setup_windows_gettext()
elif operating_system == 'FreeBSD':
try:
gettext.bindtextdomain(LOCALEDOMAIN, LOCALEDIR)
except locale.Error:
logging.warning('No translation in some Gtk.Builder strings, ')
elif operating_system == 'OpenBSD':
pass
else: # normal case
try:
locale.bindtextdomain(LOCALEDOMAIN, LOCALEDIR)
#locale.textdomain(LOCALEDOMAIN)
except locale.Error:
logging.warning('No translation in some Gtk.Builder strings, ')
const.GRAMPS_LOCALE = GrampsLocale()
#-------------------------------------------------------------------------
#
@ -489,4 +441,4 @@ def main():
logging.warning(error[0] + error[1])
if __name__ == '__main__':
main()
main()

View File

@ -57,7 +57,7 @@ from gramps.gen.datehandler import get_date
from .display import display_help
from .managedwindow import ManagedWindow
from gramps.gen.ggettext import sgettext as _
from gramps.gen.utils.trans import trans_objclass
from gramps.gen.utils.grampslocale import trans_objclass
from gramps.gen.constfunc import mac
from .glade import Glade
from .ddtargets import DdTargets

View File

@ -49,7 +49,7 @@ from gi.repository import Gtk
#
#------------------------------------------------------------------------
from gramps.gen.const import GLADE_DIR
from gramps.gen.utils.trans import LOCALEDOMAIN
from gramps.gen.utils.grampslocale import LOCALEDOMAIN
from gramps.gen.constfunc import STRTYPE
#------------------------------------------------------------------------

View File

@ -54,7 +54,7 @@ from gi.repository import Gtk
#-------------------------------------------------------------------------
from gramps.gen.ggettext import sgettext as _
from gramps.gen.simple import SimpleTable
from gramps.gen.utils.trans import trans_objclass
from gramps.gen.utils.grampslocale import trans_objclass
from gramps.gen.errors import WindowActiveError
from ...widgets.multitreeview import MultiTreeView
from ...ddtargets import DdTargets

View File

@ -37,7 +37,7 @@ _ = gettext.gettext
# GRAMPS modules
#
#------------------------------------------------------------------------
from gramps.gen.utils.trans import get_localedomain
from gramps.gen.utils.grampslocale import get_localedomain
from gramps.gen.datehandler import displayer, LANG_TO_DISPLAY
from gramps.gen.config import config
from gramps.gen.lib.grampstype import GrampsType

View File

@ -50,7 +50,7 @@ from gramps.gen.plug.docgen import (IndexMark, FontStyle, ParagraphStyle,
from gramps.gen.plug.report import Report
from gramps.gen.plug.report import utils as ReportUtils
from gramps.gen.plug.report import MenuReportOptions
from gramps.gen.utils.trans import get_available_translations
from gramps.gen.utils.grampslocale import get_available_translations
from gramps.plugins.lib.libnarrate import Narrator
from gramps.plugins.lib.libtranslate import Translator, get_language_string

View File

@ -54,7 +54,7 @@ from gramps.gen.plug.report import endnotes
from gramps.gen.plug.report import utils as ReportUtils
from gramps.gen.plug.report import MenuReportOptions
from gramps.plugins.lib.libnarrate import Narrator
from gramps.gen.utils.trans import get_available_translations
from gramps.gen.utils.grampslocale import get_available_translations
from gramps.plugins.lib.libtranslate import Translator, get_language_string
#------------------------------------------------------------------------

View File

@ -58,7 +58,7 @@ from gramps.gen.plug.report import endnotes
from gramps.gen.plug.report import utils as ReportUtils
from gramps.gen.plug.report import MenuReportOptions
from gramps.plugins.lib.libnarrate import Narrator
from gramps.gen.utils.trans import get_available_translations
from gramps.gen.utils.grampslocale import get_available_translations
from gramps.plugins.lib.libtranslate import Translator, get_language_string
#------------------------------------------------------------------------