summaryrefslogtreecommitdiff
path: root/babel/localedata.py
diff options
context:
space:
mode:
authorChristopher Lenz <cmlenz@gmail.com>2008-07-07 14:49:16 +0000
committerChristopher Lenz <cmlenz@gmail.com>2008-07-07 14:49:16 +0000
commit4a6c0f5e1ba853040bf83466e2e2b865c2b76476 (patch)
treeffd6a20b8617ee7b23eb71a41c7c0d863c1d9f69 /babel/localedata.py
parent9a9cdfa12b49e34f0c6020d27c95c55d7ad9e29e (diff)
downloadbabel-4a6c0f5e1ba853040bf83466e2e2b865c2b76476.tar.gz
Implement support for aliases in the CLDR data. Closes #68. Also, update to CLDR 1.6, and a much improved `dump_data` script.
Diffstat (limited to 'babel/localedata.py')
-rw-r--r--babel/localedata.py101
1 files changed, 91 insertions, 10 deletions
diff --git a/babel/localedata.py b/babel/localedata.py
index 40ac6aa..5a76f6a 100644
--- a/babel/localedata.py
+++ b/babel/localedata.py
@@ -23,14 +23,16 @@ try:
import threading
except ImportError:
import dummy_threading as threading
+from UserDict import DictMixin
-__all__ = ['exists', 'load']
+__all__ = ['exists', 'list', 'load']
__docformat__ = 'restructuredtext en'
_cache = {}
_cache_lock = threading.RLock()
_dirname = os.path.join(os.path.dirname(__file__), 'localedata')
+
def exists(name):
"""Check whether locale data is available for the given locale.
@@ -42,6 +44,7 @@ def exists(name):
return True
return os.path.exists(os.path.join(_dirname, '%s.dat' % name))
+
def list():
"""Return a list of all locale identifiers for which locale data is
available.
@@ -54,7 +57,8 @@ def list():
os.path.splitext(filename) for filename in os.listdir(_dirname)
] if extension == '.dat' and stem != 'root']
-def load(name):
+
+def load(name, merge_inherited=True):
"""Load the locale data for the given locale.
The locale data is a dictionary that contains much of the data defined by
@@ -74,6 +78,8 @@ def load(name):
True
:param name: the locale identifier string (or "root")
+ :param merge_inherited: whether the inherited data should be merged into
+ the data of the requested locale
:return: the locale data
:rtype: `dict`
:raise `IOError`: if no locale data file is found for the given locale
@@ -84,7 +90,7 @@ def load(name):
data = _cache.get(name)
if not data:
# Load inherited data
- if name == 'root':
+ if name == 'root' or not merge_inherited:
data = {}
else:
parts = name.split('_')
@@ -96,7 +102,7 @@ def load(name):
filename = os.path.join(_dirname, '%s.dat' % name)
fileobj = open(filename, 'rb')
try:
- if name != 'root':
+ if name != 'root' and merge_inherited:
merge(data, pickle.load(fileobj))
else:
data = pickle.load(fileobj)
@@ -107,17 +113,92 @@ def load(name):
finally:
_cache_lock.release()
+
def merge(dict1, dict2):
"""Merge the data from `dict2` into the `dict1` dictionary, making copies
of nested dictionaries.
+ >>> d = {1: 'foo', 3: 'baz'}
+ >>> merge(d, {1: 'Foo', 2: 'Bar'})
+ >>> d
+ {1: 'Foo', 2: 'Bar', 3: 'baz'}
+
:param dict1: the dictionary to merge into
:param dict2: the dictionary containing the data that should be merged
"""
- for key, value in dict2.items():
- if value is not None:
- if type(value) is dict:
- dict1[key] = dict1.get(key, {}).copy()
- merge(dict1[key], value)
+ for key, val2 in dict2.items():
+ if val2 is not None:
+ val1 = dict1.get(key)
+ if isinstance(val2, dict):
+ if val1 is None:
+ val1 = {}
+ if isinstance(val1, Alias):
+ val1 = (val1, val2)
+ elif isinstance(val1, tuple):
+ alias, others = val1
+ others = others.copy()
+ merge(others, val2)
+ val1 = (alias, others)
+ else:
+ val1 = val1.copy()
+ merge(val1, val2)
else:
- dict1[key] = value
+ val1 = val2
+ dict1[key] = val1
+
+
+class Alias(object):
+ """Representation of an alias in the locale data.
+
+ An alias is a value that refers to some other part of the locale data,
+ as specified by the `keys`.
+ """
+
+ def __init__(self, keys):
+ self.keys = tuple(keys)
+
+ def __repr__(self):
+ return '<%s %r>' % (type(self).__name__, self.keys)
+
+ def resolve(self, data):
+ """Resolve the alias based on the given data.
+
+ This is done recursively, so if one alias resolves to a second alias,
+ that second alias will also be resolved.
+
+ :param data: the locale data
+ :type data: `dict`
+ """
+ base = data
+ for key in self.keys:
+ data = data[key]
+ if isinstance(data, Alias):
+ data = data.resolve(base)
+ return data
+
+
+class LocaleDataDict(DictMixin, dict):
+ """Dictionary wrapper that automatically resolves aliases to the actual
+ values.
+ """
+
+ def __init__(self, data, base=None):
+ dict.__init__(self, data)
+ if base is None:
+ base = self
+ self.base = base
+
+ def __getitem__(self, key):
+ val = dict.__getitem__(self, key)
+ if isinstance(val, Alias): # resolve an alias
+ val = val.resolve(self.base)
+ if isinstance(val, tuple): # Merge a partial dict with an alias
+ alias, others = val
+ val = alias.resolve(self.base).copy()
+ merge(val, others)
+ if isinstance(val, dict): # Return a nested alias-resolving dict
+ val = LocaleDataDict(val, base=self.base)
+ return val
+
+ def copy(self):
+ return LocaleDataDict(dict.copy(self), base=self.base)