1############################################################################## 2# 3# Copyright (c) 2001, 2002 Zope Foundation and Contributors. 4# All Rights Reserved. 5# 6# This software is subject to the provisions of the Zope Public License, 7# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. 8# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED 9# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS 11# FOR A PARTICULAR PURPOSE. 12# 13############################################################################## 14"""Interfaces related to Locales 15""" 16import re 17from zope.interface import Interface, Attribute 18from zope.schema import \ 19 Field, Text, TextLine, Int, Bool, Tuple, List, Dict, Date 20from zope.schema import Container, Choice 21 22class ILocaleProvider(Interface): 23 """This interface is our connection to the Zope 3 service. From it 24 we can request various Locale objects that can perform all sorts of 25 fancy operations. 26 27 This service will be singelton global service, since it doe not make much 28 sense to have many locale facilities, especially since this one will be so 29 complete, since we will the ICU XML Files as data. """ 30 31 def loadLocale(language=None, country=None, variant=None): 32 """Load the locale with the specs that are given by the arguments of 33 the method. Note that the LocaleProvider must know where to get the 34 locales from.""" 35 36 def getLocale(language=None, country=None, variant=None): 37 """Get the Locale object for a particular language, country and 38 variant.""" 39 40 41class ILocaleIdentity(Interface): 42 """Identity information class for ILocale objects. 43 44 Three pieces of information are required to identify a locale: 45 46 o language -- Language in which all of the locale text information are 47 returned. 48 49 o script -- Script in which all of the locale text information are 50 returned. 51 52 o territory -- Territory for which the locale's information are 53 appropriate. None means all territories in which language is spoken. 54 55 o variant -- Sometimes there are regional or historical differences even 56 in a certain country. For these cases we use the variant field. A good 57 example is the time before the Euro in Germany for example. Therefore 58 a valid variant would be 'PREEURO'. 59 60 Note that all of these attributes are read-only once they are set (usually 61 done in the constructor)! 62 63 This object is also used to uniquely identify a locale. 64 """ 65 66 language = TextLine( 67 title = u"Language Type", 68 description = u"The language for which a locale is applicable.", 69 constraint = re.compile(r'[a-z]{2}').match, 70 required = True, 71 readonly = True) 72 73 script = TextLine( 74 title = u"Script Type", 75 description = u"""The script for which the language/locale is 76 applicable.""", 77 constraint = re.compile(r'[a-z]*').match) 78 79 territory = TextLine( 80 title = u"Territory Type", 81 description = u"The territory for which a locale is applicable.", 82 constraint = re.compile(r'[A-Z]{2}').match, 83 required = True, 84 readonly = True) 85 86 variant = TextLine( 87 title = u"Variant Type", 88 description = u"The variant for which a locale is applicable.", 89 constraint = re.compile(r'[a-zA-Z]*').match, 90 required = True, 91 readonly = True) 92 93 version = Field( 94 title = u"Locale Version", 95 description = u"The value of this field is an ILocaleVersion object.", 96 readonly = True) 97 98 def __repr__(self): 99 """Defines the representation of the id, which should be a compact 100 string that references the language, country and variant.""" 101 102 103class ILocaleVersion(Interface): 104 """Represents the version of a locale. 105 106 The locale version is part of the ILocaleIdentity object. 107 """ 108 109 number = TextLine( 110 title = u"Version Number", 111 description = u"The version number of the locale.", 112 constraint = re.compile(r'^([0-9].)*[0-9]$').match, 113 required = True, 114 readonly = True) 115 116 generationDate = Date( 117 title = u"Generation Date", 118 description = u"Specifies the creation date of the locale.", 119 constraint = lambda date: date < datetime.now(), 120 readonly = True) 121 122 notes = Text( 123 title = u"Notes", 124 description = u"Some release notes for the version of this locale.", 125 readonly = True) 126 127 128class ILocaleDisplayNames(Interface): 129 """Localized Names of common text strings. 130 131 This object contains localized strings for many terms, including 132 language, script and territory names. But also keys and types used 133 throughout the locale object are localized here. 134 """ 135 136 languages = Dict( 137 title = u"Language type to translated name", 138 key_type = TextLine(title=u"Language Type"), 139 value_type = TextLine(title=u"Language Name")) 140 141 scripts = Dict( 142 title = u"Script type to script name", 143 key_type = TextLine(title=u"Script Type"), 144 value_type = TextLine(title=u"Script Name")) 145 146 territories = Dict( 147 title = u"Territory type to translated territory name", 148 key_type = TextLine(title=u"Territory Type"), 149 value_type = TextLine(title=u"Territory Name")) 150 151 variants = Dict( 152 title = u"Variant type to name", 153 key_type = TextLine(title=u"Variant Type"), 154 value_type = TextLine(title=u"Variant Name")) 155 156 keys = Dict( 157 title = u"Key type to name", 158 key_type = TextLine(title=u"Key Type"), 159 value_type = TextLine(title=u"Key Name")) 160 161 types = Dict( 162 title = u"Type type and key to localized name", 163 key_type = Tuple(title=u"Type Type and Key"), 164 value_type = TextLine(title=u"Type Name")) 165 166 167class ILocaleTimeZone(Interface): 168 """Represents and defines various timezone information. It mainly manages 169 all the various names for a timezone and the cities contained in it. 170 171 Important: ILocaleTimeZone objects are not intended to provide 172 implementations for the standard datetime module timezone support. They 173 are merily used for Locale support. 174 """ 175 176 type = TextLine( 177 title = u"Time Zone Type", 178 description = u"Standard name of the timezone for unique referencing.", 179 required = True, 180 readonly = True) 181 182 cities = List( 183 title = u"Cities", 184 description = u"Cities in Timezone", 185 value_type = TextLine(title=u"City Name"), 186 required = True, 187 readonly = True) 188 189 190 names = Dict( 191 title = u"Time Zone Names", 192 description = u"Various names of the timezone.", 193 key_type = Choice( 194 title = u"Time Zone Name Type", 195 values = (u'generic', u'standard', u'daylight')), 196 value_type = Tuple(title=u"Time Zone Name and Abbreviation", 197 min_length=2, max_length=2), 198 required = True, 199 readonly = True) 200 201 202class ILocaleFormat(Interface): 203 """Specifies a format for a particular type of data.""" 204 205 type = TextLine( 206 title=u"Format Type", 207 description=u"The name of the format", 208 required = False, 209 readonly = True) 210 211 displayName = TextLine( 212 title = u"Display Name", 213 description = u"Name of the calendar, for example 'gregorian'.", 214 required = False, 215 readonly = True) 216 217 pattern = TextLine( 218 title = u"Format Pattern", 219 description = u"The pattern that is used to format the object.", 220 required = True, 221 readonly = True) 222 223 224class ILocaleFormatLength(Interface): 225 """The format length describes a class of formats.""" 226 227 type = Choice( 228 title = u"Format Length Type", 229 description = u"Name of the format length", 230 values = (u'full', u'long', u'medium', u'short') 231 ) 232 233 default = TextLine( 234 title=u"Default Format", 235 description=u"The name of the defaulkt format.") 236 237 formats = Dict( 238 title = u"Formats", 239 description = u"Maps format types to format objects", 240 key_type = TextLine(title = u"Format Type"), 241 value_type = Field( 242 title = u"Format Object", 243 description = u"Values are ILocaleFormat objects."), 244 required = True, 245 readonly = True) 246 247 248class ILocaleMonthContext(Interface): 249 """Specifices a usage context for month names""" 250 251 type = TextLine( 252 title=u'Month context type', 253 description=u"Name of the month context, format or stand-alone.") 254 255 defaultWidth = TextLine( 256 title=u'Default month name width', 257 default=u'wide') 258 259 months = Dict( 260 title=u'Month Names', 261 description=u'A mapping of month name widths to a mapping of' 262 u'corresponding month names.', 263 key_type=Choice( 264 title=u'Width type', 265 values=(u'wide', u'abbreviated', u'narrow')), 266 value_type=Dict( 267 title=u'Month name', 268 key_type=Int(title=u'Type', min=1, max=12), 269 value_type=TextLine(title=u'Month Name')) 270 ) 271 272 273class ILocaleDayContext(Interface): 274 """Specifices a usage context for days names""" 275 276 type = TextLine( 277 title=u'Day context type', 278 description=u"Name of the day context, format or stand-alone.") 279 280 defaultWidth = TextLine( 281 title=u'Default day name width', 282 default=u'wide') 283 284 days = Dict( 285 title=u'Day Names', 286 description=u'A mapping of day name widths to a mapping of' 287 u'corresponding day names.', 288 key_type=Choice( 289 title=u'Width type', 290 values=(u'wide', u'abbreviated', u'narrow')), 291 value_type=Dict( 292 title=u'Day name', 293 key_type=Choice( 294 title=u"Type", 295 values=(u'sun', u'mon', u'tue', u'wed', 296 u'thu', u'fri', u'sat')), 297 value_type=TextLine(title=u'Day Name')) 298 ) 299 300 301class ILocaleCalendar(Interface): 302 """There is a massive amount of information contained in the calendar, 303 which made it attractive to be added.""" 304 305 type = TextLine( 306 title=u"Calendar Type", 307 description=u"Name of the calendar, for example 'gregorian'.") 308 309 defaultMonthContext = TextLine( 310 title=u'Default month context', 311 default=u'format') 312 313 monthContexts = Dict( 314 title=u'Month Contexts', 315 description=u'A mapping of month context types to ' 316 u'ILocaleMonthContext objects', 317 key_type=Choice(title=u'Type', 318 values=(u'format', u'stand-alone')), 319 value_type=Field(title=u'ILocaleMonthContext object')) 320 321 # BBB: leftover from CLDR 1.0 322 months = Dict( 323 title = u"Month Names", 324 description = u"A mapping of all month names and abbreviations", 325 key_type = Int(title=u"Type", min=1, max=12), 326 value_type = Tuple(title=u"Month Name and Abbreviation", 327 min_length=2, max_length=2)) 328 329 defaultDayContext = TextLine( 330 title=u'Default day context', 331 default=u'format') 332 333 dayContexts = Dict( 334 title=u'Day Contexts', 335 description=u'A mapping of day context types to ' 336 u'ILocaleDayContext objects', 337 key_type=Choice(title=u'Type', 338 values=(u'format', u'stand-alone')), 339 value_type=Field(title=u'ILocaleDayContext object')) 340 341 # BBB: leftover from CLDR 1.0 342 days = Dict( 343 title=u"Weekdays Names", 344 description = u"A mapping of all month names and abbreviations", 345 key_type = Choice(title=u"Type", 346 values=(u'sun', u'mon', u'tue', u'wed', 347 u'thu', u'fri', u'sat')), 348 value_type = Tuple(title=u"Weekdays Name and Abbreviation", 349 min_length=2, max_length=2)) 350 351 week = Dict( 352 title=u"Week Information", 353 description = u"Contains various week information", 354 key_type = Choice( 355 title=u"Type", 356 description=u""" 357 Varies Week information: 358 359 - 'minDays' is just an integer between 1 and 7. 360 361 - 'firstDay' specifies the first day of the week by integer. 362 363 - The 'weekendStart' and 'weekendEnd' are tuples of the form 364 (weekDayNumber, datetime.time) 365 """, 366 values=(u'minDays', u'firstDay', 367 u'weekendStart', u'weekendEnd'))) 368 369 am = TextLine(title=u"AM String") 370 371 pm = TextLine(title=u"PM String") 372 373 eras = Dict( 374 title = u"Era Names", 375 key_type = Int(title=u"Type", min=0), 376 value_type = Tuple(title=u"Era Name and Abbreviation", 377 min_length=2, max_length=2)) 378 379 defaultDateFormat = TextLine(title=u"Default Date Format Type") 380 381 dateFormats = Dict( 382 title=u"Date Formats", 383 description = u"Contains various Date Formats.", 384 key_type = Choice( 385 title=u"Type", 386 description = u"Name of the format length", 387 values = (u'full', u'long', u'medium', u'short')), 388 value_type = Field(title=u"ILocaleFormatLength object")) 389 390 defaultTimeFormat = TextLine(title=u"Default Time Format Type") 391 392 timeFormats = Dict( 393 title=u"Time Formats", 394 description = u"Contains various Time Formats.", 395 key_type = Choice( 396 title=u"Type", 397 description = u"Name of the format length", 398 values = (u'full', u'long', u'medium', u'short')), 399 value_type = Field(title=u"ILocaleFormatLength object")) 400 401 defaultDateTimeFormat = TextLine(title=u"Default Date-Time Format Type") 402 403 dateTimeFormats = Dict( 404 title=u"Date-Time Formats", 405 description = u"Contains various Date-Time Formats.", 406 key_type = Choice( 407 title=u"Type", 408 description = u"Name of the format length", 409 values = (u'full', u'long', u'medium', u'short')), 410 value_type = Field(title=u"ILocaleFormatLength object")) 411 412 def getMonthNames(): 413 """Return a list of month names.""" 414 415 def getMonthTypeFromName(name): 416 """Return the type of the month with the right name.""" 417 418 def getMonthAbbreviations(): 419 """Return a list of month abbreviations.""" 420 421 def getMonthTypeFromAbbreviation(abbr): 422 """Return the type of the month with the right abbreviation.""" 423 424 def getDayNames(): 425 """Return a list of weekday names.""" 426 427 def getDayTypeFromName(name): 428 """Return the id of the weekday with the right name.""" 429 430 def getDayAbbr(): 431 """Return a list of weekday abbreviations.""" 432 433 def getDayTypeFromAbbr(abbr): 434 """Return the id of the weekday with the right abbr.""" 435 436 def isWeekend(datetime): 437 """Determines whether a the argument lies in a weekend.""" 438 439 def getFirstDayName(): 440 """Return the the type of the first day in the week.""" 441 442 443class ILocaleDates(Interface): 444 """This object contains various data about dates, times and time zones.""" 445 446 localizedPatternChars = TextLine( 447 title = u"Localized Pattern Characters", 448 description = u"Localized pattern characters used in dates and times") 449 450 calendars = Dict( 451 title = u"Calendar type to ILocaleCalendar", 452 key_type = Choice( 453 title=u"Calendar Type", 454 values=(u'gregorian', 455 u'arabic', 456 u'chinese', 457 u'civil-arabic', 458 u'hebrew', 459 u'japanese', 460 u'thai-buddhist')), 461 value_type=Field(title=u"Calendar", 462 description=u"This is a ILocaleCalendar object.")) 463 464 timezones = Dict( 465 title=u"Time zone type to ILocaleTimezone", 466 key_type=TextLine(title=u"Time Zone type"), 467 value_type=Field(title=u"Time Zone", 468 description=u"This is a ILocaleTimeZone object.")) 469 470 def getFormatter(category, length=None, name=None, calendar=u'gregorian'): 471 """Get a date/time formatter. 472 473 `category` must be one of 'date', 'dateTime', 'time'. 474 475 The 'length' specifies the output length of the value. The allowed 476 values are: 'short', 'medium', 'long' and 'full'. If no length was 477 specified, the default length is chosen. 478 """ 479 480 481class ILocaleCurrency(Interface): 482 """Defines a particular currency.""" 483 484 type = TextLine(title=u'Type') 485 486 symbol = TextLine(title=u'Symbol') 487 488 displayName = TextLine(title=u'Official Name') 489 490 symbolChoice = Bool(title=u'Symbol Choice') 491 492class ILocaleNumbers(Interface): 493 """This object contains various data about numbers and currencies.""" 494 495 symbols = Dict( 496 title = u"Number Symbols", 497 key_type = Choice( 498 title = u"Format Name", 499 values = (u'decimal', u'group', u'list', u'percentSign', 500 u'nativeZeroDigit', u'patternDigit', u'plusSign', 501 u'minusSign', u'exponential', u'perMille', 502 u'infinity', u'nan')), 503 value_type=TextLine(title=u"Symbol")) 504 505 defaultDecimalFormat = TextLine(title=u"Default Decimal Format Type") 506 507 decimalFormats = Dict( 508 title=u"Decimal Formats", 509 description = u"Contains various Decimal Formats.", 510 key_type = Choice( 511 title=u"Type", 512 description = u"Name of the format length", 513 values = (u'full', u'long', u'medium', u'short')), 514 value_type = Field(title=u"ILocaleFormatLength object")) 515 516 defaultScientificFormat = TextLine(title=u"Default Scientific Format Type") 517 518 scientificFormats = Dict( 519 title=u"Scientific Formats", 520 description = u"Contains various Scientific Formats.", 521 key_type = Choice( 522 title=u"Type", 523 description = u"Name of the format length", 524 values = (u'full', u'long', u'medium', u'short')), 525 value_type = Field(title=u"ILocaleFormatLength object")) 526 527 defaultPercentFormat = TextLine(title=u"Default Percent Format Type") 528 529 percentFormats = Dict( 530 title=u"Percent Formats", 531 description = u"Contains various Percent Formats.", 532 key_type = Choice( 533 title=u"Type", 534 description = u"Name of the format length", 535 values = (u'full', u'long', u'medium', u'short')), 536 value_type = Field(title=u"ILocaleFormatLength object")) 537 538 defaultCurrencyFormat = TextLine(title=u"Default Currency Format Type") 539 540 currencyFormats = Dict( 541 title=u"Currency Formats", 542 description = u"Contains various Currency Formats.", 543 key_type = Choice( 544 title=u"Type", 545 description = u"Name of the format length", 546 values = (u'full', u'long', u'medium', u'short')), 547 value_type = Field(title=u"ILocaleFormatLength object")) 548 549 currencies = Dict( 550 title=u"Currencies", 551 description = u"Contains various Currency data.", 552 key_type = TextLine( 553 title=u"Type", 554 description = u"Name of the format length"), 555 value_type = Field(title=u"ILocaleCurrency object")) 556 557 558 def getFormatter(category, length=None, name=u''): 559 """Get the NumberFormat based on the category, length and name of the 560 format. 561 562 The 'category' specifies the type of number format you would like to 563 have. The available options are: 'decimal', 'percent', 'scientific', 564 'currency'. 565 566 The 'length' specifies the output length of the number. The allowed 567 values are: 'short', 'medium', 'long' and 'full'. If no length was 568 specified, the default length is chosen. 569 570 Every length can have actually several formats. In this case these 571 formats are named and you can specify the name here. If no name was 572 specified, the first unnamed format is chosen. 573 """ 574 575 def getDefaultCurrency(): 576 """Get the default currency.""" 577 578_orientations = [u"left-to-right", u"right-to-left", 579 u"top-to-bottom", u"bottom-to-top"] 580class ILocaleOrientation(Interface): 581 """Information about the orientation of text.""" 582 583 characters = Choice( 584 title = u"Orientation of characters", 585 values = _orientations, 586 default = u"left-to-right" 587 ) 588 589 lines = Choice( 590 title = u"Orientation of characters", 591 values = _orientations, 592 default = u"top-to-bottom" 593 ) 594 595class ILocale(Interface): 596 """This class contains all important information about the locale. 597 598 Usually a Locale is identified using a specific language, country and 599 variant. However, the country and variant are optional, so that a lookup 600 hierarchy develops. It is easy to recognize that a locale that is missing 601 the variant is more general applicable than the one with the variant. 602 Therefore, if a specific Locale does not contain the required information, 603 it should look one level higher. There will be a root locale that 604 specifies none of the above identifiers. 605 """ 606 607 id = Field( 608 title = u"Locale identity", 609 description = u"ILocaleIdentity object identifying the locale.", 610 required = True, 611 readonly = True) 612 613 displayNames = Field( 614 title = u"Display Names", 615 description = u"""ILocaleDisplayNames object that contains localized 616 names.""") 617 618 dates = Field( 619 title = u"Dates", 620 description = u"ILocaleDates object that contains date/time data.") 621 622 numbers = Field( 623 title = u"Numbers", 624 description = u"ILocaleNumbers object that contains number data.") 625 626 orientation = Field( 627 title = u"Orientation", 628 description = u"ILocaleOrientation with text orientation info.") 629 630 delimiters = Dict( 631 title=u"Delimiters", 632 description = u"Contains various Currency data.", 633 key_type = Choice( 634 title=u"Delimiter Type", 635 description = u"Delimiter name.", 636 values=(u'quotationStart', u'quotationEnd', 637 u'alternateQuotationStart', 638 u'alternateQuotationEnd')), 639 value_type = Field(title=u"Delimiter symbol")) 640 641 def getLocaleID(): 642 """Return a locale id as specified in the LDML specification""" 643 644 645class ILocaleInheritance(Interface): 646 """Locale inheritance support. 647 648 Locale-related objects implementing this interface are able to ask for its 649 inherited self. For example, 'en_US.dates.monthNames' can call on itself 650 'getInheritedSelf()' and get the value for 'en.dates.monthNames'. 651 """ 652 653 __parent__ = Attribute("The parent in the location hierarchy") 654 655 __name__ = TextLine( 656 title = u"The name within the parent", 657 description=u"""The parent can be traversed with this name to get 658 the object.""") 659 660 def getInheritedSelf(): 661 """Return itself but in the next higher up Locale.""" 662 663 664class IAttributeInheritance(ILocaleInheritance): 665 """Provides inheritance properties for attributes""" 666 667 def __setattr__(name, value): 668 """Set a new attribute on the object. 669 670 When a value is set on any inheritance-aware object and the value 671 also implements ILocaleInheritance, then we need to set the 672 '__parent__' and '__name__' attribute on the value. 673 """ 674 675 def __getattribute__(name): 676 """Return the value of the attribute with the specified name. 677 678 If an attribute is not found or is None, the next higher up Locale 679 object is consulted.""" 680 681 682class IDictionaryInheritance(ILocaleInheritance): 683 """Provides inheritance properties for dictionary keys""" 684 685 def __setitem__(key, value): 686 """Set a new item on the object. 687 688 Here we assume that the value does not require any inheritance, so 689 that we do not set '__parent__' or '__name__' on the value. 690 """ 691 692 def __getitem__(key): 693 """Return the value of the item with the specified name. 694 695 If an key is not found or is None, the next higher up Locale 696 object is consulted. 697 """ 698 699class ICollator(Interface): 700 """Provide support for collating text strings 701 702 This interface will typically be provided by adapting a locale. 703 """ 704 705 def key(text): 706 """Return a collation key for the given text. 707 """ 708 709 def cmp(text1, text2): 710 """Compare two text strings. 711 712 The return value is negative if text1 < text2, 0 is they are 713 equal, and positive if text1 > text2. 714 """ 715 716 717