OLD | NEW |
(Empty) | |
| 1 /* |
| 2 ****************************************************************************** |
| 3 * Copyright (C) 2014, International Business Machines Corporation and |
| 4 * others. All Rights Reserved. |
| 5 ****************************************************************************** |
| 6 * |
| 7 * File RELDATEFMT.CPP
|
| 8 ****************************************************************************** |
| 9 */ |
| 10 |
| 11 #include "unicode/reldatefmt.h" |
| 12 |
| 13 #if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_BREAK_ITERATION |
| 14 |
| 15 #include "unicode/localpointer.h" |
| 16 #include "quantityformatter.h" |
| 17 #include "unicode/plurrule.h" |
| 18 #include "unicode/msgfmt.h" |
| 19 #include "unicode/decimfmt.h" |
| 20 #include "unicode/numfmt.h" |
| 21 #include "unicode/brkiter.h" |
| 22 #include "uresimp.h" |
| 23 #include "unicode/ures.h" |
| 24 #include "cstring.h" |
| 25 #include "ucln_in.h" |
| 26 #include "mutex.h" |
| 27 #include "charstr.h" |
| 28 #include "uassert.h" |
| 29 |
| 30 #include "sharedbreakiterator.h" |
| 31 #include "sharedpluralrules.h" |
| 32 #include "sharednumberformat.h" |
| 33 #include "unifiedcache.h" |
| 34 |
| 35 // Copied from uscript_props.cpp |
| 36 |
| 37 static UMutex gBrkIterMutex = U_MUTEX_INITIALIZER; |
| 38 |
| 39 U_NAMESPACE_BEGIN |
| 40 |
| 41 // RelativeDateTimeFormatter specific data for a single locale |
| 42 class RelativeDateTimeCacheData: public SharedObject { |
| 43 public: |
| 44 RelativeDateTimeCacheData() : combinedDateAndTime(NULL) { } |
| 45 virtual ~RelativeDateTimeCacheData(); |
| 46 |
| 47 // no numbers: e.g Next Tuesday; Yesterday; etc. |
| 48 UnicodeString absoluteUnits[UDAT_STYLE_COUNT][UDAT_ABSOLUTE_UNIT_COUNT][UDAT
_DIRECTION_COUNT]; |
| 49 |
| 50 // has numbers: e.g Next Tuesday; Yesterday; etc. For second index, 0 |
| 51 // means past e.g 5 days ago; 1 means future e.g in 5 days. |
| 52 QuantityFormatter relativeUnits[UDAT_STYLE_COUNT][UDAT_RELATIVE_UNIT_COUNT][
2]; |
| 53 |
| 54 void adoptCombinedDateAndTime(MessageFormat *mfToAdopt) { |
| 55 delete combinedDateAndTime; |
| 56 combinedDateAndTime = mfToAdopt; |
| 57 } |
| 58 const MessageFormat *getCombinedDateAndTime() const { |
| 59 return combinedDateAndTime; |
| 60 } |
| 61 private: |
| 62 MessageFormat *combinedDateAndTime; |
| 63 RelativeDateTimeCacheData(const RelativeDateTimeCacheData &other); |
| 64 RelativeDateTimeCacheData& operator=( |
| 65 const RelativeDateTimeCacheData &other); |
| 66 }; |
| 67 |
| 68 RelativeDateTimeCacheData::~RelativeDateTimeCacheData() { |
| 69 delete combinedDateAndTime; |
| 70 } |
| 71 |
| 72 static UBool getStringWithFallback( |
| 73 const UResourceBundle *resource, |
| 74 const char *key, |
| 75 UnicodeString &result, |
| 76 UErrorCode &status) { |
| 77 int32_t len = 0; |
| 78 const UChar *resStr = ures_getStringByKeyWithFallback( |
| 79 resource, key, &len, &status); |
| 80 if (U_FAILURE(status)) { |
| 81 return FALSE; |
| 82 } |
| 83 result.setTo(TRUE, resStr, len); |
| 84 return TRUE; |
| 85 } |
| 86 |
| 87 static UBool getOptionalStringWithFallback( |
| 88 const UResourceBundle *resource, |
| 89 const char *key, |
| 90 UnicodeString &result, |
| 91 UErrorCode &status) { |
| 92 if (U_FAILURE(status)) { |
| 93 return FALSE; |
| 94 } |
| 95 int32_t len = 0; |
| 96 const UChar *resStr = ures_getStringByKey( |
| 97 resource, key, &len, &status); |
| 98 if (status == U_MISSING_RESOURCE_ERROR) { |
| 99 result.remove(); |
| 100 status = U_ZERO_ERROR; |
| 101 return TRUE; |
| 102 } |
| 103 if (U_FAILURE(status)) { |
| 104 return FALSE; |
| 105 } |
| 106 result.setTo(TRUE, resStr, len); |
| 107 return TRUE; |
| 108 } |
| 109 |
| 110 static UBool getString( |
| 111 const UResourceBundle *resource, |
| 112 UnicodeString &result, |
| 113 UErrorCode &status) { |
| 114 int32_t len = 0; |
| 115 const UChar *resStr = ures_getString(resource, &len, &status); |
| 116 if (U_FAILURE(status)) { |
| 117 return FALSE; |
| 118 } |
| 119 result.setTo(TRUE, resStr, len); |
| 120 return TRUE; |
| 121 } |
| 122 |
| 123 static UBool getStringByIndex( |
| 124 const UResourceBundle *resource, |
| 125 int32_t idx, |
| 126 UnicodeString &result, |
| 127 UErrorCode &status) { |
| 128 int32_t len = 0; |
| 129 const UChar *resStr = ures_getStringByIndex( |
| 130 resource, idx, &len, &status); |
| 131 if (U_FAILURE(status)) { |
| 132 return FALSE; |
| 133 } |
| 134 result.setTo(TRUE, resStr, len); |
| 135 return TRUE; |
| 136 } |
| 137 |
| 138 static void initAbsoluteUnit( |
| 139 const UResourceBundle *resource, |
| 140 const UnicodeString &unitName, |
| 141 UnicodeString *absoluteUnit, |
| 142 UErrorCode &status) { |
| 143 getStringWithFallback( |
| 144 resource, |
| 145 "-1", |
| 146 absoluteUnit[UDAT_DIRECTION_LAST], |
| 147 status); |
| 148 getStringWithFallback( |
| 149 resource, |
| 150 "0", |
| 151 absoluteUnit[UDAT_DIRECTION_THIS], |
| 152 status); |
| 153 getStringWithFallback( |
| 154 resource, |
| 155 "1", |
| 156 absoluteUnit[UDAT_DIRECTION_NEXT], |
| 157 status); |
| 158 getOptionalStringWithFallback( |
| 159 resource, |
| 160 "-2", |
| 161 absoluteUnit[UDAT_DIRECTION_LAST_2], |
| 162 status); |
| 163 getOptionalStringWithFallback( |
| 164 resource, |
| 165 "2", |
| 166 absoluteUnit[UDAT_DIRECTION_NEXT_2], |
| 167 status); |
| 168 absoluteUnit[UDAT_DIRECTION_PLAIN] = unitName; |
| 169 } |
| 170 |
| 171 static void initQuantityFormatter( |
| 172 const UResourceBundle *resource, |
| 173 QuantityFormatter &formatter, |
| 174 UErrorCode &status) { |
| 175 if (U_FAILURE(status)) { |
| 176 return; |
| 177 } |
| 178 int32_t size = ures_getSize(resource); |
| 179 for (int32_t i = 0; i < size; ++i) { |
| 180 LocalUResourceBundlePointer pluralBundle( |
| 181 ures_getByIndex(resource, i, NULL, &status)); |
| 182 if (U_FAILURE(status)) { |
| 183 return; |
| 184 } |
| 185 UnicodeString rawPattern; |
| 186 if (!getString(pluralBundle.getAlias(), rawPattern, status)) { |
| 187 return; |
| 188 } |
| 189 if (!formatter.add( |
| 190 ures_getKey(pluralBundle.getAlias()), |
| 191 rawPattern, |
| 192 status)) { |
| 193 return; |
| 194 } |
| 195 } |
| 196 } |
| 197 |
| 198 static void initRelativeUnit( |
| 199 const UResourceBundle *resource, |
| 200 QuantityFormatter *relativeUnit, |
| 201 UErrorCode &status) { |
| 202 LocalUResourceBundlePointer topLevel( |
| 203 ures_getByKeyWithFallback( |
| 204 resource, "relativeTime", NULL, &status)); |
| 205 if (U_FAILURE(status)) { |
| 206 return; |
| 207 } |
| 208 LocalUResourceBundlePointer futureBundle(ures_getByKeyWithFallback( |
| 209 topLevel.getAlias(), "future", NULL, &status)); |
| 210 if (U_FAILURE(status)) { |
| 211 return; |
| 212 } |
| 213 initQuantityFormatter( |
| 214 futureBundle.getAlias(), |
| 215 relativeUnit[1], |
| 216 status); |
| 217 LocalUResourceBundlePointer pastBundle(ures_getByKeyWithFallback( |
| 218 topLevel.getAlias(), "past", NULL, &status)); |
| 219 if (U_FAILURE(status)) { |
| 220 return; |
| 221 } |
| 222 initQuantityFormatter( |
| 223 pastBundle.getAlias(), |
| 224 relativeUnit[0], |
| 225 status); |
| 226 } |
| 227 |
| 228 static void initRelativeUnit( |
| 229 const UResourceBundle *resource, |
| 230 const char *path, |
| 231 QuantityFormatter *relativeUnit, |
| 232 UErrorCode &status) { |
| 233 LocalUResourceBundlePointer topLevel( |
| 234 ures_getByKeyWithFallback(resource, path, NULL, &status)); |
| 235 if (U_FAILURE(status)) { |
| 236 return; |
| 237 } |
| 238 initRelativeUnit(topLevel.getAlias(), relativeUnit, status); |
| 239 } |
| 240 |
| 241 static void addTimeUnit( |
| 242 const UResourceBundle *resource, |
| 243 const char *path, |
| 244 QuantityFormatter *relativeUnit, |
| 245 UnicodeString *absoluteUnit, |
| 246 UErrorCode &status) { |
| 247 LocalUResourceBundlePointer topLevel( |
| 248 ures_getByKeyWithFallback(resource, path, NULL, &status)); |
| 249 if (U_FAILURE(status)) { |
| 250 return; |
| 251 } |
| 252 initRelativeUnit(topLevel.getAlias(), relativeUnit, status); |
| 253 UnicodeString unitName; |
| 254 if (!getStringWithFallback(topLevel.getAlias(), "dn", unitName, status)) { |
| 255 return; |
| 256 } |
| 257 // TODO(Travis Keep): This is a hack to get around CLDR bug 6818. |
| 258 const char *localeId = ures_getLocaleByType( |
| 259 topLevel.getAlias(), ULOC_ACTUAL_LOCALE, &status); |
| 260 if (U_FAILURE(status)) { |
| 261 return; |
| 262 } |
| 263 Locale locale(localeId); |
| 264 if (uprv_strcmp("en", locale.getLanguage()) == 0) { |
| 265 unitName.toLower(); |
| 266 } |
| 267 // end hack |
| 268 ures_getByKeyWithFallback( |
| 269 topLevel.getAlias(), "relative", topLevel.getAlias(), &status); |
| 270 if (U_FAILURE(status)) { |
| 271 return; |
| 272 } |
| 273 initAbsoluteUnit( |
| 274 topLevel.getAlias(), |
| 275 unitName, |
| 276 absoluteUnit, |
| 277 status); |
| 278 } |
| 279 |
| 280 static void readDaysOfWeek( |
| 281 const UResourceBundle *resource, |
| 282 const char *path, |
| 283 UnicodeString *daysOfWeek, |
| 284 UErrorCode &status) { |
| 285 LocalUResourceBundlePointer topLevel( |
| 286 ures_getByKeyWithFallback(resource, path, NULL, &status)); |
| 287 if (U_FAILURE(status)) { |
| 288 return; |
| 289 } |
| 290 int32_t size = ures_getSize(topLevel.getAlias()); |
| 291 if (size != 7) { |
| 292 status = U_INTERNAL_PROGRAM_ERROR; |
| 293 return; |
| 294 } |
| 295 for (int32_t i = 0; i < size; ++i) { |
| 296 if (!getStringByIndex(topLevel.getAlias(), i, daysOfWeek[i], status)) { |
| 297 return; |
| 298 } |
| 299 } |
| 300 } |
| 301 |
| 302 static void addWeekDay( |
| 303 const UResourceBundle *resource, |
| 304 const char *path, |
| 305 const UnicodeString *daysOfWeek, |
| 306 UDateAbsoluteUnit absoluteUnit, |
| 307 UnicodeString absoluteUnits[][UDAT_DIRECTION_COUNT], |
| 308 UErrorCode &status) { |
| 309 LocalUResourceBundlePointer topLevel( |
| 310 ures_getByKeyWithFallback(resource, path, NULL, &status)); |
| 311 if (U_FAILURE(status)) { |
| 312 return; |
| 313 } |
| 314 initAbsoluteUnit( |
| 315 topLevel.getAlias(), |
| 316 daysOfWeek[absoluteUnit - UDAT_ABSOLUTE_SUNDAY], |
| 317 absoluteUnits[absoluteUnit], |
| 318 status); |
| 319 } |
| 320 |
| 321 static void addTimeUnits( |
| 322 const UResourceBundle *resource, |
| 323 const char *path, const char *pathShort, const char *pathNarrow, |
| 324 UDateRelativeUnit relativeUnit, |
| 325 UDateAbsoluteUnit absoluteUnit, |
| 326 RelativeDateTimeCacheData &cacheData, |
| 327 UErrorCode &status) { |
| 328 addTimeUnit( |
| 329 resource, |
| 330 path, |
| 331 cacheData.relativeUnits[UDAT_STYLE_LONG][relativeUnit], |
| 332 cacheData.absoluteUnits[UDAT_STYLE_LONG][absoluteUnit], |
| 333 status); |
| 334 addTimeUnit( |
| 335 resource, |
| 336 pathShort, |
| 337 cacheData.relativeUnits[UDAT_STYLE_SHORT][relativeUnit], |
| 338 cacheData.absoluteUnits[UDAT_STYLE_SHORT][absoluteUnit], |
| 339 status); |
| 340 if (U_FAILURE(status)) { |
| 341 return; |
| 342 } |
| 343 addTimeUnit( |
| 344 resource, |
| 345 pathNarrow, |
| 346 cacheData.relativeUnits[UDAT_STYLE_NARROW][relativeUnit], |
| 347 cacheData.absoluteUnits[UDAT_STYLE_NARROW][absoluteUnit], |
| 348 status); |
| 349 if (status == U_MISSING_RESOURCE_ERROR) { |
| 350 // retry addTimeUnit for UDAT_STYLE_NARROW using pathShort |
| 351 status = U_ZERO_ERROR; |
| 352 addTimeUnit( |
| 353 resource, |
| 354 pathShort, |
| 355 cacheData.relativeUnits[UDAT_STYLE_NARROW][relativeUnit], |
| 356 cacheData.absoluteUnits[UDAT_STYLE_NARROW][absoluteUnit], |
| 357 status); |
| 358 } |
| 359 } |
| 360 |
| 361 static void initRelativeUnits( |
| 362 const UResourceBundle *resource, |
| 363 const char *path, const char *pathShort, const char *pathNarrow, |
| 364 UDateRelativeUnit relativeUnit, |
| 365 QuantityFormatter relativeUnits[][UDAT_RELATIVE_UNIT_COUNT][2], |
| 366 UErrorCode &status) { |
| 367 initRelativeUnit( |
| 368 resource, |
| 369 path, |
| 370 relativeUnits[UDAT_STYLE_LONG][relativeUnit], |
| 371 status); |
| 372 initRelativeUnit( |
| 373 resource, |
| 374 pathShort, |
| 375 relativeUnits[UDAT_STYLE_SHORT][relativeUnit], |
| 376 status); |
| 377 if (U_FAILURE(status)) { |
| 378 return; |
| 379 } |
| 380 initRelativeUnit( |
| 381 resource, |
| 382 pathNarrow, |
| 383 relativeUnits[UDAT_STYLE_NARROW][relativeUnit], |
| 384 status); |
| 385 if (status == U_MISSING_RESOURCE_ERROR) { |
| 386 // retry initRelativeUnit for UDAT_STYLE_NARROW using pathShort |
| 387 status = U_ZERO_ERROR; |
| 388 initRelativeUnit( |
| 389 resource, |
| 390 pathShort, |
| 391 relativeUnits[UDAT_STYLE_NARROW][relativeUnit], |
| 392 status); |
| 393 } |
| 394 } |
| 395 |
| 396 static void addWeekDays( |
| 397 const UResourceBundle *resource, |
| 398 const char *path, const char *pathShort, const char *pathNarrow, |
| 399 const UnicodeString daysOfWeek[][7], |
| 400 UDateAbsoluteUnit absoluteUnit, |
| 401 UnicodeString absoluteUnits[][UDAT_ABSOLUTE_UNIT_COUNT][UDAT_DIRECTION_C
OUNT], |
| 402 UErrorCode &status) { |
| 403 addWeekDay( |
| 404 resource, |
| 405 path, |
| 406 daysOfWeek[UDAT_STYLE_LONG], |
| 407 absoluteUnit, |
| 408 absoluteUnits[UDAT_STYLE_LONG], |
| 409 status); |
| 410 addWeekDay( |
| 411 resource, |
| 412 pathShort, |
| 413 daysOfWeek[UDAT_STYLE_SHORT], |
| 414 absoluteUnit, |
| 415 absoluteUnits[UDAT_STYLE_SHORT], |
| 416 status); |
| 417 if (U_FAILURE(status)) { |
| 418 return; |
| 419 } |
| 420 addWeekDay( |
| 421 resource, |
| 422 pathNarrow, |
| 423 daysOfWeek[UDAT_STYLE_NARROW], |
| 424 absoluteUnit, |
| 425 absoluteUnits[UDAT_STYLE_NARROW], |
| 426 status); |
| 427 if (status == U_MISSING_RESOURCE_ERROR) { |
| 428 // retry addWeekDay for UDAT_STYLE_NARROW using pathShort |
| 429 status = U_ZERO_ERROR; |
| 430 addWeekDay( |
| 431 resource, |
| 432 pathShort, |
| 433 daysOfWeek[UDAT_STYLE_NARROW], |
| 434 absoluteUnit, |
| 435 absoluteUnits[UDAT_STYLE_NARROW], |
| 436 status); |
| 437 } |
| 438 } |
| 439 |
| 440 static UBool loadUnitData( |
| 441 const UResourceBundle *resource, |
| 442 RelativeDateTimeCacheData &cacheData, |
| 443 UErrorCode &status) { |
| 444 addTimeUnits( |
| 445 resource, |
| 446 "fields/day", "fields/day-short", "fields/day-narrow", |
| 447 UDAT_RELATIVE_DAYS, |
| 448 UDAT_ABSOLUTE_DAY, |
| 449 cacheData, |
| 450 status); |
| 451 addTimeUnits( |
| 452 resource, |
| 453 "fields/week", "fields/week-short", "fields/week-narrow", |
| 454 UDAT_RELATIVE_WEEKS, |
| 455 UDAT_ABSOLUTE_WEEK, |
| 456 cacheData, |
| 457 status); |
| 458 addTimeUnits( |
| 459 resource, |
| 460 "fields/month", "fields/month-short", "fields/month-narrow", |
| 461 UDAT_RELATIVE_MONTHS, |
| 462 UDAT_ABSOLUTE_MONTH, |
| 463 cacheData, |
| 464 status); |
| 465 addTimeUnits( |
| 466 resource, |
| 467 "fields/year", "fields/year-short", "fields/year-narrow", |
| 468 UDAT_RELATIVE_YEARS, |
| 469 UDAT_ABSOLUTE_YEAR, |
| 470 cacheData, |
| 471 status); |
| 472 initRelativeUnits( |
| 473 resource, |
| 474 "fields/second", "fields/second-short", "fields/second-narrow", |
| 475 UDAT_RELATIVE_SECONDS, |
| 476 cacheData.relativeUnits, |
| 477 status); |
| 478 initRelativeUnits( |
| 479 resource, |
| 480 "fields/minute", "fields/minute-short", "fields/minute-narrow", |
| 481 UDAT_RELATIVE_MINUTES, |
| 482 cacheData.relativeUnits, |
| 483 status); |
| 484 initRelativeUnits( |
| 485 resource, |
| 486 "fields/hour", "fields/hour-short", "fields/hour-narrow", |
| 487 UDAT_RELATIVE_HOURS, |
| 488 cacheData.relativeUnits, |
| 489 status); |
| 490 getStringWithFallback( |
| 491 resource, |
| 492 "fields/second/relative/0", |
| 493 cacheData.absoluteUnits[UDAT_STYLE_LONG][UDAT_ABSOLUTE_NOW][UDAT_DIR
ECTION_PLAIN], |
| 494 status); |
| 495 getStringWithFallback( |
| 496 resource, |
| 497 "fields/second-short/relative/0", |
| 498 cacheData.absoluteUnits[UDAT_STYLE_SHORT][UDAT_ABSOLUTE_NOW][UDAT_DI
RECTION_PLAIN], |
| 499 status); |
| 500 getStringWithFallback( |
| 501 resource, |
| 502 "fields/second-narrow/relative/0", |
| 503 cacheData.absoluteUnits[UDAT_STYLE_NARROW][UDAT_ABSOLUTE_NOW][UDAT_D
IRECTION_PLAIN], |
| 504 status); |
| 505 UnicodeString daysOfWeek[UDAT_STYLE_COUNT][7]; |
| 506 readDaysOfWeek( |
| 507 resource, |
| 508 "calendar/gregorian/dayNames/stand-alone/wide", |
| 509 daysOfWeek[UDAT_STYLE_LONG], |
| 510 status); |
| 511 readDaysOfWeek( |
| 512 resource, |
| 513 "calendar/gregorian/dayNames/stand-alone/short", |
| 514 daysOfWeek[UDAT_STYLE_SHORT], |
| 515 status); |
| 516 readDaysOfWeek( |
| 517 resource, |
| 518 "calendar/gregorian/dayNames/stand-alone/narrow", |
| 519 daysOfWeek[UDAT_STYLE_NARROW], |
| 520 status); |
| 521 addWeekDays( |
| 522 resource, |
| 523 "fields/mon/relative", |
| 524 "fields/mon-short/relative", |
| 525 "fields/mon-narrow/relative", |
| 526 daysOfWeek, |
| 527 UDAT_ABSOLUTE_MONDAY, |
| 528 cacheData.absoluteUnits, |
| 529 status); |
| 530 addWeekDays( |
| 531 resource, |
| 532 "fields/tue/relative", |
| 533 "fields/tue-short/relative", |
| 534 "fields/tue-narrow/relative", |
| 535 daysOfWeek, |
| 536 UDAT_ABSOLUTE_TUESDAY, |
| 537 cacheData.absoluteUnits, |
| 538 status); |
| 539 addWeekDays( |
| 540 resource, |
| 541 "fields/wed/relative", |
| 542 "fields/wed-short/relative", |
| 543 "fields/wed-narrow/relative", |
| 544 daysOfWeek, |
| 545 UDAT_ABSOLUTE_WEDNESDAY, |
| 546 cacheData.absoluteUnits, |
| 547 status); |
| 548 addWeekDays( |
| 549 resource, |
| 550 "fields/thu/relative", |
| 551 "fields/thu-short/relative", |
| 552 "fields/thu-narrow/relative", |
| 553 daysOfWeek, |
| 554 UDAT_ABSOLUTE_THURSDAY, |
| 555 cacheData.absoluteUnits, |
| 556 status); |
| 557 addWeekDays( |
| 558 resource, |
| 559 "fields/fri/relative", |
| 560 "fields/fri-short/relative", |
| 561 "fields/fri-narrow/relative", |
| 562 daysOfWeek, |
| 563 UDAT_ABSOLUTE_FRIDAY, |
| 564 cacheData.absoluteUnits, |
| 565 status); |
| 566 addWeekDays( |
| 567 resource, |
| 568 "fields/sat/relative", |
| 569 "fields/sat-short/relative", |
| 570 "fields/sat-narrow/relative", |
| 571 daysOfWeek, |
| 572 UDAT_ABSOLUTE_SATURDAY, |
| 573 cacheData.absoluteUnits, |
| 574 status); |
| 575 addWeekDays( |
| 576 resource, |
| 577 "fields/sun/relative", |
| 578 "fields/sun-short/relative", |
| 579 "fields/sun-narrow/relative", |
| 580 daysOfWeek, |
| 581 UDAT_ABSOLUTE_SUNDAY, |
| 582 cacheData.absoluteUnits, |
| 583 status); |
| 584 return U_SUCCESS(status); |
| 585 } |
| 586 |
| 587 static UBool getDateTimePattern( |
| 588 const UResourceBundle *resource, |
| 589 UnicodeString &result, |
| 590 UErrorCode &status) { |
| 591 UnicodeString defaultCalendarName; |
| 592 if (!getStringWithFallback( |
| 593 resource, |
| 594 "calendar/default", |
| 595 defaultCalendarName, |
| 596 status)) { |
| 597 return FALSE; |
| 598 } |
| 599 CharString pathBuffer; |
| 600 pathBuffer.append("calendar/", status) |
| 601 .appendInvariantChars(defaultCalendarName, status) |
| 602 .append("/DateTimePatterns", status); |
| 603 LocalUResourceBundlePointer topLevel( |
| 604 ures_getByKeyWithFallback( |
| 605 resource, pathBuffer.data(), NULL, &status)); |
| 606 if (U_FAILURE(status)) { |
| 607 return FALSE; |
| 608 } |
| 609 int32_t size = ures_getSize(topLevel.getAlias()); |
| 610 if (size <= 8) { |
| 611 // Oops, size is to small to access the index that we want, fallback |
| 612 // to a hard-coded value. |
| 613 result = UNICODE_STRING_SIMPLE("{1} {0}"); |
| 614 return TRUE; |
| 615 } |
| 616 return getStringByIndex(topLevel.getAlias(), 8, result, status); |
| 617 } |
| 618 |
| 619 template<> U_I18N_API |
| 620 const RelativeDateTimeCacheData *LocaleCacheKey<RelativeDateTimeCacheData>::crea
teObject(const void * /*unused*/, UErrorCode &status) const { |
| 621 const char *localeId = fLoc.getName(); |
| 622 LocalUResourceBundlePointer topLevel(ures_open(NULL, localeId, &status)); |
| 623 if (U_FAILURE(status)) { |
| 624 return NULL; |
| 625 } |
| 626 LocalPointer<RelativeDateTimeCacheData> result( |
| 627 new RelativeDateTimeCacheData()); |
| 628 if (result.isNull()) { |
| 629 status = U_MEMORY_ALLOCATION_ERROR; |
| 630 return NULL; |
| 631 } |
| 632 if (!loadUnitData( |
| 633 topLevel.getAlias(), |
| 634 *result, |
| 635 status)) { |
| 636 return NULL; |
| 637 } |
| 638 UnicodeString dateTimePattern; |
| 639 if (!getDateTimePattern(topLevel.getAlias(), dateTimePattern, status)) { |
| 640 return NULL; |
| 641 } |
| 642 result->adoptCombinedDateAndTime( |
| 643 new MessageFormat(dateTimePattern, localeId, status)); |
| 644 if (U_FAILURE(status)) { |
| 645 return NULL; |
| 646 } |
| 647 result->addRef(); |
| 648 return result.orphan(); |
| 649 } |
| 650 |
| 651 RelativeDateTimeFormatter::RelativeDateTimeFormatter(UErrorCode& status) : |
| 652 fCache(NULL), |
| 653 fNumberFormat(NULL), |
| 654 fPluralRules(NULL), |
| 655 fStyle(UDAT_STYLE_LONG), |
| 656 fContext(UDISPCTX_CAPITALIZATION_NONE), |
| 657 fOptBreakIterator(NULL) { |
| 658 init(NULL, NULL, status); |
| 659 } |
| 660 |
| 661 RelativeDateTimeFormatter::RelativeDateTimeFormatter( |
| 662 const Locale& locale, UErrorCode& status) : |
| 663 fCache(NULL), |
| 664 fNumberFormat(NULL), |
| 665 fPluralRules(NULL), |
| 666 fStyle(UDAT_STYLE_LONG), |
| 667 fContext(UDISPCTX_CAPITALIZATION_NONE), |
| 668 fOptBreakIterator(NULL), |
| 669 fLocale(locale) { |
| 670 init(NULL, NULL, status); |
| 671 } |
| 672 |
| 673 RelativeDateTimeFormatter::RelativeDateTimeFormatter( |
| 674 const Locale& locale, NumberFormat *nfToAdopt, UErrorCode& status) : |
| 675 fCache(NULL), |
| 676 fNumberFormat(NULL), |
| 677 fPluralRules(NULL), |
| 678 fStyle(UDAT_STYLE_LONG), |
| 679 fContext(UDISPCTX_CAPITALIZATION_NONE), |
| 680 fOptBreakIterator(NULL), |
| 681 fLocale(locale) { |
| 682 init(nfToAdopt, NULL, status); |
| 683 } |
| 684 |
| 685 RelativeDateTimeFormatter::RelativeDateTimeFormatter( |
| 686 const Locale& locale, |
| 687 NumberFormat *nfToAdopt, |
| 688 UDateRelativeDateTimeFormatterStyle styl, |
| 689 UDisplayContext capitalizationContext, |
| 690 UErrorCode& status) : |
| 691 fCache(NULL), |
| 692 fNumberFormat(NULL), |
| 693 fPluralRules(NULL), |
| 694 fStyle(styl), |
| 695 fContext(capitalizationContext), |
| 696 fOptBreakIterator(NULL), |
| 697 fLocale(locale) { |
| 698 if (U_FAILURE(status)) { |
| 699 return; |
| 700 } |
| 701 if ((capitalizationContext >> 8) != UDISPCTX_TYPE_CAPITALIZATION) { |
| 702 status = U_ILLEGAL_ARGUMENT_ERROR; |
| 703 return; |
| 704 } |
| 705 if (capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTEN
CE) { |
| 706 BreakIterator *bi = BreakIterator::createSentenceInstance(locale, status
); |
| 707 if (U_FAILURE(status)) { |
| 708 return; |
| 709 } |
| 710 init(nfToAdopt, bi, status); |
| 711 } else { |
| 712 init(nfToAdopt, NULL, status); |
| 713 } |
| 714 } |
| 715 |
| 716 RelativeDateTimeFormatter::RelativeDateTimeFormatter( |
| 717 const RelativeDateTimeFormatter& other) |
| 718 : UObject(other), |
| 719 fCache(other.fCache), |
| 720 fNumberFormat(other.fNumberFormat), |
| 721 fPluralRules(other.fPluralRules), |
| 722 fStyle(other.fStyle), |
| 723 fContext(other.fContext), |
| 724 fOptBreakIterator(other.fOptBreakIterator), |
| 725 fLocale(other.fLocale) { |
| 726 fCache->addRef(); |
| 727 fNumberFormat->addRef(); |
| 728 fPluralRules->addRef(); |
| 729 if (fOptBreakIterator != NULL) { |
| 730 fOptBreakIterator->addRef(); |
| 731 } |
| 732 } |
| 733 |
| 734 RelativeDateTimeFormatter& RelativeDateTimeFormatter::operator=( |
| 735 const RelativeDateTimeFormatter& other) { |
| 736 if (this != &other) { |
| 737 SharedObject::copyPtr(other.fCache, fCache); |
| 738 SharedObject::copyPtr(other.fNumberFormat, fNumberFormat); |
| 739 SharedObject::copyPtr(other.fPluralRules, fPluralRules); |
| 740 SharedObject::copyPtr(other.fOptBreakIterator, fOptBreakIterator); |
| 741 fStyle = other.fStyle; |
| 742 fContext = other.fContext; |
| 743 fLocale = other.fLocale; |
| 744 } |
| 745 return *this; |
| 746 } |
| 747 |
| 748 RelativeDateTimeFormatter::~RelativeDateTimeFormatter() { |
| 749 if (fCache != NULL) { |
| 750 fCache->removeRef(); |
| 751 } |
| 752 if (fNumberFormat != NULL) { |
| 753 fNumberFormat->removeRef(); |
| 754 } |
| 755 if (fPluralRules != NULL) { |
| 756 fPluralRules->removeRef(); |
| 757 } |
| 758 if (fOptBreakIterator != NULL) { |
| 759 fOptBreakIterator->removeRef(); |
| 760 } |
| 761 } |
| 762 |
| 763 const NumberFormat& RelativeDateTimeFormatter::getNumberFormat() const { |
| 764 return **fNumberFormat; |
| 765 } |
| 766 |
| 767 UDisplayContext RelativeDateTimeFormatter::getCapitalizationContext() const { |
| 768 return fContext; |
| 769 } |
| 770 |
| 771 UDateRelativeDateTimeFormatterStyle RelativeDateTimeFormatter::getFormatStyle()
const { |
| 772 return fStyle; |
| 773 } |
| 774 |
| 775 UnicodeString& RelativeDateTimeFormatter::format( |
| 776 double quantity, UDateDirection direction, UDateRelativeUnit unit, |
| 777 UnicodeString& appendTo, UErrorCode& status) const { |
| 778 if (U_FAILURE(status)) { |
| 779 return appendTo; |
| 780 } |
| 781 if (direction != UDAT_DIRECTION_LAST && direction != UDAT_DIRECTION_NEXT) { |
| 782 status = U_ILLEGAL_ARGUMENT_ERROR; |
| 783 return appendTo; |
| 784 } |
| 785 int32_t bFuture = direction == UDAT_DIRECTION_NEXT ? 1 : 0; |
| 786 FieldPosition pos(FieldPosition::DONT_CARE); |
| 787 if (fOptBreakIterator == NULL) { |
| 788 return fCache->relativeUnits[fStyle][unit][bFuture].format( |
| 789 quantity, |
| 790 **fNumberFormat, |
| 791 **fPluralRules, |
| 792 appendTo, |
| 793 pos, |
| 794 status); |
| 795 } |
| 796 UnicodeString result; |
| 797 fCache->relativeUnits[fStyle][unit][bFuture].format( |
| 798 quantity, |
| 799 **fNumberFormat, |
| 800 **fPluralRules, |
| 801 result, |
| 802 pos, |
| 803 status); |
| 804 adjustForContext(result); |
| 805 return appendTo.append(result); |
| 806 } |
| 807 |
| 808 UnicodeString& RelativeDateTimeFormatter::format( |
| 809 UDateDirection direction, UDateAbsoluteUnit unit, |
| 810 UnicodeString& appendTo, UErrorCode& status) const { |
| 811 if (U_FAILURE(status)) { |
| 812 return appendTo; |
| 813 } |
| 814 if (unit == UDAT_ABSOLUTE_NOW && direction != UDAT_DIRECTION_PLAIN) { |
| 815 status = U_ILLEGAL_ARGUMENT_ERROR; |
| 816 return appendTo; |
| 817 } |
| 818 if (fOptBreakIterator == NULL) { |
| 819 return appendTo.append(fCache->absoluteUnits[fStyle][unit][direction]); |
| 820 } |
| 821 UnicodeString result(fCache->absoluteUnits[fStyle][unit][direction]); |
| 822 adjustForContext(result); |
| 823 return appendTo.append(result); |
| 824 } |
| 825 |
| 826 UnicodeString& RelativeDateTimeFormatter::combineDateAndTime( |
| 827 const UnicodeString& relativeDateString, const UnicodeString& timeString, |
| 828 UnicodeString& appendTo, UErrorCode& status) const { |
| 829 Formattable args[2] = {timeString, relativeDateString}; |
| 830 FieldPosition fpos(0); |
| 831 return fCache->getCombinedDateAndTime()->format( |
| 832 args, 2, appendTo, fpos, status); |
| 833 } |
| 834 |
| 835 void RelativeDateTimeFormatter::adjustForContext(UnicodeString &str) const { |
| 836 if (fOptBreakIterator == NULL |
| 837 || str.length() == 0 || !u_islower(str.char32At(0))) { |
| 838 return; |
| 839 } |
| 840 |
| 841 // Must guarantee that one thread at a time accesses the shared break |
| 842 // iterator. |
| 843 Mutex lock(&gBrkIterMutex); |
| 844 str.toTitle( |
| 845 fOptBreakIterator->get(), |
| 846 fLocale, |
| 847 U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT); |
| 848 } |
| 849 |
| 850 void RelativeDateTimeFormatter::init( |
| 851 NumberFormat *nfToAdopt, |
| 852 BreakIterator *biToAdopt, |
| 853 UErrorCode &status) { |
| 854 LocalPointer<NumberFormat> nf(nfToAdopt); |
| 855 LocalPointer<BreakIterator> bi(biToAdopt); |
| 856 UnifiedCache::getByLocale(fLocale, fCache, status); |
| 857 if (U_FAILURE(status)) { |
| 858 return; |
| 859 } |
| 860 const SharedPluralRules *pr = PluralRules::createSharedInstance( |
| 861 fLocale, UPLURAL_TYPE_CARDINAL, status); |
| 862 if (U_FAILURE(status)) { |
| 863 return; |
| 864 } |
| 865 SharedObject::copyPtr(pr, fPluralRules); |
| 866 pr->removeRef(); |
| 867 if (nf.isNull()) { |
| 868 const SharedNumberFormat *shared = NumberFormat::createSharedInstance( |
| 869 fLocale, UNUM_DECIMAL, status); |
| 870 if (U_FAILURE(status)) { |
| 871 return; |
| 872 } |
| 873 SharedObject::copyPtr(shared, fNumberFormat); |
| 874 shared->removeRef(); |
| 875 } else { |
| 876 SharedNumberFormat *shared = new SharedNumberFormat(nf.getAlias()); |
| 877 if (shared == NULL) { |
| 878 status = U_MEMORY_ALLOCATION_ERROR; |
| 879 return; |
| 880 } |
| 881 nf.orphan(); |
| 882 SharedObject::copyPtr(shared, fNumberFormat); |
| 883 } |
| 884 if (bi.isNull()) { |
| 885 SharedObject::clearPtr(fOptBreakIterator); |
| 886 } else { |
| 887 SharedBreakIterator *shared = new SharedBreakIterator(bi.getAlias()); |
| 888 if (shared == NULL) { |
| 889 status = U_MEMORY_ALLOCATION_ERROR; |
| 890 return; |
| 891 } |
| 892 bi.orphan(); |
| 893 SharedObject::copyPtr(shared, fOptBreakIterator); |
| 894 } |
| 895 } |
| 896 |
| 897 |
| 898 U_NAMESPACE_END |
| 899 |
| 900 #endif /* !UCONFIG_NO_FORMATTING */ |
| 901 |
OLD | NEW |