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