1 /* 2 ** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 3 ** Distributed under the terms of the OpenBeOS License. 4 */ 5 6 7 #include <AutoDeleter.h> 8 #include <CalendarView.h> 9 #include <Catalog.h> 10 #include <Locale.h> 11 #include <LocaleRoster.h> 12 13 #include <unicode/datefmt.h> 14 #include <unicode/dcfmtsym.h> 15 #include <unicode/decimfmt.h> 16 #include <unicode/dtfmtsym.h> 17 #include <unicode/smpdtfmt.h> 18 #include <ICUWrapper.h> 19 20 #include <vector> 21 22 23 #define ICU_VERSION icu_44 24 25 26 using BPrivate::ObjectDeleter; 27 using BPrivate::B_WEEK_START_MONDAY; 28 using BPrivate::B_WEEK_START_SUNDAY; 29 30 31 static DateFormat* CreateDateFormat(bool longFormat, const Locale& locale, 32 const BString& format); 33 static DateFormat* CreateTimeFormat(bool longFormat, const Locale& locale, 34 const BString& format); 35 36 37 BLocale::BLocale(const char* languageAndCountryCode) 38 : 39 fCountry(languageAndCountryCode), 40 fLanguage(languageAndCountryCode), 41 fICULocale(new ICU_VERSION::Locale(languageAndCountryCode)) 42 { 43 } 44 45 46 BLocale::BLocale(const BLocale& other) 47 : 48 fCountry(other.fCountry), 49 fLanguage(other.fLanguage), 50 fICULocale(new ICU_VERSION::Locale(*other.fICULocale)), 51 fLongDateFormat(other.fLongDateFormat), 52 fShortDateFormat(other.fShortDateFormat), 53 fLongTimeFormat(other.fLongTimeFormat), 54 fShortTimeFormat(other.fShortTimeFormat) 55 { 56 } 57 58 59 BLocale& 60 BLocale::operator=(const BLocale& other) 61 { 62 if (this == &other) 63 return *this; 64 65 *fICULocale = *other.fICULocale; 66 67 fLongDateFormat = other.fLongDateFormat; 68 fShortDateFormat = other.fShortDateFormat; 69 fLongTimeFormat = other.fLongTimeFormat; 70 fShortTimeFormat = other.fShortTimeFormat; 71 72 fCountry = other.fCountry; 73 fLanguage = other.fLanguage; 74 75 return *this; 76 } 77 78 79 BLocale::~BLocale() 80 { 81 delete fICULocale; 82 } 83 84 85 const char * 86 BLocale::GetString(uint32 id) 87 { 88 // Note: this code assumes a certain order of the string bases 89 90 if (id >= B_OTHER_STRINGS_BASE) { 91 if (id == B_CODESET) 92 return "UTF-8"; 93 94 return ""; 95 } 96 return fLanguage.GetString(id); 97 } 98 99 100 void 101 BLocale::SetCountry(const BCountry& newCountry) 102 { 103 fCountry = newCountry; 104 } 105 106 107 void 108 BLocale::SetCollator(const BCollator& newCollator) 109 { 110 fCollator = newCollator; 111 } 112 113 114 void 115 BLocale::SetLanguage(const char* languageCode) 116 { 117 fLanguage.SetTo(languageCode); 118 } 119 120 121 const char* 122 BLocale::Code() const 123 { 124 return fICULocale->getName(); 125 } 126 127 128 bool 129 BLocale::GetName(BString& name) const 130 { 131 UnicodeString uString; 132 fICULocale->getDisplayName(uString); 133 BStringByteSink stringConverter(&name); 134 uString.toUTF8(stringConverter); 135 return true; 136 } 137 138 // #pragma mark - Date 139 140 141 status_t 142 BLocale::FormatDate(char* string, size_t maxSize, time_t time, bool longFormat) 143 { 144 ObjectDeleter<DateFormat> dateFormatter = CreateDateFormat(longFormat, 145 *fICULocale, longFormat ? fLongDateFormat : fShortDateFormat); 146 if (dateFormatter.Get() == NULL) 147 return B_NO_MEMORY; 148 149 UnicodeString ICUString; 150 ICUString = dateFormatter->format((UDate)time * 1000, ICUString); 151 152 CheckedArrayByteSink stringConverter(string, maxSize); 153 154 ICUString.toUTF8(stringConverter); 155 156 if (stringConverter.Overflowed()) 157 return B_BAD_VALUE; 158 159 return B_OK; 160 } 161 162 163 status_t 164 BLocale::FormatDate(BString *string, time_t time, bool longFormat) 165 { 166 string->Truncate(0); 167 // We make the string empty, this way even in cases where ICU fail we at 168 // least return something sane 169 ObjectDeleter<DateFormat> dateFormatter = CreateDateFormat(longFormat, 170 *fICULocale, longFormat ? fLongDateFormat : fShortDateFormat); 171 if (dateFormatter.Get() == NULL) 172 return B_NO_MEMORY; 173 174 UnicodeString ICUString; 175 ICUString = dateFormatter->format((UDate)time * 1000, ICUString); 176 177 BStringByteSink stringConverter(string); 178 179 ICUString.toUTF8(stringConverter); 180 181 return B_OK; 182 } 183 184 185 status_t 186 BLocale::FormatDate(BString* string, int*& fieldPositions, int& fieldCount, 187 time_t time, bool longFormat) 188 { 189 string->Truncate(0); 190 191 ObjectDeleter<DateFormat> dateFormatter = CreateDateFormat(longFormat, 192 *fICULocale, longFormat ? fLongDateFormat : fShortDateFormat); 193 if (dateFormatter.Get() == NULL) 194 return B_NO_MEMORY; 195 196 fieldPositions = NULL; 197 UErrorCode error = U_ZERO_ERROR; 198 ICU_VERSION::FieldPositionIterator positionIterator; 199 UnicodeString ICUString; 200 ICUString = dateFormatter->format((UDate)time * 1000, ICUString, 201 &positionIterator, error); 202 203 if (error != U_ZERO_ERROR) 204 return B_ERROR; 205 206 ICU_VERSION::FieldPosition field; 207 std::vector<int> fieldPosStorage; 208 fieldCount = 0; 209 while (positionIterator.next(field)) { 210 fieldPosStorage.push_back(field.getBeginIndex()); 211 fieldPosStorage.push_back(field.getEndIndex()); 212 fieldCount += 2; 213 } 214 215 fieldPositions = (int*) malloc(fieldCount * sizeof(int)); 216 217 for (int i = 0 ; i < fieldCount ; i++ ) 218 fieldPositions[i] = fieldPosStorage[i]; 219 220 BStringByteSink stringConverter(string); 221 222 ICUString.toUTF8(stringConverter); 223 224 return B_OK; 225 } 226 227 228 status_t 229 BLocale::GetDateFormat(BString& format, bool longFormat) const 230 { 231 if (longFormat && fLongDateFormat.Length() > 0) 232 format = fLongDateFormat; 233 else if (!longFormat && fShortDateFormat.Length() > 0) 234 format = fShortDateFormat; 235 else { 236 format.Truncate(0); 237 238 ObjectDeleter<DateFormat> dateFormatter = CreateDateFormat(longFormat, 239 *fICULocale, longFormat ? fLongDateFormat : fShortDateFormat); 240 if (dateFormatter.Get() == NULL) 241 return B_NO_MEMORY; 242 243 SimpleDateFormat* dateFormatterImpl 244 = static_cast<SimpleDateFormat*>(dateFormatter.Get()); 245 246 UnicodeString ICUString; 247 ICUString = dateFormatterImpl->toPattern(ICUString); 248 249 BStringByteSink stringConverter(&format); 250 251 ICUString.toUTF8(stringConverter); 252 } 253 254 return B_OK; 255 } 256 257 258 status_t 259 BLocale::SetDateFormat(const char* formatString, bool longFormat) 260 { 261 printf("FV::SetDateFormat: df='%s'\n", formatString); 262 if (longFormat) 263 fLongDateFormat = formatString; 264 else 265 fShortDateFormat = formatString; 266 267 return B_OK; 268 } 269 270 271 status_t 272 BLocale::GetDateFields(BDateElement*& fields, int& fieldCount, 273 bool longFormat) const 274 { 275 ObjectDeleter<DateFormat> dateFormatter = CreateDateFormat(longFormat, 276 *fICULocale, longFormat ? fLongDateFormat : fShortDateFormat); 277 if (dateFormatter.Get() == NULL) 278 return B_NO_MEMORY; 279 280 fields = NULL; 281 UErrorCode error = U_ZERO_ERROR; 282 ICU_VERSION::FieldPositionIterator positionIterator; 283 UnicodeString ICUString; 284 time_t now; 285 ICUString = dateFormatter->format((UDate)time(&now) * 1000, ICUString, 286 &positionIterator, error); 287 288 if (U_FAILURE(error)) 289 return B_ERROR; 290 291 ICU_VERSION::FieldPosition field; 292 std::vector<int> fieldPosStorage; 293 fieldCount = 0; 294 while (positionIterator.next(field)) { 295 fieldPosStorage.push_back(field.getField()); 296 fieldCount ++; 297 } 298 299 fields = (BDateElement*) malloc(fieldCount * sizeof(BDateElement)); 300 301 for (int i = 0 ; i < fieldCount ; i++ ) { 302 switch (fieldPosStorage[i]) { 303 case UDAT_YEAR_FIELD: 304 fields[i] = B_DATE_ELEMENT_YEAR; 305 break; 306 case UDAT_MONTH_FIELD: 307 fields[i] = B_DATE_ELEMENT_MONTH; 308 break; 309 case UDAT_DATE_FIELD: 310 fields[i] = B_DATE_ELEMENT_DAY; 311 break; 312 default: 313 fields[i] = B_DATE_ELEMENT_INVALID; 314 break; 315 } 316 } 317 318 return B_OK; 319 } 320 321 322 int 323 BLocale::StartOfWeek() const 324 { 325 UErrorCode err = U_ZERO_ERROR; 326 Calendar* c = Calendar::createInstance(*fICULocale, err); 327 328 if (err == U_ZERO_ERROR && c->getFirstDayOfWeek(err) == UCAL_SUNDAY) { 329 delete c; 330 return B_WEEK_START_SUNDAY; 331 } else { 332 delete c; 333 // Might be another day, but BeAPI will not handle it 334 return B_WEEK_START_MONDAY; 335 } 336 } 337 338 339 status_t 340 BLocale::FormatDateTime(char* target, size_t maxSize, time_t time, 341 bool longFormat) 342 { 343 ObjectDeleter<DateFormat> dateFormatter = CreateDateFormat(longFormat, 344 *fICULocale, longFormat ? fLongDateFormat : fShortDateFormat); 345 if (dateFormatter.Get() == NULL) 346 return B_NO_MEMORY; 347 348 ObjectDeleter<DateFormat> timeFormatter = CreateTimeFormat(longFormat, 349 *fICULocale, longFormat ? fLongTimeFormat : fShortTimeFormat); 350 if (timeFormatter.Get() == NULL) 351 return B_NO_MEMORY; 352 353 UnicodeString ICUString; 354 ICUString = dateFormatter->format((UDate)time * 1000, ICUString); 355 356 ICUString.append(UnicodeString::fromUTF8(", ")); 357 358 ICUString = timeFormatter->format((UDate)time * 1000, ICUString); 359 360 CheckedArrayByteSink stringConverter(target, maxSize); 361 ICUString.toUTF8(stringConverter); 362 363 if (stringConverter.Overflowed()) 364 return B_BAD_VALUE; 365 366 return B_OK; 367 } 368 369 370 // #pragma mark - Time 371 372 373 status_t 374 BLocale::FormatTime(char* string, size_t maxSize, time_t time, bool longFormat) 375 { 376 ObjectDeleter<DateFormat> timeFormatter = CreateTimeFormat(longFormat, 377 *fICULocale, longFormat ? fLongTimeFormat : fShortTimeFormat); 378 if (timeFormatter.Get() == NULL) 379 return B_NO_MEMORY; 380 381 UnicodeString ICUString; 382 ICUString = timeFormatter->format((UDate)time * 1000, ICUString); 383 384 CheckedArrayByteSink stringConverter(string, maxSize); 385 386 ICUString.toUTF8(stringConverter); 387 388 if (stringConverter.Overflowed()) 389 return B_BAD_VALUE; 390 391 return B_OK; 392 } 393 394 395 status_t 396 BLocale::FormatTime(BString* string, time_t time, bool longFormat) 397 { 398 string->Truncate(0); 399 400 ObjectDeleter<DateFormat> timeFormatter = CreateTimeFormat(longFormat, 401 *fICULocale, longFormat ? fLongTimeFormat : fShortTimeFormat); 402 if (timeFormatter.Get() == NULL) 403 return B_NO_MEMORY; 404 405 UnicodeString ICUString; 406 ICUString = timeFormatter->format((UDate)time * 1000, ICUString); 407 408 BStringByteSink stringConverter(string); 409 410 ICUString.toUTF8(stringConverter); 411 412 return B_OK; 413 } 414 415 416 status_t 417 BLocale::FormatTime(BString* string, int*& fieldPositions, int& fieldCount, 418 time_t time, bool longFormat) 419 { 420 string->Truncate(0); 421 422 ObjectDeleter<DateFormat> timeFormatter = CreateTimeFormat(longFormat, 423 *fICULocale, longFormat ? fLongTimeFormat : fShortTimeFormat); 424 if (timeFormatter.Get() == NULL) 425 return B_NO_MEMORY; 426 427 fieldPositions = NULL; 428 UErrorCode error = U_ZERO_ERROR; 429 ICU_VERSION::FieldPositionIterator positionIterator; 430 UnicodeString ICUString; 431 ICUString = timeFormatter->format((UDate)time * 1000, ICUString, 432 &positionIterator, error); 433 434 if (error != U_ZERO_ERROR) 435 return B_ERROR; 436 437 ICU_VERSION::FieldPosition field; 438 std::vector<int> fieldPosStorage; 439 fieldCount = 0; 440 while (positionIterator.next(field)) { 441 fieldPosStorage.push_back(field.getBeginIndex()); 442 fieldPosStorage.push_back(field.getEndIndex()); 443 fieldCount += 2; 444 } 445 446 fieldPositions = (int*) malloc(fieldCount * sizeof(int)); 447 448 for (int i = 0 ; i < fieldCount ; i++ ) 449 fieldPositions[i] = fieldPosStorage[i]; 450 451 BStringByteSink stringConverter(string); 452 453 ICUString.toUTF8(stringConverter); 454 455 return B_OK; 456 } 457 458 459 status_t 460 BLocale::GetTimeFields(BDateElement*& fields, int& fieldCount, 461 bool longFormat) const 462 { 463 ObjectDeleter<DateFormat> timeFormatter = CreateTimeFormat(longFormat, 464 *fICULocale, longFormat ? fLongTimeFormat : fShortTimeFormat); 465 if (timeFormatter.Get() == NULL) 466 return B_NO_MEMORY; 467 468 fields = NULL; 469 UErrorCode error = U_ZERO_ERROR; 470 ICU_VERSION::FieldPositionIterator positionIterator; 471 UnicodeString ICUString; 472 time_t now; 473 ICUString = timeFormatter->format((UDate)time(&now) * 1000, ICUString, 474 &positionIterator, error); 475 476 if (error != U_ZERO_ERROR) 477 return B_ERROR; 478 479 ICU_VERSION::FieldPosition field; 480 std::vector<int> fieldPosStorage; 481 fieldCount = 0; 482 while (positionIterator.next(field)) { 483 fieldPosStorage.push_back(field.getField()); 484 fieldCount ++; 485 } 486 487 fields = (BDateElement*) malloc(fieldCount * sizeof(BDateElement)); 488 489 for (int i = 0 ; i < fieldCount ; i++ ) { 490 switch (fieldPosStorage[i]) { 491 case UDAT_HOUR_OF_DAY1_FIELD: 492 case UDAT_HOUR_OF_DAY0_FIELD: 493 case UDAT_HOUR1_FIELD: 494 case UDAT_HOUR0_FIELD: 495 fields[i] = B_DATE_ELEMENT_HOUR; 496 break; 497 case UDAT_MINUTE_FIELD: 498 fields[i] = B_DATE_ELEMENT_MINUTE; 499 break; 500 case UDAT_SECOND_FIELD: 501 fields[i] = B_DATE_ELEMENT_SECOND; 502 break; 503 case UDAT_AM_PM_FIELD: 504 fields[i] = B_DATE_ELEMENT_AM_PM; 505 break; 506 default: 507 fields[i] = B_DATE_ELEMENT_INVALID; 508 break; 509 } 510 } 511 512 return B_OK; 513 } 514 515 516 status_t 517 BLocale::SetTimeFormat(const char* formatString, bool longFormat) 518 { 519 if (longFormat) 520 fLongTimeFormat = formatString; 521 else 522 fShortTimeFormat = formatString; 523 524 return B_OK; 525 } 526 527 528 status_t 529 BLocale::GetTimeFormat(BString& format, bool longFormat) const 530 { 531 if (longFormat && fLongTimeFormat.Length() > 0) 532 format = fLongTimeFormat; 533 else if (!longFormat && fShortTimeFormat.Length() > 0) 534 format = fShortTimeFormat; 535 else { 536 format.Truncate(0); 537 538 ObjectDeleter<DateFormat> timeFormatter = CreateTimeFormat(longFormat, 539 *fICULocale, longFormat ? fLongTimeFormat : fShortTimeFormat); 540 if (timeFormatter.Get() == NULL) 541 return B_NO_MEMORY; 542 543 SimpleDateFormat* timeFormatterImpl 544 = static_cast<SimpleDateFormat*>(timeFormatter.Get()); 545 546 UnicodeString ICUString; 547 ICUString = timeFormatterImpl->toPattern(ICUString); 548 549 BStringByteSink stringConverter(&format); 550 ICUString.toUTF8(stringConverter); 551 } 552 553 return B_OK; 554 } 555 556 557 // #pragma mark - Numbers 558 559 560 status_t 561 BLocale::FormatNumber(char* string, size_t maxSize, double value) 562 { 563 BString fullString; 564 status_t status = FormatNumber(&fullString, value); 565 if (status == B_OK) 566 strlcpy(string, fullString.String(), maxSize); 567 568 return status; 569 } 570 571 572 status_t 573 BLocale::FormatNumber(BString* string, double value) 574 { 575 UErrorCode err = U_ZERO_ERROR; 576 ObjectDeleter<NumberFormat> numberFormatter = NumberFormat::createInstance( 577 *fICULocale, NumberFormat::kNumberStyle, err); 578 579 if (numberFormatter.Get() == NULL) 580 return B_NO_MEMORY; 581 if (U_FAILURE(err)) 582 return B_ERROR; 583 584 UnicodeString ICUString; 585 ICUString = numberFormatter->format(value, ICUString); 586 587 string->Truncate(0); 588 BStringByteSink stringConverter(string); 589 ICUString.toUTF8(stringConverter); 590 591 return B_OK; 592 } 593 594 595 status_t 596 BLocale::FormatNumber(char* string, size_t maxSize, int32 value) 597 { 598 BString fullString; 599 status_t status = FormatNumber(&fullString, value); 600 if (status == B_OK) 601 strlcpy(string, fullString.String(), maxSize); 602 603 return status; 604 } 605 606 607 status_t 608 BLocale::FormatNumber(BString* string, int32 value) 609 { 610 UErrorCode err = U_ZERO_ERROR; 611 ObjectDeleter<NumberFormat> numberFormatter = NumberFormat::createInstance( 612 *fICULocale, NumberFormat::kNumberStyle, err); 613 614 if (numberFormatter.Get() == NULL) 615 return B_NO_MEMORY; 616 if (U_FAILURE(err)) 617 return B_ERROR; 618 619 UnicodeString ICUString; 620 ICUString = numberFormatter->format((int32_t)value, ICUString); 621 622 string->Truncate(0); 623 BStringByteSink stringConverter(string); 624 ICUString.toUTF8(stringConverter); 625 626 return B_OK; 627 } 628 629 630 ssize_t 631 BLocale::FormatMonetary(char* string, size_t maxSize, double value) 632 { 633 BString fullString; 634 ssize_t written = FormatMonetary(&fullString, value); 635 if (written < 0) 636 return written; 637 638 return strlcpy(string, fullString.String(), maxSize); 639 } 640 641 642 ssize_t 643 BLocale::FormatMonetary(BString* string, double value) 644 { 645 if (string == NULL) 646 return B_BAD_VALUE; 647 648 UErrorCode err; 649 ObjectDeleter<NumberFormat> numberFormatter 650 = NumberFormat::createCurrencyInstance(*fICULocale, err); 651 652 if (numberFormatter.Get() == NULL) 653 return B_NO_MEMORY; 654 if (U_FAILURE(err)) 655 return B_ERROR; 656 657 UnicodeString ICUString; 658 ICUString = numberFormatter->format(value, ICUString); 659 660 string->Truncate(0); 661 BStringByteSink stringConverter(string); 662 ICUString.toUTF8(stringConverter); 663 664 return string->Length(); 665 } 666 667 668 // #pragma mark - Helpers 669 670 671 static DateFormat* 672 CreateDateFormat(bool longFormat, const Locale& locale, 673 const BString& format) 674 { 675 DateFormat* dateFormatter = DateFormat::createDateInstance( 676 longFormat ? DateFormat::FULL : DateFormat::SHORT, locale); 677 678 if (format.Length() > 0) { 679 SimpleDateFormat* dateFormatterImpl 680 = static_cast<SimpleDateFormat*>(dateFormatter); 681 682 UnicodeString pattern(format.String()); 683 dateFormatterImpl->applyPattern(pattern); 684 } 685 686 return dateFormatter; 687 } 688 689 690 static DateFormat* 691 CreateTimeFormat(bool longFormat, const Locale& locale, 692 const BString& format) 693 { 694 DateFormat* timeFormatter = DateFormat::createTimeInstance( 695 longFormat ? DateFormat::MEDIUM : DateFormat::SHORT, locale); 696 697 if (format.Length() > 0) { 698 SimpleDateFormat* timeFormatterImpl 699 = static_cast<SimpleDateFormat*>(timeFormatter); 700 701 UnicodeString pattern(format.String()); 702 timeFormatterImpl->applyPattern(pattern); 703 } 704 705 return timeFormatter; 706 } 707