gettext interface cleaned up

error handling improved
This commit is contained in:
lars 2006-11-29 14:02:33 +00:00
parent d1c4835d8e
commit 210c27a495
7 changed files with 102 additions and 92 deletions

View File

@ -203,21 +203,6 @@ class CryptoBoxProps(CryptoBox):
return None
def getAvailableLanguages(self):
'''reads all files in path LangDir and returns a list of
basenames from existing hdf files, that should are all available
languages'''
# TODO: for now we hardcode it - change this!
return "en fr si de".split(" ")
# TODO: old implementation (before gettext) - remove it
languages = [ f.rstrip(".hdf")
for f in os.listdir(self.prefs["Locations"]["LangDir"])
if f.endswith(".hdf") ]
if len(languages) < 1:
self.log.error("No .hdf files found! The website won't render properly.")
return languages
def sendEventNotification(self, event, event_infos):
"""call all available scripts in the event directory with some event information"""
event_dir = self.prefs["Locations"]["EventDir"]

View File

@ -355,7 +355,7 @@ DefaultVolumePrefix = string(min=1)
DefaultCipher = string(default="aes-cbc-essiv:sha256")
ConfigVolumeLabel = string(min=1, default="cbox_config")
UseConfigPartition = integer(min=0, max=1, default=0)
DisabledPlugins = list(default=[])
DisabledPlugins = list(default=list())
[Locations]
MountParentDir = directoryExists(default="/var/cache/cryptobox-server/mnt")
@ -373,7 +373,7 @@ Details = string(min=1)
[WebSettings]
Stylesheet = string(min=1)
Language = string(min=1, default="en")
Languages = list(min=1,default=list("en"))
[Programs]
cryptsetup = fileExecutable(default="/sbin/cryptsetup")

View File

@ -29,11 +29,12 @@ class CryptoBoxPlugin:
fallbackIconFileName = "plugin_icon_unknown.gif"
def __init__(self, cbox, pluginDir):
def __init__(self, cbox, pluginDir, siteClass=None):
self.cbox = cbox
self.hdf = {}
self.pluginDir = pluginDir
self.hdf_prefix = "Data.Plugins.%s." % self.getName()
self.site = siteClass

View File

@ -8,9 +8,10 @@ import logging
class PluginManager:
"""manage available plugins"""
def __init__(self, cbox, plugin_dirs="."):
def __init__(self, cbox, plugin_dirs=".", siteClass=None):
self.cbox = cbox
self.log = logging.getLogger("CryptoBox")
self.site = siteClass
if hasattr(plugin_dirs, "__iter__"):
self.plugin_dirs = [os.path.abspath(dir) for dir in plugin_dirs]
else:
@ -43,7 +44,7 @@ class PluginManager:
pl_class = getattr(imp.load_source(name, plfile), name)
except AttributeError:
return None
return pl_class(self.cbox, os.path.dirname(plfile))
return pl_class(self.cbox, os.path.dirname(plfile), self.site)
else:
return None

View File

@ -22,13 +22,19 @@ class WebInterfaceDataset(dict):
def setCryptoBoxState(self):
import cherrypy
import cryptobox.core.main
import cryptobox.web.languages
self["Data.Version"] = cryptobox.core.main.VERSION
langs = self.cbox.getAvailableLanguages()
langs = self.cbox.prefs["WebSettings"]["Languages"]
langs.sort()
for (index, lang) in enumerate(langs):
self.cbox.log.info("language loaded: %s" % lang)
self["Data.Languages.%d.name" % index] = lang
self["Data.Languages.%d.link" % index] = self.__getLanguageName(lang)
try:
(langname, plural_info) = cryptobox.web.languages.LANGUAGE_INFO[lang]
self["Data.Languages.%d.link" % index] = langname
self["Data.Languages.%d.name" % index] = lang
self.cbox.log.info("language loaded: %s" % lang)
except KeyError:
## language was not found
self.cbox.log.warn("invalid language specified in configuration: %s" % lang)
try:
self["Data.ScriptURL.Prot"] = cherrypy.request.scheme
host = cherrypy.request.headers["Host"]
@ -122,7 +128,7 @@ class WebInterfaceDataset(dict):
self["Settings.LanguageDir"] = os.path.abspath(self.prefs["Locations"]["LangDir"])
self["Settings.DocDir"] = os.path.abspath(self.prefs["Locations"]["DocDir"])
self["Settings.Stylesheet"] = self.prefs["WebSettings"]["Stylesheet"]
self["Settings.Language"] = self.prefs["WebSettings"]["Language"]
self["Settings.Language"] = self.prefs["WebSettings"]["Languages"][0]
self["Settings.PluginDir"] = self.prefs["Locations"]["PluginDir"]
self["Settings.SettingsDir"] = self.prefs["Locations"]["SettingsDir"]

View File

@ -0,0 +1,23 @@
"""supply information about existing languages
"""
## every language information should contain (name, pluralformat)
LANGUAGE_INFO = {
"cs": ('Český', ('3', '(n==1) ? 0 : (n>=2 && n< =4) ? 1 : 2')),
"da": ('Dansk', ('2', '(n != 1)')),
"de": ('Deutsch', ('2', '(n != 1)')),
"en": ('English', ('2', '(n != 1)')),
"es": ('Español', ('2', '(n != 1)')),
"fi": ('Suomi', ('2', '(n != 1)')),
"fr": ('Français', ('2', '(n != 1)')),
"hu": ('Magyar', ('1', '0')),
"it": ('Italiano', ('2', '(n != 1)')),
"ja": ('日本語', ('1', '0')),
"nl": ('Nederlands', ('2', '(n != 1)')),
"pl": ('Polski', ('3', '(n==1 ? 0 : n%10>=2 && n%10< =4 && (n%100<10 || n%100>=20) ? 1 : 2)')),
"pt": ('Português', ('2', '(n != 1)')),
"ru": ('Русский', ('3', '(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10< =4 && (n%100<10 || n%100>=20) ? 1 : 2)')),
"sl": ('Slovensko', ('4', '(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3)')),
"sv": ('Svenska', ('2', '(n != 1)')),
}

View File

@ -46,6 +46,8 @@ class WebInterfaceSites:
self.__resetDataset()
## store the original http error handler
self._cp_on_http_error = self.newHTTPErrorHandler
## set initial language order
self.langOrder = self.cbox.prefs["WebSettings"]["Languages"]
def __resetDataset(self):
@ -64,7 +66,7 @@ class WebInterfaceSites:
def __loadPlugins(self):
self.pluginList = cryptobox.plugins.manage.PluginManager(self.cbox, self.prefs["Locations"]["PluginDir"])
self.pluginList = cryptobox.plugins.manage.PluginManager(self.cbox, self.prefs["Locations"]["PluginDir"], self)
for plugin in self.pluginList.getPlugins():
if not plugin: continue
plname = plugin.getName()
@ -134,6 +136,14 @@ class WebInterfaceSites:
return self.return_plugin_action(self.pluginList.getPlugin("disks"))(**param_dict)
def newHTTPErrorHandler(self, errorCode, message):
"""handle http errors gracefully
404 - not found errors: ignored if url is below /cryptobox-misc/
other 404 errors: send the error code and return a nice informative page
500 - runtime errors: return "ok" exit code and show a polite excuse
others: are there any other possible http errors?
"""
import traceback, sys
## we ignore uninteresting not-found errors
if (errorCode == 404) and \
(cherrypy.request.path.startswith("/cryptobox-misc/") or \
@ -151,8 +161,10 @@ class WebInterfaceSites:
if errorCode == 500:
## we fix the error code (200 is "OK")
cherrypy.response.status = 200
## TODO: 'message' is None - we should check a stack trace or something?
self.cbox.log.warn("HTTP-ERROR[500] - a runtime error occoured: %s" % str(message))
self.cbox.log.error("HTTP-ERROR[500] - a runtime error occoured: %s" % str(message))
## add a traceback and exception information to the lo
for a in traceback.format_exception(*sys.exc_info()):
self.cbox.log.error("\t%s" % a)
self.dataset["Data.Warning"] = "RuntimeError"
cherrypy.response.body = self.__render("empty")
return
@ -285,7 +297,8 @@ class WebInterfaceSites:
examples are: non-https, readonly-config, ...
"""
## TODO: maybe add an option "mount" (if it is available, but inactive)?
## this check is done _after_ "resetDataSet" -> a possible config partition was
## loaded before
if self.cbox.prefs.requiresPartition() and not self.cbox.prefs.getActivePartition():
self.dataset["Data.EnvironmentWarning"] = "ReadOnlyConfig"
# TODO: turn this on soon (add "not") - for now it is annoying
@ -311,31 +324,28 @@ class WebInterfaceSites:
def __setWebLang(self, value):
guess = value
availLangs = self.cbox.getAvailableLanguages()
## no language specified: check browser language
if not guess:
guess = self.__getPreferredBrowserLanguage(availLangs)
## no preferred language or invalid language?
if not guess \
or not guess in availLangs \
or re.search(u'\W', guess):
## warn only for invalid languages
if not guess is None:
self.cbox.log.info("invalid language choosen: %s" % guess)
guess = self.prefs["WebSettings"]["Language"]
## maybe the language is still not valid
if not guess in availLangs:
self.log.warn("the configured language is invalid: %s" % guess)
guess = "en"
## maybe there is no english dataset???
if not guess in availLangs:
self.log.warn("couldn't find the english dataset")
guess = availLangs[0]
self.dataset["Settings.Language"] = guess
## we only have to save it, if it was specified correctly and explicitly
if value == guess:
self.dataset["Settings.LinkAttrs.weblang"] = guess
"""set the preferred priority of languages according to the following order:
1. language selected via web interface
2. preferred browser language setting
3. languages defined in the config file
"""
## start with the configured language order
langOrder = self.cbox.prefs["WebSettings"]["Languages"][:]
## put the preferred browser language in front
guess = self.__getPreferredBrowserLanguage(langOrder)
if guess:
langOrder.remove(guess)
langOrder.insert(0,guess)
## is the chosen language (via web interface) valid? - put it in front
if value and (value in langOrder) and (not re.search(u'\W',value)):
langOrder.remove(value)
langOrder.insert(0,value)
elif value:
self.cbox.log.info("invalid language selected: %s" % value)
## store current language setting
self.langOrder = langOrder
self.dataset["Settings.Language"] = langOrder[0]
self.dataset["Settings.LinkAttrs.weblang"] = langOrder[0]
def __getPreferredBrowserLanguage(self, availLangs):
@ -366,6 +376,8 @@ class WebInterfaceSites:
def __setDevice(self, device):
"""check a device name that was chosen via the web interface
issue a warning if the device is invalid"""
if device and re.match(u'[\w /\-]+$', device) and self.cbox.getContainer(device):
self.log.debug("select device: %s" % device)
return True
@ -375,19 +387,10 @@ class WebInterfaceSites:
return False
def __checkVolumeName(self, name):
if name and re.match(u'[\w \-]+$', name):
return True
else:
return False
def __getLanguageValue(self, value):
hdf = self.__getLanguageData(self.dataset["Settings.Language"])
return hdf.getValue(value, "")
def __substituteGettext(self, languages, textDomain, hdf):
"""substitute all texts in the hdf dataset with their translated
counterparts as returned by gettext
"""
import gettext
try:
translator = gettext.translation(textDomain, languages=languages)
@ -407,41 +410,32 @@ class WebInterfaceSites:
walk_tree(hdf)
def __getLanguageData(self, web_lang="en"):
def __getLanguageData(self):
"""return the hdf dataset of the main interface and all plugins
translations are done according to self.langOrder
"""
## check if the language setting was changed - use cached data if possible
try:
if self.cachedLanguageData["langOrder"] == self.langOrder:
self.cbox.log.debug("using cached language data")
return self.cachedLanguageData["hdf"]
except AttributeError:
pass
self.cbox.log.debug("generating language data")
hdf = neo_util.HDF()
hdf.readFile(os.path.join(self.prefs["Locations"]["TemplateDir"],"language.hdf"))
self.__substituteGettext([web_lang], GETTEXT_DOMAIN, hdf)
self.__substituteGettext(self.langOrder, GETTEXT_DOMAIN, hdf)
## load the language data of all plugins
for p in self.pluginList.getPlugins():
pl_lang = p.getLanguageData()
self.__substituteGettext([web_lang], "%s-feature-%s" % (GETTEXT_DOMAIN, p.getName()), pl_lang)
self.__substituteGettext(self.langOrder, "%s-feature-%s" % (GETTEXT_DOMAIN, p.getName()), pl_lang)
hdf.copy("Plugins.%s" % p.getName(), pl_lang)
self.cbox.log.debug("language data for plugin loaded: %s" % p.getName())
## cache result for later retrieval
self.cachedLanguageData = {"langOrder": self.langOrder, "hdf": hdf}
return hdf
def __getLanguageData2(self, web_lang="en"):
default_lang = "en"
conf_lang = self.prefs["WebSettings"]["Language"]
hdf = neo_util.HDF()
langDir = os.path.abspath(self.prefs["Locations"]["LangDir"])
langFiles = []
## first: read default language (en)
if (default_lang != conf_lang) and (default_lang != web_lang):
langFiles.append(os.path.join(langDir, default_lang + ".hdf"))
## second: read language as defined in the config file
if (conf_lang != web_lang):
langFiles.append(os.path.join(langDir, conf_lang + ".hdf"))
## third: read language as configured via web interface
langFiles.append(os.path.join(langDir, web_lang + ".hdf"))
for langFile in langFiles:
if os.access(langFile, os.R_OK):
hdf.readFile(langFile)
else:
log.warn("Couldn't read language file: %s" % langFile)
return hdf
def __render(self, renderInfo, plugin=None):
'''renders from clearsilver templates and returns the resulting html
'''
@ -457,7 +451,7 @@ class WebInterfaceSites:
## load the language data
hdf = neo_util.HDF()
hdf.copy("Lang", self.__getLanguageData(self.dataset["Settings.Language"]))
hdf.copy("Lang", self.__getLanguageData())
## first: assume, that the template file is in the global template directory
self.dataset["Settings.TemplateFile"] = os.path.abspath(os.path.join(self.prefs["Locations"]["TemplateDir"], template + ".cs"))