Ticket #68: cldr_aliases.diff
| File cldr_aliases.diff, 23.0 KB (added by cmlenz, 4 years ago) |
|---|
-
babel/core.py
285 285 #{ General Locale Display Names 286 286 287 287 def languages(self): 288 return self._data['languages']288 return localedata.AliasResolvingDict(self._data)['languages'] 289 289 languages = property(languages, doc="""\ 290 290 Mapping of language codes to translated language names. 291 291 … … 297 297 """) 298 298 299 299 def scripts(self): 300 return self._data['scripts']300 return localedata.AliasResolvingDict(self._data)['scripts'] 301 301 scripts = property(scripts, doc="""\ 302 302 Mapping of script codes to translated script names. 303 303 … … 309 309 """) 310 310 311 311 def territories(self): 312 return self._data['territories']312 return localedata.AliasResolvingDict(self._data)['territories'] 313 313 territories = property(territories, doc="""\ 314 314 Mapping of script codes to translated script names. 315 315 … … 321 321 """) 322 322 323 323 def variants(self): 324 return self._data['variants']324 return localedata.AliasResolvingDict(self._data)['variants'] 325 325 variants = property(variants, doc="""\ 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 """) … … 334 334 #{ Number Formatting 335 335 336 336 def currencies(self): 337 return self._data['currency_names']337 return localedata.AliasResolvingDict(self._data)['currency_names'] 338 338 currencies = property(currencies, doc="""\ 339 339 Mapping of currency codes to translated currency names. 340 340 … … 347 347 """) 348 348 349 349 def currency_symbols(self): 350 return self._data['currency_symbols']350 return localedata.AliasResolvingDict(self._data)['currency_symbols'] 351 351 currency_symbols = property(currency_symbols, doc="""\ 352 352 Mapping of currency codes to symbols. 353 353 … … 360 360 """) 361 361 362 362 def number_symbols(self): 363 return self._data['number_symbols']363 return localedata.AliasResolvingDict(self._data)['number_symbols'] 364 364 number_symbols = property(number_symbols, doc="""\ 365 365 Symbols used in number formatting. 366 366 … … 371 371 """) 372 372 373 373 def decimal_formats(self): 374 return self._data['decimal_formats']374 return localedata.AliasResolvingDict(self._data)['decimal_formats'] 375 375 decimal_formats = property(decimal_formats, doc="""\ 376 376 Locale patterns for decimal number formatting. 377 377 … … 382 382 """) 383 383 384 384 def currency_formats(self): 385 return self._data['currency_formats']385 return localedata.AliasResolvingDict(self._data)['currency_formats'] 386 386 currency_formats = property(currency_formats, doc=r"""\ 387 387 Locale patterns for currency number formatting. 388 388 … … 393 393 """) 394 394 395 395 def percent_formats(self): 396 return self._data['percent_formats']396 return localedata.AliasResolvingDict(self._data)['percent_formats'] 397 397 percent_formats = property(percent_formats, doc="""\ 398 398 Locale patterns for percent number formatting. 399 399 … … 404 404 """) 405 405 406 406 def scientific_formats(self): 407 return self._data['scientific_formats']407 return localedata.AliasResolvingDict(self._data)['scientific_formats'] 408 408 scientific_formats = property(scientific_formats, doc="""\ 409 409 Locale patterns for scientific number formatting. 410 410 … … 417 417 #{ Calendar Information and Date Formatting 418 418 419 419 def periods(self): 420 return self._data['periods']420 return localedata.AliasResolvingDict(self._data)['periods'] 421 421 periods = property(periods, doc="""\ 422 422 Locale display names for day periods (AM/PM). 423 423 … … 428 428 """) 429 429 430 430 def days(self): 431 return self._data['days']431 return localedata.AliasResolvingDict(self._data)['days'] 432 432 days = property(days, doc="""\ 433 433 Locale display names for weekdays. 434 434 … … 439 439 """) 440 440 441 441 def months(self): 442 return self._data['months']442 return localedata.AliasResolvingDict(self._data)['months'] 443 443 months = property(months, doc="""\ 444 444 Locale display names for months. 445 445 … … 450 450 """) 451 451 452 452 def quarters(self): 453 return self._data['quarters']453 return localedata.AliasResolvingDict(self._data)['quarters'] 454 454 quarters = property(quarters, doc="""\ 455 455 Locale display names for quarters. 456 456 … … 461 461 """) 462 462 463 463 def eras(self): 464 return self._data['eras']464 return localedata.AliasResolvingDict(self._data)['eras'] 465 465 eras = property(eras, doc="""\ 466 466 Locale display names for eras. 467 467 … … 474 474 """) 475 475 476 476 def time_zones(self): 477 return self._data['time_zones']477 return localedata.AliasResolvingDict(self._data)['time_zones'] 478 478 time_zones = property(time_zones, doc="""\ 479 479 Locale display names for time zones. 480 480 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 """) 488 488 489 489 def meta_zones(self): 490 return self._data['meta_zones']490 return localedata.AliasResolvingDict(self._data)['meta_zones'] 491 491 meta_zones = property(meta_zones, doc="""\ 492 492 Locale display names for meta time zones. 493 493 … … 502 502 """) 503 503 504 504 def zone_formats(self): 505 return self._data['zone_formats']505 return localedata.AliasResolvingDict(self._data)['zone_formats'] 506 506 zone_formats = property(zone_formats, doc=r"""\ 507 507 Patterns related to the formatting of time zones. 508 508 … … 516 516 """) 517 517 518 518 def first_week_day(self): 519 return self._data['week_data']['first_day']519 return localedata.AliasResolvingDict(self._data)['week_data']['first_day'] 520 520 first_week_day = property(first_week_day, doc="""\ 521 521 The first day of a week. 522 522 … … 529 529 """) 530 530 531 531 def weekend_start(self): 532 return self._data['week_data']['weekend_start']532 return localedata.AliasResolvingDict(self._data)['week_data']['weekend_start'] 533 533 weekend_start = property(weekend_start, doc="""\ 534 534 The day the weekend starts. 535 535 … … 540 540 """) 541 541 542 542 def weekend_end(self): 543 return self._data['week_data']['weekend_end']543 return localedata.AliasResolvingDict(self._data)['week_data']['weekend_end'] 544 544 weekend_end = property(weekend_end, doc="""\ 545 545 The day the weekend ends. 546 546 … … 551 551 """) 552 552 553 553 def min_week_days(self): 554 return self._data['week_data']['min_days']554 return localedata.AliasResolvingDict(self._data)['week_data']['min_days'] 555 555 min_week_days = property(min_week_days, doc="""\ 556 556 The minimum number of days in a week so that the week is counted as the 557 557 first week of a year or month. … … 563 563 """) 564 564 565 565 def date_formats(self): 566 return self._data['date_formats']566 return localedata.AliasResolvingDict(self._data)['date_formats'] 567 567 date_formats = property(date_formats, doc="""\ 568 568 Locale patterns for date formatting. 569 569 … … 576 576 """) 577 577 578 578 def time_formats(self): 579 return self._data['time_formats']579 return localedata.AliasResolvingDict(self._data)['time_formats'] 580 580 time_formats = property(time_formats, doc="""\ 581 581 Locale patterns for time formatting. 582 582 … … 589 589 """) 590 590 591 591 def datetime_formats(self): 592 return self._data['datetime_formats']592 return localedata.AliasResolvingDict(self._data)['datetime_formats'] 593 593 datetime_formats = property(datetime_formats, doc="""\ 594 594 Locale patterns for datetime formatting. 595 595 -
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 … … 61 65 the Common Locale Data Repository (CLDR). This data is stored as a 62 66 collection of pickle files inside the ``babel`` package. 63 67 64 >> >d = load('en_US')65 >> >d['languages']['sv']68 >> d = load('en_US') 69 >> d['languages']['sv'] 66 70 u'Swedish' 67 71 68 72 Note that the results are cached, and subsequent requests for the same 69 73 locale return the same dictionary: 70 74 71 >> >d1 = load('en_US')72 >> >d2 = load('en_US')73 >> >d1 is d275 >> d1 = load('en_US') 76 >> d2 = load('en_US') 77 >> d1 is d2 74 78 True 75 79 76 80 :param name: the locale identifier string (or "root") … … 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 AliasResolvingDict(DictMixin, object): 169 170 def __init__(self, data, base=None): 171 self.data = data 172 if base is None: 173 base = self 174 self.base = base 175 176 def __getitem__(self, key): 177 val = self.data[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 = AliasResolvingDict(val, base=self.base) 186 return val 187 188 def __setitem__(self, key, value): 189 self.data[key] = value 190 191 def copy(self): 192 return AliasResolvingDict(self.data.copy(), base=self.base) 193 194 def keys(self): 195 return self.data.keys() -
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_alias(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.AliasResolvingDict(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 }, d) 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 54 def _translate_alias(ctxt, path): 55 parts = path.split('/') 56 keys = ctxt[:] 57 for part in parts: 58 if part == '..': 59 keys.pop() 60 else: 61 match = TYPE_ATTR_RE.match(part) 62 if match: 63 keys.append(match.group(1)) 64 else: 65 assert NAME_RE.match(part) 66 keys.append(part) 67 return keys 68 69 46 70 def main(): 47 71 parser = OptionParser(usage='%prog path/to/cldr') 48 72 options, args = parser.parse_args() … … 109 133 stem, ext = os.path.splitext(filename) 110 134 if ext != '.xml': 111 135 continue 136 #if stem != 'root': 137 # break 112 138 113 139 tree = parse(os.path.join(srcdir, 'main', filename)) 114 140 data = {} … … 227 253 228 254 months = data.setdefault('months', {}) 229 255 for ctxt in calendar.findall('months/monthContext'): 230 ctxts = months.setdefault(ctxt.attrib['type'], {}) 256 ctxt_type = ctxt.attrib['type'] 257 ctxts = months.setdefault(ctxt_type, {}) 231 258 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) 259 width_type = width.attrib['type'] 260 widths = ctxts.setdefault(width_type, {}) 261 for elem in width.getiterator(): 262 if elem.tag == 'month': 263 if 'draft' in elem.attrib and int(elem.attrib['type']) in widths: 264 continue 265 widths[int(elem.attrib.get('type'))] = unicode(elem.text) 266 elif elem.tag == 'alias': 267 assert elem.attrib['source'] == 'locale' 268 ctxts[width_type] = Alias( 269 _translate_alias(['months', ctxt_type, width_type], 270 elem.attrib['path']) 271 ) 237 272 238 273 days = data.setdefault('days', {}) 239 274 for ctxt in calendar.findall('days/dayContext'): 240 ctxts = days.setdefault(ctxt.attrib['type'], {}) 275 ctxt_type = ctxt.attrib['type'] 276 ctxts = days.setdefault(ctxt_type, {}) 241 277 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) 278 width_type = width.attrib['type'] 279 widths = ctxts.setdefault(width_type, {}) 280 for elem in width.getiterator(): 281 if elem.tag == 'day': 282 dtype = weekdays[elem.attrib['type']] 283 if 'draft' in elem.attrib and dtype in widths: 284 continue 285 widths[dtype] = unicode(elem.text) 286 elif elem.tag == 'alias': 287 assert elem.attrib['source'] == 'locale' 288 ctxts[width_type] = Alias( 289 _translate_alias(['days', ctxt_type, width_type], 290 elem.attrib['path']) 291 ) 248 292 249 293 quarters = data.setdefault('quarters', {}) 250 294 for ctxt in calendar.findall('quarters/quarterContext'): 295 ctxt_type = ctxt.attrib['type'] 251 296 ctxts = quarters.setdefault(ctxt.attrib['type'], {}) 252 297 for width in ctxt.findall('quarterWidth'): 253 widths = ctxts.setdefault(width.attrib['type'], {}) 254 for elem in width.findall('quarter'): 255 if 'draft' in elem.attrib and int(elem.attrib['type']) in widths: 256 continue 257 widths[int(elem.attrib.get('type'))] = unicode(elem.text) 298 width_type = width.attrib['type'] 299 widths = ctxts.setdefault(width_type, {}) 300 for elem in width.getiterator(): 301 if elem.tag == 'quarter': 302 if 'draft' in elem.attrib and int(elem.attrib['type']) in widths: 303 continue 304 widths[int(elem.attrib.get('type'))] = unicode(elem.text) 305 elif elem.tag == 'alias': 306 assert elem.attrib['source'] == 'locale' 307 ctxts[width_type] = Alias( 308 _translate_alias(['quarters', ctxt_type, width_type], 309 elem.attrib['path']) 310 ) 258 311 259 312 eras = data.setdefault('eras', {}) 260 313 for width in calendar.findall('eras/*'): … … 272 325 # AM/PM 273 326 periods = data.setdefault('periods', {}) 274 327 for elem in calendar.findall('am'): 275 if 'draft' in elem.attriband elem.tag in periods:328 if ('draft' in elem.attrib or 'alt' in elem.attrib) and elem.tag in periods: 276 329 continue 277 330 periods[elem.tag] = unicode(elem.text) 278 331 for elem in calendar.findall('pm'): 279 if 'draft' in elem.attriband elem.tag in periods:332 if ('draft' in elem.attrib or 'alt' in elem.attrib) and elem.tag in periods: 280 333 continue 281 334 periods[elem.tag] = unicode(elem.text) 282 335 … … 360 413 finally: 361 414 outfile.close() 362 415 416 363 417 if __name__ == '__main__': 364 418 main()
