Ticket #68: cldr_aliases.3.diff
| File cldr_aliases.3.diff, 20.5 KB (added by cmlenz, 4 years ago) |
|---|
-
babel/core.py
223 223 224 224 def _data(self): 225 225 if self.__data is None: 226 self.__data = localedata. load(str(self))226 self.__data = localedata.LocaleDataDict(localedata.load(str(self))) 227 227 return self.__data 228 228 _data = property(_data) 229 229 … … 326 326 Mapping of script codes to translated script names. 327 327 328 328 >>> Locale('de', 'DE').variants['1901'] 329 u' alte deutsche Rechtschreibung'329 u'Alte deutsche Rechtschreibung' 330 330 331 331 :type: `dict` 332 332 """) … … 481 481 >>> Locale('en', 'US').time_zones['Europe/London']['long']['daylight'] 482 482 u'British Summer Time' 483 483 >>> Locale('en', 'US').time_zones['America/St_Johns']['city'] 484 u 'St. John\u2019s'484 u"St. John's" 485 485 486 486 :type: `dict` 487 487 """) -
babel/localedata.py
23 23 import threading 24 24 except ImportError: 25 25 import dummy_threading as threading 26 from UserDict import DictMixin 26 27 27 28 __all__ = ['exists', 'load'] 28 29 __docformat__ = 'restructuredtext en' … … 31 32 _cache_lock = threading.RLock() 32 33 _dirname = os.path.join(os.path.dirname(__file__), 'localedata') 33 34 35 34 36 def exists(name): 35 37 """Check whether locale data is available for the given locale. 36 38 … … 42 44 return True 43 45 return os.path.exists(os.path.join(_dirname, '%s.dat' % name)) 44 46 47 45 48 def list(): 46 49 """Return a list of all locale identifiers for which locale data is 47 50 available. … … 54 57 os.path.splitext(filename) for filename in os.listdir(_dirname) 55 58 ] if extension == '.dat' and stem != 'root'] 56 59 60 57 61 def load(name): 58 62 """Load the locale data for the given locale. 59 63 … … 107 111 finally: 108 112 _cache_lock.release() 109 113 114 110 115 def merge(dict1, dict2): 111 116 """Merge the data from `dict2` into the `dict1` dictionary, making copies 112 117 of nested dictionaries. 113 118 119 >>> d = {1: 'foo', 3: 'baz'} 120 >>> merge(d, {1: 'Foo', 2: 'Bar'}) 121 >>> d 122 {1: 'Foo', 2: 'Bar', 3: 'baz'} 123 124 >>> d = {1: {1: 'FOO', 2: 'BAR'}, 2: 'foo'} 125 >>> merge(d, {1: {3: 'BAZ'}}) 126 >>> d 127 {1: {1: 'FOO', 2: 'BAR', 3: 'BAZ'}, 2: 'foo'} 128 114 129 :param dict1: the dictionary to merge into 115 130 :param dict2: the dictionary containing the data that should be merged 116 131 """ 117 for key, value in dict2.items(): 118 if value is not None: 119 if type(value) is dict: 120 dict1[key] = dict1.get(key, {}).copy() 121 merge(dict1[key], value) 132 for key, val2 in dict2.items(): 133 if val2 is not None: 134 if type(val2) is dict: 135 val1 = dict1.get(key, {}) 136 if type(val1) is Alias: 137 dict1[key] = (val1, val2) 138 else: 139 dict1[key] = val1.copy() 140 merge(dict1[key], val2) 141 elif type(val2) is Alias: 142 dict1[key] = (val2, dict1[key]) 122 143 else: 123 dict1[key] = value 144 val1 = dict1.get(key) 145 if type(val1) is Alias: 146 dict1[key] = (val1, val2) 147 else: 148 dict1[key] = val2 149 150 151 class Alias(object): 152 153 def __init__(self, keys): 154 self.keys = keys 155 156 def __repr__(self): 157 return '<%s %r>' % (type(self).__name__, self.keys) 158 159 def resolve(self, data): 160 base = data 161 for key in self.keys: 162 data = data[key] 163 if type(data) is Alias: 164 data = data.resolve(base) 165 return data 166 167 168 class LocaleDataDict(DictMixin, dict): 169 170 def __init__(self, data, base=None): 171 dict.__init__(self, data) 172 if base is None: 173 base = self 174 self.base = base 175 176 def __getitem__(self, key): 177 val = dict.__getitem__(self, key) 178 if type(val) is Alias: # resolve an alias 179 val = val.resolve(self.base) 180 if type(val) is tuple: # Merge a partial dict with an alias 181 alias, others = val 182 val = alias.resolve(self.base).copy() 183 merge(val, others) 184 if type(val) is dict: # Return a nested alias-resolving dict 185 val = LocaleDataDict(val, base=self.base) 186 return val 187 188 def copy(self): 189 return LocaleDataDict(dict.copy(self), base=self.base) -
babel/tests/localedata.py
16 16 17 17 from babel import localedata 18 18 19 20 class MergeResolveTestCase(unittest.TestCase): 21 22 def test_merge_items(self): 23 d = {1: 'foo', 3: 'baz'} 24 localedata.merge(d, {1: 'Foo', 2: 'Bar'}) 25 self.assertEqual({1: 'Foo', 2: 'Bar', 3: 'baz'}, d) 26 27 def test_merge_nested_dict(self): 28 d1 = { 29 'x': {'a': 1, 'b': 2, 'c': 3} 30 } 31 d2 = { 32 'x': {'a': 1, 'b': 12, 'd': 14} 33 } 34 localedata.merge(d1, d2) 35 self.assertEqual({ 36 'x': {'a': 1, 'b': 12, 'c': 3, 'd': 14} 37 }, d1) 38 39 40 def test_merge_with_alias_and_resolve(self): 41 alias = localedata.Alias('x') 42 d1 = { 43 'x': {'a': 1, 'b': 2, 'c': 3}, 44 'y': alias 45 } 46 d2 = { 47 'x': {'a': 1, 'b': 12, 'd': 14}, 48 'y': {'b': 22, 'e': 25} 49 } 50 localedata.merge(d1, d2) 51 self.assertEqual({ 52 'x': {'a': 1, 'b': 12, 'c': 3, 'd': 14}, 53 'y': (alias, {'b': 22, 'e': 25}) 54 }, d1) 55 d = localedata.LocaleDataDict(d1) 56 self.assertEqual({ 57 'x': {'a': 1, 'b': 12, 'c': 3, 'd': 14}, 58 'y': {'a': 1, 'b': 22, 'c': 3, 'd': 14, 'e': 25} 59 }, dict(d.items())) 60 61 19 62 def suite(): 20 63 suite = unittest.TestSuite() 21 64 suite.addTest(doctest.DocTestSuite(localedata)) 65 suite.addTest(unittest.makeSuite(MergeResolveTestCase)) 22 66 return suite 23 67 24 68 if __name__ == '__main__': -
babel/tests/dates.py
29 29 fmt = dates.DateTimeFormat(d, locale='cs_CZ') 30 30 self.assertEqual('1.', fmt['LLL']) 31 31 32 def test_abbreviated_month_alias(self): 33 d = date(2006, 3, 8) 34 fmt = dates.DateTimeFormat(d, locale='de_DE') 35 self.assertEqual(u'Mär', fmt['LLL']) 36 32 37 def test_week_of_year_first(self): 33 38 d = date(2006, 1, 8) 34 39 fmt = dates.DateTimeFormat(d, locale='de_DE') … … 187 192 tz = timezone('Europe/Paris') 188 193 t = time(15, 30, tzinfo=tz) 189 194 fmt = dates.DateTimeFormat(t, locale='fr_FR') 190 self.assertEqual(u' Heure de l’Europe centrale', fmt['vvvv'])195 self.assertEqual(u'heure d’Europe centrale', fmt['vvvv']) 191 196 192 197 def test_hour_formatting(self): 193 198 l = 'en_US' -
babel/numbers.py
165 165 >>> format_currency(1099.98, 'USD', locale='en_US') 166 166 u'$1,099.98' 167 167 >>> format_currency(1099.98, 'USD', locale='es_CO') 168 u'US$ 1.099,98'168 u'US$\\xa01.099,98' 169 169 >>> format_currency(1099.98, 'EUR', locale='de_DE') 170 u'1.099,98 \\u20ac'170 u'1.099,98\\xa0\\u20ac' 171 171 172 172 The pattern can also be specified explicitly: 173 173 -
babel/dates.py
189 189 string is used for GMT: 190 190 191 191 >>> get_timezone_gmt(dt, 'long', locale='fr_FR') 192 u' HMG-08:00'192 u'UTC-08:00' 193 193 194 194 :param datetime: the ``datetime`` object; if `None`, the current date and 195 195 time in UTC is used -
scripts/import_cldr.py
16 16 from optparse import OptionParser 17 17 import os 18 18 import pickle 19 import re 19 20 import sys 20 21 try: 21 22 from xml.etree.ElementTree import parse … … 26 27 sys.path.insert(0, os.path.join(os.path.dirname(sys.argv[0]), '..')) 27 28 28 29 from babel import dates, numbers 30 from babel.localedata import Alias 29 31 30 32 weekdays = {'mon': 0, 'tue': 1, 'wed': 2, 'thu': 3, 'fri': 4, 'sat': 5, 31 33 'sun': 6} … … 36 38 def any(iterable): 37 39 return filter(None, list(iterable)) 38 40 41 39 42 def _text(elem): 40 43 buf = [elem.text or ''] 41 44 for child in elem: … … 43 46 buf.append(elem.tail or '') 44 47 return u''.join(filter(None, buf)).strip() 45 48 49 50 NAME_RE = re.compile(r"^\w+$") 51 TYPE_ATTR_RE = re.compile(r"^\w+\[@type='(.*?)'\]$") 52 53 NAME_MAP = { 54 'dateFormats': 'date_formats', 55 'dateTimeFormats': 'datetime_formats', 56 'eraAbbr': 'abbreviated', 57 'eraNames': 'wide', 58 'eraNarrow': 'narrow', 59 'timeFormats': 'time_formats' 60 } 61 62 def _translate_alias(ctxt, path): 63 parts = path.split('/') 64 keys = ctxt[:] 65 for part in parts: 66 if part == '..': 67 keys.pop() 68 else: 69 match = TYPE_ATTR_RE.match(part) 70 if match: 71 keys.append(match.group(1)) 72 else: 73 assert NAME_RE.match(part) 74 keys.append(NAME_MAP.get(part, part)) 75 return keys 76 77 46 78 def main(): 47 79 parser = OptionParser(usage='%prog path/to/cldr') 48 80 options, args = parser.parse_args() … … 109 141 stem, ext = os.path.splitext(filename) 110 142 if ext != '.xml': 111 143 continue 144 #if stem != 'root': 145 # break 112 146 113 147 tree = parse(os.path.join(srcdir, 'main', filename)) 114 148 data = {} … … 227 261 228 262 months = data.setdefault('months', {}) 229 263 for ctxt in calendar.findall('months/monthContext'): 230 ctxts = months.setdefault(ctxt.attrib['type'], {}) 264 ctxt_type = ctxt.attrib['type'] 265 ctxts = months.setdefault(ctxt_type, {}) 231 266 for width in ctxt.findall('monthWidth'): 232 widths = ctxts.setdefault(width.attrib['type'], {}) 233 for elem in width.findall('month'): 234 if 'draft' in elem.attrib and int(elem.attrib['type']) in widths: 235 continue 236 widths[int(elem.attrib.get('type'))] = unicode(elem.text) 267 width_type = width.attrib['type'] 268 widths = ctxts.setdefault(width_type, {}) 269 for elem in width.getiterator(): 270 if elem.tag == 'month': 271 if 'draft' in elem.attrib and int(elem.attrib['type']) in widths: 272 continue 273 widths[int(elem.attrib.get('type'))] = unicode(elem.text) 274 elif elem.tag == 'alias': 275 assert elem.attrib['source'] == 'locale' 276 ctxts[width_type] = Alias( 277 _translate_alias(['months', ctxt_type, width_type], 278 elem.attrib['path']) 279 ) 237 280 238 281 days = data.setdefault('days', {}) 239 282 for ctxt in calendar.findall('days/dayContext'): 240 ctxts = days.setdefault(ctxt.attrib['type'], {}) 283 ctxt_type = ctxt.attrib['type'] 284 ctxts = days.setdefault(ctxt_type, {}) 241 285 for width in ctxt.findall('dayWidth'): 242 widths = ctxts.setdefault(width.attrib['type'], {}) 243 for elem in width.findall('day'): 244 dtype = weekdays[elem.attrib['type']] 245 if 'draft' in elem.attrib and dtype in widths: 246 continue 247 widths[dtype] = unicode(elem.text) 286 width_type = width.attrib['type'] 287 widths = ctxts.setdefault(width_type, {}) 288 for elem in width.getiterator(): 289 if elem.tag == 'day': 290 dtype = weekdays[elem.attrib['type']] 291 if 'draft' in elem.attrib and dtype in widths: 292 continue 293 widths[dtype] = unicode(elem.text) 294 elif elem.tag == 'alias': 295 assert elem.attrib['source'] == 'locale' 296 ctxts[width_type] = Alias( 297 _translate_alias(['days', ctxt_type, width_type], 298 elem.attrib['path']) 299 ) 248 300 249 301 quarters = data.setdefault('quarters', {}) 250 302 for ctxt in calendar.findall('quarters/quarterContext'): 303 ctxt_type = ctxt.attrib['type'] 251 304 ctxts = quarters.setdefault(ctxt.attrib['type'], {}) 252 305 for width in ctxt.findall('quarterWidth'): 253 widths = ctxts.setdefault(width.attrib['type'], {}) 254 for elem in width.findall('quarter'): 306 width_type = width.attrib['type'] 307 widths = ctxts.setdefault(width_type, {}) 308 for elem in width.getiterator(): 309 if elem.tag == 'quarter': 310 if 'draft' in elem.attrib and int(elem.attrib['type']) in widths: 311 continue 312 widths[int(elem.attrib.get('type'))] = unicode(elem.text) 313 elif elem.tag == 'alias': 314 assert elem.attrib['source'] == 'locale' 315 ctxts[width_type] = Alias( 316 _translate_alias(['quarters', ctxt_type, width_type], 317 elem.attrib['path']) 318 ) 319 320 eras = data.setdefault('eras', {}) 321 for width in calendar.findall('eras/*'): 322 width_type = NAME_MAP[width.tag] 323 widths = eras.setdefault(width_type, {}) 324 for elem in width.getiterator(): 325 if elem.tag == 'era': 255 326 if 'draft' in elem.attrib and int(elem.attrib['type']) in widths: 256 327 continue 257 328 widths[int(elem.attrib.get('type'))] = unicode(elem.text) 329 elif elem.tag == 'alias': 330 assert elem.attrib['source'] == 'locale' 331 eras[width_type] = Alias( 332 _translate_alias(['eras', width_type], 333 elem.attrib['path']) 334 ) 258 335 259 eras = data.setdefault('eras', {})260 for width in calendar.findall('eras/*'):261 ewidth = {262 'eraAbbr': 'abbreviated',263 'eraNames': 'wide',264 'eraNarrow': 'narrow',265 }[width.tag]266 widths = eras.setdefault(ewidth, {})267 for elem in width.findall('era'):268 if 'draft' in elem.attrib and int(elem.attrib['type']) in widths:269 continue270 widths[int(elem.attrib.get('type'))] = unicode(elem.text)271 272 336 # AM/PM 273 337 periods = data.setdefault('periods', {}) 274 338 for elem in calendar.findall('am'): 275 if 'draft' in elem.attriband elem.tag in periods:339 if ('draft' in elem.attrib or 'alt' in elem.attrib) and elem.tag in periods: 276 340 continue 277 341 periods[elem.tag] = unicode(elem.text) 278 342 for elem in calendar.findall('pm'): 279 if 'draft' in elem.attriband elem.tag in periods:343 if ('draft' in elem.attrib or 'alt' in elem.attrib) and elem.tag in periods: 280 344 continue 281 345 periods[elem.tag] = unicode(elem.text) 282 346 283 347 date_formats = data.setdefault('date_formats', {}) 284 for elem in calendar.findall('dateFormats/dateFormatLength'): 285 if 'draft' in elem.attrib and elem.attrib.get('type') in date_formats: 286 continue 287 try: 288 date_formats[elem.attrib.get('type')] = \ 289 dates.parse_pattern(unicode(elem.findtext('dateFormat/pattern'))) 290 except ValueError, e: 291 print>>sys.stderr, 'ERROR: %s' % e 348 for format in calendar.findall('dateFormats'): 349 for elem in format.getiterator(): 350 if elem.tag == 'dateFormatLength': 351 if 'draft' in elem.attrib and \ 352 elem.attrib.get('type') in date_formats: 353 continue 354 try: 355 date_formats[elem.attrib.get('type')] = \ 356 dates.parse_pattern(unicode(elem.findtext('dateFormat/pattern'))) 357 except ValueError, e: 358 print>>sys.stderr, 'ERROR: %s' % e 359 elif elem.tag == 'alias': 360 date_formats = Alias(_translate_alias( 361 ['date_formats'], elem.attrib['path']) 362 ) 292 363 293 364 time_formats = data.setdefault('time_formats', {}) 294 for elem in calendar.findall('timeFormats/timeFormatLength'): 295 if 'draft' in elem.attrib and elem.attrib.get('type') in time_formats: 296 continue 297 try: 298 time_formats[elem.attrib.get('type')] = \ 299 dates.parse_pattern(unicode(elem.findtext('timeFormat/pattern'))) 300 except ValueError, e: 301 print>>sys.stderr, 'ERROR: %s' % e 365 for format in calendar.findall('timeFormats'): 366 for elem in format.getiterator(): 367 if elem.tag == 'timeFormatLength': 368 if 'draft' in elem.attrib and \ 369 elem.attrib.get('type') in time_formats: 370 continue 371 try: 372 time_formats[elem.attrib.get('type')] = \ 373 dates.parse_pattern(unicode(elem.findtext('timeFormat/pattern'))) 374 except ValueError, e: 375 print>>sys.stderr, 'ERROR: %s' % e 376 elif elem.tag == 'alias': 377 time_formats = Alias(_translate_alias( 378 ['time_formats'], elem.attrib['path']) 379 ) 302 380 303 381 datetime_formats = data.setdefault('datetime_formats', {}) 304 for elem in calendar.findall('dateTimeFormats/dateTimeFormatLength'): 305 if 'draft' in elem.attrib and elem.attrib.get('type') in datetime_formats: 306 continue 307 try: 308 datetime_formats[elem.attrib.get('type')] = \ 309 unicode(elem.findtext('dateTimeFormat/pattern')) 310 except ValueError, e: 311 print>>sys.stderr, 'ERROR: %s' % e 382 for format in calendar.findall('dateTimeFormats'): 383 for elem in format.getiterator(): 384 if elem.tag == 'dateTimeFormatLength': 385 if 'draft' in elem.attrib and \ 386 elem.attrib.get('type') in datetime_formats: 387 continue 388 try: 389 datetime_formats[elem.attrib.get('type')] = \ 390 unicode(elem.findtext('dateTimeFormat/pattern')) 391 except ValueError, e: 392 print>>sys.stderr, 'ERROR: %s' % e 393 elif elem.tag == 'alias': 394 datetime_formats = Alias(_translate_alias( 395 ['datetime_formats'], elem.attrib['path']) 396 ) 312 397 313 398 # <numbers> 314 399 … … 360 445 finally: 361 446 outfile.close() 362 447 448 363 449 if __name__ == '__main__': 364 450 main()
