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 <Country.h> 8 9 #include <assert.h> 10 11 #include <String.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 <monetary.h> 21 #include <stdarg.h> 22 23 24 const char* gStrings[] = { 25 // date/time format 26 "", 27 "", 28 // short date/time format 29 "", 30 "", 31 // am/pm string 32 "AM", 33 "PM", 34 // separators 35 ".", 36 ":", 37 38 // currency/monetary 39 "." 40 "," 41 }; 42 43 44 BCountry::BCountry(const char* languageCode, const char* countryCode) 45 : 46 fStrings(gStrings) 47 { 48 fICULocale = new icu_4_2::Locale(languageCode, countryCode); 49 } 50 51 52 BCountry::BCountry(const char* languageAndCountryCode) 53 : 54 fStrings(gStrings) 55 { 56 fICULocale = new icu_4_2::Locale(languageAndCountryCode); 57 fICULongDateFormatter = DateFormat::createDateInstance( 58 DateFormat::FULL, *fICULocale); 59 fICUShortDateFormatter = DateFormat::createDateInstance( 60 DateFormat::SHORT, *fICULocale); 61 } 62 63 64 BCountry::~BCountry() 65 { 66 delete fICULocale; 67 } 68 69 70 bool 71 BCountry::Name(BString& name) const 72 { 73 UnicodeString uString; 74 fICULocale->getDisplayName(uString); 75 BStringByteSink stringConverter(&name); 76 uString.toUTF8(stringConverter); 77 return true; 78 } 79 80 81 const char* 82 BCountry::Code() const 83 { 84 return fICULocale->getName(); 85 } 86 87 88 // TODO use ICU backend keywords instead 89 const char* 90 BCountry::GetString(uint32 id) const 91 { 92 if (id < B_COUNTRY_STRINGS_BASE || id >= B_NUM_COUNTRY_STRINGS) 93 return NULL; 94 95 return gStrings[id - B_COUNTRY_STRINGS_BASE]; 96 } 97 98 99 void 100 BCountry::FormatDate(char* string, size_t maxSize, time_t time, bool longFormat) 101 { 102 BString fullString; 103 FormatDate(&fullString, time, longFormat); 104 strncpy(string, fullString.String(), maxSize); 105 } 106 107 108 void 109 BCountry::FormatDate(BString *string, time_t time, bool longFormat) 110 { 111 // TODO: ICU allows for 4 different levels of expansion : 112 // short, medium, long, and full. Our bool parameter is not enough... 113 icu_4_2::DateFormat* dateFormatter 114 = longFormat ? fICULongDateFormatter : fICUShortDateFormatter; 115 UnicodeString ICUString; 116 ICUString = dateFormatter->format((UDate)time * 1000, ICUString); 117 118 string->Truncate(0); 119 BStringByteSink stringConverter(string); 120 121 ICUString.toUTF8(stringConverter); 122 } 123 124 125 void 126 BCountry::FormatTime(char* string, size_t maxSize, time_t time, bool longFormat) 127 { 128 BString fullString; 129 FormatTime(&fullString, time, longFormat); 130 strncpy(string, fullString.String(), maxSize); 131 } 132 133 134 void 135 BCountry::FormatTime(BString* string, time_t time, bool longFormat) 136 { 137 // TODO: ICU allows for 4 different levels of expansion : 138 // short, medium, long, and full. Our bool parameter is not enough... 139 icu_4_2::DateFormat* timeFormatter; 140 timeFormatter = DateFormat::createTimeInstance( 141 longFormat ? DateFormat::FULL : DateFormat::SHORT, 142 *fICULocale); 143 UnicodeString ICUString; 144 ICUString = timeFormatter->format((UDate)time * 1000, ICUString); 145 146 string->Truncate(0); 147 BStringByteSink stringConverter(string); 148 149 ICUString.toUTF8(stringConverter); 150 } 151 152 153 bool 154 BCountry::DateFormat(BString& format, bool longFormat) const 155 { 156 icu_4_2::DateFormat* dateFormatter 157 = longFormat ? fICULongDateFormatter : fICUShortDateFormatter; 158 SimpleDateFormat* dateFormatterImpl 159 = static_cast<SimpleDateFormat*>(dateFormatter); 160 161 UnicodeString ICUString; 162 ICUString = dateFormatterImpl->toPattern(ICUString); 163 164 BStringByteSink stringConverter(&format); 165 166 ICUString.toUTF8(stringConverter); 167 168 return true; 169 } 170 171 172 void 173 BCountry::SetDateFormat(const char* formatString, bool longFormat) 174 { 175 icu_4_2::DateFormat* dateFormatter 176 = longFormat ? fICULongDateFormatter : fICUShortDateFormatter; 177 SimpleDateFormat* dateFormatterImpl 178 = static_cast<SimpleDateFormat*>(dateFormatter); 179 180 UnicodeString pattern(formatString); 181 dateFormatterImpl->applyPattern(pattern); 182 } 183 184 185 bool 186 BCountry::TimeFormat(BString& format, bool longFormat) const 187 { 188 icu_4_2::DateFormat* dateFormatter; 189 dateFormatter = DateFormat::createTimeInstance( 190 longFormat ? DateFormat::FULL : DateFormat::SHORT, 191 *fICULocale); 192 SimpleDateFormat* dateFormatterImpl 193 = static_cast<SimpleDateFormat*>(dateFormatter); 194 195 UnicodeString ICUString; 196 ICUString = dateFormatterImpl->toPattern(ICUString); 197 198 BStringByteSink stringConverter(&format); 199 200 ICUString.toUTF8(stringConverter); 201 202 return true; 203 } 204 205 206 // TODO find how to get it from ICU (setting it is ok, we use the pattern-string 207 // for that) 208 // Or remove this function ? 209 const char* 210 BCountry::DateSeparator() const 211 { 212 return fStrings[B_DATE_SEPARATOR]; 213 } 214 215 216 const char* 217 BCountry::TimeSeparator() const 218 { 219 return fStrings[B_TIME_SEPARATOR]; 220 } 221 222 223 void 224 BCountry::FormatNumber(char* string, size_t maxSize, double value) 225 { 226 BString fullString; 227 FormatNumber(&fullString, value); 228 strncpy(string, fullString.String(), maxSize); 229 } 230 231 232 status_t 233 BCountry::FormatNumber(BString* string, double value) 234 { 235 UErrorCode err = U_ZERO_ERROR; 236 NumberFormat* numberFormatter 237 = NumberFormat::createInstance(*fICULocale, NumberFormat::kNumberStyle, 238 err); 239 240 // Warning: we're returning an ICU error here but the type is status_t. 241 if (U_FAILURE(err)) return err; 242 243 UnicodeString ICUString; 244 ICUString = numberFormatter->format(value, ICUString); 245 246 string->Truncate(0); 247 BStringByteSink stringConverter(string); 248 249 ICUString.toUTF8(stringConverter); 250 251 return U_ZERO_ERROR; 252 } 253 254 255 void 256 BCountry::FormatNumber(char* string, size_t maxSize, int32 value) 257 { 258 BString fullString; 259 FormatNumber(&fullString, value); 260 strncpy(string, fullString.String(), maxSize); 261 } 262 263 264 void 265 BCountry::FormatNumber(BString* string, int32 value) 266 { 267 UErrorCode err; 268 NumberFormat* numberFormatter 269 = NumberFormat::createInstance(*fICULocale, err); 270 271 assert(err == U_ZERO_ERROR); 272 273 UnicodeString ICUString; 274 ICUString = numberFormatter->format((int32_t)value, ICUString); 275 276 string->Truncate(0); 277 BStringByteSink stringConverter(string); 278 279 ICUString.toUTF8(stringConverter); 280 } 281 282 283 // This will only work for locales using the decimal system... 284 bool 285 BCountry::DecimalPoint(BString& format) const 286 { 287 UErrorCode err; 288 NumberFormat* numberFormatter 289 = NumberFormat::createInstance(*fICULocale, err); 290 291 assert(err == U_ZERO_ERROR); 292 293 DecimalFormat* decimalFormatter 294 = dynamic_cast<DecimalFormat*>(numberFormatter); 295 296 assert(decimalFormatter != NULL); 297 298 const DecimalFormatSymbols* syms 299 = decimalFormatter->getDecimalFormatSymbols(); 300 301 UnicodeString ICUString; 302 ICUString = syms->getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol); 303 304 BStringByteSink stringConverter(&format); 305 306 ICUString.toUTF8(stringConverter); 307 308 return true; 309 } 310 311 312 bool 313 BCountry::ThousandsSeparator(BString& separator) const 314 { 315 UErrorCode err; 316 NumberFormat* numberFormatter 317 = NumberFormat::createInstance(*fICULocale, err); 318 assert(err == U_ZERO_ERROR); 319 DecimalFormat* decimalFormatter 320 = dynamic_cast<DecimalFormat*>(numberFormatter); 321 322 assert(decimalFormatter != NULL); 323 324 const DecimalFormatSymbols* syms 325 = decimalFormatter->getDecimalFormatSymbols(); 326 327 UnicodeString ICUString; 328 ICUString = syms->getSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol); 329 330 BStringByteSink stringConverter(&separator); 331 332 ICUString.toUTF8(stringConverter); 333 334 return true; 335 } 336 337 338 bool 339 BCountry::Grouping(BString& grouping) const 340 { 341 UErrorCode err; 342 NumberFormat* numberFormatter 343 = NumberFormat::createInstance(*fICULocale, err); 344 assert(err == U_ZERO_ERROR); 345 DecimalFormat* decimalFormatter 346 = dynamic_cast<DecimalFormat*>(numberFormatter); 347 348 assert(decimalFormatter != NULL); 349 350 const DecimalFormatSymbols* syms 351 = decimalFormatter->getDecimalFormatSymbols(); 352 353 UnicodeString ICUString; 354 ICUString = syms->getSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol); 355 356 BStringByteSink stringConverter(&grouping); 357 358 ICUString.toUTF8(stringConverter); 359 360 return true; 361 } 362 363 364 bool 365 BCountry::PositiveSign(BString& sign) const 366 { 367 UErrorCode err; 368 NumberFormat* numberFormatter 369 = NumberFormat::createInstance(*fICULocale, err); 370 assert(err == U_ZERO_ERROR); 371 DecimalFormat* decimalFormatter 372 = dynamic_cast<DecimalFormat*>(numberFormatter); 373 374 assert(decimalFormatter != NULL); 375 376 const DecimalFormatSymbols* syms 377 = decimalFormatter->getDecimalFormatSymbols(); 378 379 UnicodeString ICUString; 380 ICUString = syms->getSymbol(DecimalFormatSymbols::kPlusSignSymbol); 381 382 BStringByteSink stringConverter(&sign); 383 384 ICUString.toUTF8(stringConverter); 385 386 return true; 387 } 388 389 390 bool 391 BCountry::NegativeSign(BString& sign) const 392 { 393 UErrorCode err; 394 NumberFormat* numberFormatter 395 = NumberFormat::createInstance(*fICULocale, err); 396 assert(err == U_ZERO_ERROR); 397 DecimalFormat* decimalFormatter 398 = dynamic_cast<DecimalFormat*>(numberFormatter); 399 400 assert(decimalFormatter != NULL); 401 402 const DecimalFormatSymbols* syms 403 = decimalFormatter->getDecimalFormatSymbols(); 404 405 UnicodeString ICUString; 406 ICUString = syms->getSymbol(DecimalFormatSymbols::kMinusSignSymbol); 407 408 BStringByteSink stringConverter(&sign); 409 410 ICUString.toUTF8(stringConverter); 411 412 return true; 413 } 414 415 416 // TODO does ICU even support this ? Is it in the keywords ? 417 int8 418 BCountry::Measurement() const 419 { 420 return B_US; 421 } 422 423 424 ssize_t 425 BCountry::FormatMonetary(char* string, size_t maxSize, double value) 426 { 427 BString fullString; 428 FormatMonetary(&fullString, value); 429 strncpy(string, fullString.String(), maxSize); 430 } 431 432 433 ssize_t 434 BCountry::FormatMonetary(BString* string, double value) 435 { 436 UErrorCode err; 437 NumberFormat* numberFormatter 438 = NumberFormat::createCurrencyInstance(*fICULocale, err); 439 440 assert(err == U_ZERO_ERROR); 441 442 UnicodeString ICUString; 443 ICUString = numberFormatter->format(value, ICUString); 444 445 string->Truncate(0); 446 BStringByteSink stringConverter(string); 447 448 ICUString.toUTF8(stringConverter); 449 450 return B_OK; 451 } 452 453 454 bool 455 BCountry::CurrencySymbol(BString& symbol) const 456 { 457 UErrorCode err; 458 NumberFormat* numberFormatter 459 = NumberFormat::createCurrencyInstance(*fICULocale, err); 460 assert(err == U_ZERO_ERROR); 461 DecimalFormat* decimalFormatter 462 = dynamic_cast<DecimalFormat*>(numberFormatter); 463 464 assert(decimalFormatter != NULL); 465 466 const DecimalFormatSymbols* syms 467 = decimalFormatter->getDecimalFormatSymbols(); 468 469 UnicodeString ICUString; 470 ICUString = syms->getSymbol(DecimalFormatSymbols::kCurrencySymbol); 471 472 BStringByteSink stringConverter(&symbol); 473 474 ICUString.toUTF8(stringConverter); 475 476 return true; 477 } 478 479 480 bool 481 BCountry::InternationalCurrencySymbol(BString& symbol) const 482 { 483 UErrorCode err; 484 NumberFormat* numberFormatter 485 = NumberFormat::createCurrencyInstance(*fICULocale, err); 486 assert(err == U_ZERO_ERROR); 487 DecimalFormat* decimalFormatter 488 = dynamic_cast<DecimalFormat*>(numberFormatter); 489 490 assert(decimalFormatter != NULL); 491 492 const DecimalFormatSymbols* syms 493 = decimalFormatter->getDecimalFormatSymbols(); 494 495 UnicodeString ICUString; 496 ICUString = syms->getSymbol(DecimalFormatSymbols::kIntlCurrencySymbol); 497 498 BStringByteSink stringConverter(&symbol); 499 500 ICUString.toUTF8(stringConverter); 501 502 return true; 503 } 504 505 506 bool 507 BCountry::MonDecimalPoint(BString& decimal) const 508 { 509 UErrorCode err; 510 NumberFormat* numberFormatter 511 = NumberFormat::createCurrencyInstance(*fICULocale, err); 512 assert(err == U_ZERO_ERROR); 513 DecimalFormat* decimalFormatter 514 = dynamic_cast<DecimalFormat*>(numberFormatter); 515 516 assert(decimalFormatter != NULL); 517 518 const DecimalFormatSymbols* syms 519 = decimalFormatter->getDecimalFormatSymbols(); 520 521 UnicodeString ICUString; 522 ICUString = syms->getSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol); 523 524 BStringByteSink stringConverter(&decimal); 525 526 ICUString.toUTF8(stringConverter); 527 528 return true; 529 } 530 531 532 bool 533 BCountry::MonThousandsSeparator(BString& separator) const 534 { 535 UErrorCode err; 536 NumberFormat* numberFormatter 537 = NumberFormat::createCurrencyInstance(*fICULocale, err); 538 assert(err == U_ZERO_ERROR); 539 DecimalFormat* decimalFormatter 540 = dynamic_cast<DecimalFormat*>(numberFormatter); 541 542 assert(decimalFormatter != NULL); 543 544 const DecimalFormatSymbols* syms 545 = decimalFormatter->getDecimalFormatSymbols(); 546 547 UnicodeString ICUString; 548 ICUString = syms->getSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol); 549 550 BStringByteSink stringConverter(&separator); 551 552 ICUString.toUTF8(stringConverter); 553 554 return true; 555 } 556 557 558 bool 559 BCountry::MonGrouping(BString& grouping) const 560 { 561 UErrorCode err; 562 NumberFormat* numberFormatter 563 = NumberFormat::createCurrencyInstance(*fICULocale, err); 564 assert(err == U_ZERO_ERROR); 565 DecimalFormat* decimalFormatter 566 = dynamic_cast<DecimalFormat*>(numberFormatter); 567 568 assert(decimalFormatter != NULL); 569 570 const DecimalFormatSymbols* syms 571 = decimalFormatter->getDecimalFormatSymbols(); 572 573 UnicodeString ICUString; 574 ICUString = syms->getSymbol( 575 DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol); 576 577 BStringByteSink stringConverter(&grouping); 578 579 ICUString.toUTF8(stringConverter); 580 581 return true; 582 } 583 584 585 // TODO: is this possible to get from ICU ? 586 int32 587 BCountry::MonFracDigits() const 588 { 589 return 2; 590 } 591 592