Localization seems difficult to me in the moment. It works like that that
the user defines a lot of entries in weewx.conf or skin.conf.
The disadvantages are to me:
- It makes the configuration files very long.
- Changing localization involes changing lots of entries.
- Skins cannot come with multiple localizations included.
So I thought about it for a long time, and I gave it a try. I want to
present a possible solution.
To simplify the process a localization file is used that is referenced in
weewx.conf. To change localization simply the file name is changed. Then
the values come from another file. Each localization file has the same
structure as skin.conf. If the localization file has no entry for a label
the value from weewx.conf or skin.conf is returned instead.
Usage is simple: for example $locale('obs.label.outTemp') looks for an
entry 'outTemp' in section [Labels][[Generic]] in the localization file. It
it is there, its value is returned. Otherwise the value from skin_dict is
returned.
Advantages are:
- Label value texts can be "outsourced" to separate files.
- Localization can be changed by changing one single entry.
- Skin authors can ship their packages with multiple localizations
included.
- No breaking changes.
An alternative to that solution would be to include the localization lookup
into the standard $obs.label... or $Extras... lookup.
--
You received this message because you are subscribed to the Google Groups
"weewx-development" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/weewx-development/259e43e6-efe9-467e-9949-862dda0f13c8n%40googlegroups.com.
# Copyright (C) 2021 Johanna Roedenbeck
"""
SearchList extension to simplify localization
advantages:
* change one entry only to change localization
* skin author can provide multiple languages within installation package
usage:
Instead of using label tags directly, they are used as parameter to
the $locale() tag. $locale() provides a language dependent label
string if some is available und otherwise the entry from weewx.conf
or skin.conf
Example:
$locale('obs.label.outTemp')
The extension looks in the appropriate localization file for an entry.
If it finds one it returns it. If it finds no entry the value from
skin_dict (weewx.conf or skin.conf) is returned.
The extension needs an additional entry called 'lang_file' directly
in the skin section of weewx.conf. It points to the localization
file to use. Relative paths are relative to the skin directory.
The localization file has the same structure as the skin.conf file.
Entries that depend on language need to be defined there, only.
Other entries remain defined in weewx.conf or skin.conf
The localization file is not restricted to "Extras" and "Labels"
section, but can process all sections of the file.
"""
from weewx.cheetahgenerator import SearchList
from weewx.units import ValueTuple,ValueHelper
import configobj
import weeutil.weeutil
import os
import os.path
try:
# Test for new-style weewx v4 logging by trying to import weeutil.logger
import weeutil.logger
import logging
log = logging.getLogger(__name__)
def logdbg(msg):
log.debug(msg)
def loginf(msg):
log.info(msg)
def logerr(msg):
log.error(msg)
except ImportError:
# Old-style weewx logging
import syslog
def logmsg(level, msg):
syslog.syslog(level, 'skin_locale: %s' % msg)
def logdbg(msg):
logmsg(syslog.LOG_DEBUG, msg)
def loginf(msg):
logmsg(syslog.LOG_INFO, msg)
def logerr(msg):
logmsg(syslog.LOG_ERR, msg)
class SkinLocaleSearchList(SearchList):
def nested(self,search_dict,keys):
""" get value from structured dict
search_dict: contents of the localization file as dict
keys: array of keys
"""
try:
x=search_dict[keys[0]]
except (KeyError,IndexError):
return None
# if no more keys or result is no dict anymore
if len(keys)==1 or not isinstance(x,dict):
return x
# next level
return self.nested(x,keys[1:])
def get_extension_list(self,timespan,db_lookup):
# get language file name
try:
lang_file = self.generator.skin_dict['lang_file']
except (KeyError,IndexError):
lang_file = ""
# if path is relative get skin directory
try:
ww=self.generator.config_dict['WEEWX_ROOT']
xx=self.generator.config_dict['StdReport']['SKIN_ROOT']
yy=self.generator.skin_dict['skin']
zz=os.path.join(ww,xx,yy)
except (KeyError,IndexError):
zz = ''
# get dict from language file or empty dict if not defined
if lang_file is not None and lang_file:
lang_file=os.path.join(zz,lang_file)
d=configobj.ConfigObj(lang_file)
else:
d={}
# localization dict
self.lang_dict=d
def locale_label(expression):
key=expression.split('.')
# obs.label.observation_type is in ['Label']['Generic']
if len(key)>2 and key[0]=='obs' and key[1]=='label':
key[0]='Labels'
key[1]='Generic'
# get value from localization dict
val = self.nested(self.lang_dict,key)
# if no value is defined there, fall back to skin_dict
if val is None:
try:
if key[0].lower()=='extras':
val = self.generator.skin_dict['Extras'][key[1]]
elif key[0].lower()=='labels' and key[1].lower()=='generic':
val = self.generator.skin_dict['Labels']['Generic'][key[2]]
elif key[0].lower()=='almanac':
val = self.generator.skin_dict['Almanac'][key[1]]
else:
val = ""
except (KeyError,IndexError,ValueError):
val = ""
return val
return [{'locale':locale_label}]