xref: /haiku/src/kits/locale/Locale.cpp (revision 2bd0cd6cb81083f3d070bc780644db8e63ff054d)
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 <Autolock.h>
9 #include <CalendarView.h>
10 #include <Catalog.h>
11 #include <Locale.h>
12 #include <LocaleRoster.h>
13 #include <MutableLocaleRoster.h>
14 #include <TimeZone.h>
15 
16 #include <unicode/datefmt.h>
17 #include <unicode/dcfmtsym.h>
18 #include <unicode/decimfmt.h>
19 #include <unicode/dtfmtsym.h>
20 #include <unicode/numfmt.h>
21 #include <unicode/smpdtfmt.h>
22 #include <unicode/ustring.h>
23 #include <ICUWrapper.h>
24 
25 #include <vector>
26 
27 
28 #define ICU_VERSION icu_44
29 
30 
31 using BPrivate::ObjectDeleter;
32 using BPrivate::B_WEEK_START_MONDAY;
33 using BPrivate::B_WEEK_START_SUNDAY;
34 
35 
36 static DateFormat* CreateDateFormat(bool longFormat, const Locale& locale,
37 						const BString& format);
38 static DateFormat* CreateTimeFormat(bool longFormat, const Locale& locale,
39 						const BString& format);
40 
41 
42 BLocale::BLocale(const char* languageAndCountryCode)
43 	:
44 	fCountry(languageAndCountryCode),
45 	fLanguage(languageAndCountryCode),
46 	fICULocale(new ICU_VERSION::Locale(languageAndCountryCode))
47 {
48 }
49 
50 
51 BLocale::BLocale(const BLocale& other)
52 	:
53 	fCountry(other.fCountry),
54 	fLanguage(other.fLanguage),
55 	fICULocale(new ICU_VERSION::Locale(*other.fICULocale)),
56 	fLongDateFormat(other.fLongDateFormat),
57 	fShortDateFormat(other.fShortDateFormat),
58 	fLongTimeFormat(other.fLongTimeFormat),
59 	fShortTimeFormat(other.fShortTimeFormat)
60 {
61 }
62 
63 
64 BLocale&
65 BLocale::operator=(const BLocale& other)
66 {
67 	if (this == &other)
68 		return *this;
69 
70 	*fICULocale = *other.fICULocale;
71 
72 	fLongDateFormat = other.fLongDateFormat;
73 	fShortDateFormat = other.fShortDateFormat;
74 	fLongTimeFormat = other.fLongTimeFormat;
75 	fShortTimeFormat = other.fShortTimeFormat;
76 
77 	fCountry = other.fCountry;
78 	fLanguage = other.fLanguage;
79 
80 	return *this;
81 }
82 
83 
84 BLocale::~BLocale()
85 {
86 	delete fICULocale;
87 }
88 
89 
90 status_t
91 BLocale::GetCollator(BCollator* collator) const
92 {
93 	if (!collator)
94 		return B_BAD_VALUE;
95 
96 	BAutolock lock(fLock);
97 	if (!lock.IsLocked())
98 		return B_ERROR;
99 
100 	*collator = fCollator;
101 
102 	return B_OK;
103 }
104 
105 
106 status_t
107 BLocale::GetLanguage(BLanguage* language) const
108 {
109 	if (!language)
110 		return B_BAD_VALUE;
111 
112 	BAutolock lock(fLock);
113 	if (!lock.IsLocked())
114 		return B_ERROR;
115 
116 	*language = fLanguage;
117 
118 	return B_OK;
119 }
120 
121 
122 status_t
123 BLocale::GetCountry(BCountry* country) const
124 {
125 	if (!country)
126 		return B_BAD_VALUE;
127 
128 	BAutolock lock(fLock);
129 	if (!lock.IsLocked())
130 		return B_ERROR;
131 
132 	*country = fCountry;
133 
134 	return B_OK;
135 }
136 
137 
138 const char *
139 BLocale::GetString(uint32 id) const
140 {
141 	// Note: this code assumes a certain order of the string bases
142 
143 	if (id >= B_OTHER_STRINGS_BASE) {
144 		if (id == B_CODESET)
145 			return "UTF-8";
146 
147 		return "";
148 	}
149 	return fLanguage.GetString(id);
150 }
151 
152 
153 void
154 BLocale::SetCountry(const BCountry& newCountry)
155 {
156 	fCountry = newCountry;
157 }
158 
159 
160 void
161 BLocale::SetCollator(const BCollator& newCollator)
162 {
163 	fCollator = newCollator;
164 }
165 
166 
167 void
168 BLocale::SetLanguage(const char* languageCode)
169 {
170 	fLanguage.SetTo(languageCode);
171 }
172 
173 
174 const char*
175 BLocale::Code() const
176 {
177 	return fICULocale->getName();
178 }
179 
180 
181 bool
182 BLocale::GetName(BString& name) const
183 {
184 	UnicodeString uString;
185 	fICULocale->getDisplayName(uString);
186 	BStringByteSink stringConverter(&name);
187 	uString.toUTF8(stringConverter);
188 	return true;
189 }
190 
191 // #pragma mark - Date
192 
193 
194 status_t
195 BLocale::FormatDate(char* string, size_t maxSize, time_t time,
196 	bool longFormat) const
197 {
198 	ObjectDeleter<DateFormat> dateFormatter = CreateDateFormat(longFormat,
199 		*fICULocale, longFormat ? fLongDateFormat : fShortDateFormat);
200 	if (dateFormatter.Get() == NULL)
201 		return B_NO_MEMORY;
202 
203 	UnicodeString ICUString;
204 	ICUString = dateFormatter->format((UDate)time * 1000, ICUString);
205 
206 	CheckedArrayByteSink stringConverter(string, maxSize);
207 
208 	ICUString.toUTF8(stringConverter);
209 
210 	if (stringConverter.Overflowed())
211 		return B_BAD_VALUE;
212 
213 	return B_OK;
214 }
215 
216 
217 status_t
218 BLocale::FormatDate(BString *string, time_t time, bool longFormat,
219 	const BTimeZone* timeZone) const
220 {
221 	string->Truncate(0);
222 		// We make the string empty, this way even in cases where ICU fail we at
223 		// least return something sane
224 	Locale locale(fLanguage.Code());
225 	ObjectDeleter<DateFormat> dateFormatter = CreateDateFormat(longFormat,
226 		locale, longFormat ? fLongDateFormat : fShortDateFormat);
227 	if (dateFormatter.Get() == NULL)
228 		return B_NO_MEMORY;
229 
230 	if (timeZone != NULL) {
231 		ObjectDeleter<TimeZone> icuTimeZone
232 			= TimeZone::createTimeZone(timeZone->ID().String());
233 		if (icuTimeZone.Get() == NULL)
234 			return B_NO_MEMORY;
235 		dateFormatter->setTimeZone(*icuTimeZone.Get());
236 	}
237 
238 	UnicodeString ICUString;
239 	ICUString = dateFormatter->format((UDate)time * 1000, ICUString);
240 
241 	BStringByteSink stringConverter(string);
242 	ICUString.toUTF8(stringConverter);
243 
244 	return B_OK;
245 }
246 
247 
248 status_t
249 BLocale::FormatDate(BString* string, int*& fieldPositions, int& fieldCount,
250 	time_t time, bool longFormat) const
251 {
252 	string->Truncate(0);
253 
254 	ObjectDeleter<DateFormat> dateFormatter = CreateDateFormat(longFormat,
255 		*fICULocale, longFormat ? fLongDateFormat : fShortDateFormat);
256 	if (dateFormatter.Get() == NULL)
257 		return B_NO_MEMORY;
258 
259 	fieldPositions = NULL;
260 	UErrorCode error = U_ZERO_ERROR;
261 	ICU_VERSION::FieldPositionIterator positionIterator;
262 	UnicodeString ICUString;
263 	ICUString = dateFormatter->format((UDate)time * 1000, ICUString,
264 		&positionIterator, error);
265 
266 	if (error != U_ZERO_ERROR)
267 		return B_ERROR;
268 
269 	ICU_VERSION::FieldPosition field;
270 	std::vector<int> fieldPosStorage;
271 	fieldCount  = 0;
272 	while (positionIterator.next(field)) {
273 		fieldPosStorage.push_back(field.getBeginIndex());
274 		fieldPosStorage.push_back(field.getEndIndex());
275 		fieldCount += 2;
276 	}
277 
278 	fieldPositions = (int*) malloc(fieldCount * sizeof(int));
279 
280 	for (int i = 0 ; i < fieldCount ; i++ )
281 		fieldPositions[i] = fieldPosStorage[i];
282 
283 	BStringByteSink stringConverter(string);
284 
285 	ICUString.toUTF8(stringConverter);
286 
287 	return B_OK;
288 }
289 
290 
291 status_t
292 BLocale::GetDateFormat(BString& format, bool longFormat) const
293 {
294 	if (longFormat && fLongDateFormat.Length() > 0)
295 		format = fLongDateFormat;
296 	else if (!longFormat && fShortDateFormat.Length() > 0)
297 		format = fShortDateFormat;
298 	else {
299 		format.Truncate(0);
300 
301 		ObjectDeleter<DateFormat> dateFormatter = CreateDateFormat(longFormat,
302 			*fICULocale, longFormat ? fLongDateFormat : fShortDateFormat);
303 		if (dateFormatter.Get() == NULL)
304 			return B_NO_MEMORY;
305 
306 		SimpleDateFormat* dateFormatterImpl
307 			= static_cast<SimpleDateFormat*>(dateFormatter.Get());
308 
309 		UnicodeString ICUString;
310 		ICUString = dateFormatterImpl->toPattern(ICUString);
311 
312 		BStringByteSink stringConverter(&format);
313 
314 		ICUString.toUTF8(stringConverter);
315 	}
316 
317 	return B_OK;
318 }
319 
320 
321 status_t
322 BLocale::SetDateFormat(const char* formatString, bool longFormat)
323 {
324 	if (longFormat)
325 		fLongDateFormat = formatString;
326 	else
327 		fShortDateFormat = formatString;
328 
329 	return B_OK;
330 }
331 
332 
333 status_t
334 BLocale::GetDateFields(BDateElement*& fields, int& fieldCount,
335 	bool longFormat) const
336 {
337 	ObjectDeleter<DateFormat> dateFormatter = CreateDateFormat(longFormat,
338 		*fICULocale, longFormat ? fLongDateFormat : fShortDateFormat);
339 	if (dateFormatter.Get() == NULL)
340 		return B_NO_MEMORY;
341 
342 	fields = NULL;
343 	UErrorCode error = U_ZERO_ERROR;
344 	ICU_VERSION::FieldPositionIterator positionIterator;
345 	UnicodeString ICUString;
346 	time_t now;
347 	ICUString = dateFormatter->format((UDate)time(&now) * 1000, ICUString,
348 		&positionIterator, error);
349 
350 	if (U_FAILURE(error))
351 		return B_ERROR;
352 
353 	ICU_VERSION::FieldPosition field;
354 	std::vector<int> fieldPosStorage;
355 	fieldCount  = 0;
356 	while (positionIterator.next(field)) {
357 		fieldPosStorage.push_back(field.getField());
358 		fieldCount ++;
359 	}
360 
361 	fields = (BDateElement*) malloc(fieldCount * sizeof(BDateElement));
362 
363 	for (int i = 0 ; i < fieldCount ; i++ ) {
364 		switch (fieldPosStorage[i]) {
365 			case UDAT_YEAR_FIELD:
366 				fields[i] = B_DATE_ELEMENT_YEAR;
367 				break;
368 			case UDAT_MONTH_FIELD:
369 				fields[i] = B_DATE_ELEMENT_MONTH;
370 				break;
371 			case UDAT_DATE_FIELD:
372 				fields[i] = B_DATE_ELEMENT_DAY;
373 				break;
374 			default:
375 				fields[i] = B_DATE_ELEMENT_INVALID;
376 				break;
377 		}
378 	}
379 
380 	return B_OK;
381 }
382 
383 
384 int
385 BLocale::StartOfWeek() const
386 {
387 	UErrorCode err = U_ZERO_ERROR;
388 	Calendar* c = Calendar::createInstance(*fICULocale, err);
389 
390 	if (err == U_ZERO_ERROR && c->getFirstDayOfWeek(err) == UCAL_SUNDAY) {
391 		delete c;
392 		return B_WEEK_START_SUNDAY;
393 	} else {
394 		delete c;
395 		// Might be another day, but BeAPI will not handle it
396 		return B_WEEK_START_MONDAY;
397 	}
398 }
399 
400 
401 status_t
402 BLocale::FormatDateTime(char* target, size_t maxSize, time_t time,
403 	bool longFormat) const
404 {
405 	ObjectDeleter<DateFormat> dateFormatter = CreateDateFormat(longFormat,
406 		*fICULocale, longFormat ? fLongDateFormat : fShortDateFormat);
407 	if (dateFormatter.Get() == NULL)
408 		return B_NO_MEMORY;
409 
410 	ObjectDeleter<DateFormat> timeFormatter = CreateTimeFormat(longFormat,
411 		*fICULocale, longFormat ? fLongTimeFormat : fShortTimeFormat);
412 	if (timeFormatter.Get() == NULL)
413 		return B_NO_MEMORY;
414 
415 	UnicodeString ICUString;
416 	ICUString = dateFormatter->format((UDate)time * 1000, ICUString);
417 
418 	ICUString.append(UnicodeString::fromUTF8(", "));
419 
420 	ICUString = timeFormatter->format((UDate)time * 1000, ICUString);
421 
422 	CheckedArrayByteSink stringConverter(target, maxSize);
423 	ICUString.toUTF8(stringConverter);
424 
425 	if (stringConverter.Overflowed())
426 		return B_BAD_VALUE;
427 
428 	return B_OK;
429 }
430 
431 
432 status_t
433 BLocale::FormatDateTime(BString* target, time_t time, bool longFormat,
434 	const BTimeZone* timeZone) const
435 {
436 	ObjectDeleter<DateFormat> dateFormatter = CreateDateFormat(longFormat,
437 		*fICULocale, longFormat ? fLongDateFormat : fShortDateFormat);
438 	if (dateFormatter.Get() == NULL)
439 		return B_NO_MEMORY;
440 
441 	ObjectDeleter<DateFormat> timeFormatter = CreateTimeFormat(longFormat,
442 		*fICULocale, longFormat ? fLongTimeFormat : fShortTimeFormat);
443 	if (timeFormatter.Get() == NULL)
444 		return B_NO_MEMORY;
445 
446 	if (timeZone != NULL) {
447 		ObjectDeleter<TimeZone> icuTimeZone
448 			= TimeZone::createTimeZone(timeZone->ID().String());
449 		if (icuTimeZone.Get() == NULL)
450 			return B_NO_MEMORY;
451 		timeFormatter->setTimeZone(*icuTimeZone.Get());
452 	}
453 
454 	UnicodeString ICUString;
455 	ICUString = dateFormatter->format((UDate)time * 1000, ICUString);
456 
457 	ICUString.append(UnicodeString::fromUTF8(", "));
458 
459 	ICUString = timeFormatter->format((UDate)time * 1000, ICUString);
460 
461 	BStringByteSink stringConverter(target);
462 	ICUString.toUTF8(stringConverter);
463 
464 	return B_OK;
465 }
466 
467 
468 // #pragma mark - Time
469 
470 
471 status_t
472 BLocale::FormatTime(char* string, size_t maxSize, time_t time,
473 	bool longFormat) const
474 {
475 	ObjectDeleter<DateFormat> timeFormatter = CreateTimeFormat(longFormat,
476 		*fICULocale, longFormat ? fLongTimeFormat : fShortTimeFormat);
477 	if (timeFormatter.Get() == NULL)
478 		return B_NO_MEMORY;
479 
480 	UnicodeString ICUString;
481 	ICUString = timeFormatter->format((UDate)time * 1000, ICUString);
482 
483 	CheckedArrayByteSink stringConverter(string, maxSize);
484 
485 	ICUString.toUTF8(stringConverter);
486 
487 	if (stringConverter.Overflowed())
488 		return B_BAD_VALUE;
489 
490 	return B_OK;
491 }
492 
493 
494 status_t
495 BLocale::FormatTime(BString* string, time_t time, bool longFormat,
496 	const BTimeZone* timeZone) const
497 {
498 	string->Truncate(0);
499 
500 	ObjectDeleter<DateFormat> timeFormatter = CreateTimeFormat(longFormat,
501 		*fICULocale, longFormat ? fLongTimeFormat : fShortTimeFormat);
502 	if (timeFormatter.Get() == NULL)
503 		return B_NO_MEMORY;
504 
505 	if (timeZone != NULL) {
506 		ObjectDeleter<TimeZone> icuTimeZone
507 			= TimeZone::createTimeZone(timeZone->ID().String());
508 		if (icuTimeZone.Get() == NULL)
509 			return B_NO_MEMORY;
510 		timeFormatter->setTimeZone(*icuTimeZone.Get());
511 	}
512 
513 	UnicodeString ICUString;
514 	ICUString = timeFormatter->format((UDate)time * 1000, ICUString);
515 
516 	BStringByteSink stringConverter(string);
517 
518 	ICUString.toUTF8(stringConverter);
519 
520 	return B_OK;
521 }
522 
523 
524 status_t
525 BLocale::FormatTime(BString* string, int*& fieldPositions, int& fieldCount,
526 	time_t time, bool longFormat) const
527 {
528 	string->Truncate(0);
529 
530 	ObjectDeleter<DateFormat> timeFormatter = CreateTimeFormat(longFormat,
531 		*fICULocale, longFormat ? fLongTimeFormat : fShortTimeFormat);
532 	if (timeFormatter.Get() == NULL)
533 		return B_NO_MEMORY;
534 
535 	fieldPositions = NULL;
536 	UErrorCode error = U_ZERO_ERROR;
537 	ICU_VERSION::FieldPositionIterator positionIterator;
538 	UnicodeString ICUString;
539 	ICUString = timeFormatter->format((UDate)time * 1000, ICUString,
540 		&positionIterator, error);
541 
542 	if (error != U_ZERO_ERROR)
543 		return B_ERROR;
544 
545 	ICU_VERSION::FieldPosition field;
546 	std::vector<int> fieldPosStorage;
547 	fieldCount  = 0;
548 	while (positionIterator.next(field)) {
549 		fieldPosStorage.push_back(field.getBeginIndex());
550 		fieldPosStorage.push_back(field.getEndIndex());
551 		fieldCount += 2;
552 	}
553 
554 	fieldPositions = (int*) malloc(fieldCount * sizeof(int));
555 
556 	for (int i = 0 ; i < fieldCount ; i++ )
557 		fieldPositions[i] = fieldPosStorage[i];
558 
559 	BStringByteSink stringConverter(string);
560 
561 	ICUString.toUTF8(stringConverter);
562 
563 	return B_OK;
564 }
565 
566 
567 status_t
568 BLocale::GetTimeFields(BDateElement*& fields, int& fieldCount,
569 	bool longFormat) const
570 {
571 	ObjectDeleter<DateFormat> timeFormatter = CreateTimeFormat(longFormat,
572 		*fICULocale, longFormat ? fLongTimeFormat : fShortTimeFormat);
573 	if (timeFormatter.Get() == NULL)
574 		return B_NO_MEMORY;
575 
576 	fields = NULL;
577 	UErrorCode error = U_ZERO_ERROR;
578 	ICU_VERSION::FieldPositionIterator positionIterator;
579 	UnicodeString ICUString;
580 	time_t now;
581 	ICUString = timeFormatter->format((UDate)time(&now) * 1000,	ICUString,
582 		&positionIterator, error);
583 
584 	if (error != U_ZERO_ERROR)
585 		return B_ERROR;
586 
587 	ICU_VERSION::FieldPosition field;
588 	std::vector<int> fieldPosStorage;
589 	fieldCount  = 0;
590 	while (positionIterator.next(field)) {
591 		fieldPosStorage.push_back(field.getField());
592 		fieldCount ++;
593 	}
594 
595 	fields = (BDateElement*) malloc(fieldCount * sizeof(BDateElement));
596 
597 	for (int i = 0 ; i < fieldCount ; i++ ) {
598 		switch (fieldPosStorage[i]) {
599 			case UDAT_HOUR_OF_DAY1_FIELD:
600 			case UDAT_HOUR_OF_DAY0_FIELD:
601 			case UDAT_HOUR1_FIELD:
602 			case UDAT_HOUR0_FIELD:
603 				fields[i] = B_DATE_ELEMENT_HOUR;
604 				break;
605 			case UDAT_MINUTE_FIELD:
606 				fields[i] = B_DATE_ELEMENT_MINUTE;
607 				break;
608 			case UDAT_SECOND_FIELD:
609 				fields[i] = B_DATE_ELEMENT_SECOND;
610 				break;
611 			case UDAT_AM_PM_FIELD:
612 				fields[i] = B_DATE_ELEMENT_AM_PM;
613 				break;
614 			default:
615 				fields[i] = B_DATE_ELEMENT_INVALID;
616 				break;
617 		}
618 	}
619 
620 	return B_OK;
621 }
622 
623 
624 status_t
625 BLocale::SetTimeFormat(const char* formatString, bool longFormat)
626 {
627 	if (longFormat)
628 		fLongTimeFormat = formatString;
629 	else
630 		fShortTimeFormat = formatString;
631 
632 	return B_OK;
633 }
634 
635 
636 status_t
637 BLocale::GetTimeFormat(BString& format, bool longFormat) const
638 {
639 	if (longFormat && fLongTimeFormat.Length() > 0)
640 		format = fLongTimeFormat;
641 	else if (!longFormat && fShortTimeFormat.Length() > 0)
642 		format = fShortTimeFormat;
643 	else {
644 		format.Truncate(0);
645 
646 		ObjectDeleter<DateFormat> timeFormatter = CreateTimeFormat(longFormat,
647 			*fICULocale, longFormat ? fLongTimeFormat : fShortTimeFormat);
648 		if (timeFormatter.Get() == NULL)
649 			return B_NO_MEMORY;
650 
651 		SimpleDateFormat* timeFormatterImpl
652 			= static_cast<SimpleDateFormat*>(timeFormatter.Get());
653 
654 		UnicodeString ICUString;
655 		ICUString = timeFormatterImpl->toPattern(ICUString);
656 
657 		BStringByteSink stringConverter(&format);
658 		ICUString.toUTF8(stringConverter);
659 	}
660 
661 	return B_OK;
662 }
663 
664 
665 // #pragma mark - Numbers
666 
667 
668 status_t
669 BLocale::FormatNumber(char* string, size_t maxSize, double value) const
670 {
671 	BString fullString;
672 	status_t status = FormatNumber(&fullString, value);
673 	if (status == B_OK)
674 		strlcpy(string, fullString.String(), maxSize);
675 
676 	return status;
677 }
678 
679 
680 status_t
681 BLocale::FormatNumber(BString* string, double value) const
682 {
683 	UErrorCode err = U_ZERO_ERROR;
684 	ObjectDeleter<NumberFormat> numberFormatter	= NumberFormat::createInstance(
685 		*fICULocale, NumberFormat::kNumberStyle, err);
686 
687 	if (numberFormatter.Get() == NULL)
688 		return B_NO_MEMORY;
689 	if (U_FAILURE(err))
690 		return B_ERROR;
691 
692 	UnicodeString ICUString;
693 	ICUString = numberFormatter->format(value, ICUString);
694 
695 	string->Truncate(0);
696 	BStringByteSink stringConverter(string);
697 	ICUString.toUTF8(stringConverter);
698 
699 	return B_OK;
700 }
701 
702 
703 status_t
704 BLocale::FormatNumber(char* string, size_t maxSize, int32 value) const
705 {
706 	BString fullString;
707 	status_t status = FormatNumber(&fullString, value);
708 	if (status == B_OK)
709 		strlcpy(string, fullString.String(), maxSize);
710 
711 	return status;
712 }
713 
714 
715 status_t
716 BLocale::FormatNumber(BString* string, int32 value) const
717 {
718 	UErrorCode err = U_ZERO_ERROR;
719 	ObjectDeleter<NumberFormat> numberFormatter	= NumberFormat::createInstance(
720 		*fICULocale, NumberFormat::kNumberStyle, err);
721 
722 	if (numberFormatter.Get() == NULL)
723 		return B_NO_MEMORY;
724 	if (U_FAILURE(err))
725 		return B_ERROR;
726 
727 	UnicodeString ICUString;
728 	ICUString = numberFormatter->format((int32_t)value, ICUString);
729 
730 	string->Truncate(0);
731 	BStringByteSink stringConverter(string);
732 	ICUString.toUTF8(stringConverter);
733 
734 	return B_OK;
735 }
736 
737 
738 ssize_t
739 BLocale::FormatMonetary(char* string, size_t maxSize, double value) const
740 {
741 	BString fullString;
742 	ssize_t written = FormatMonetary(&fullString, value);
743 	if (written < 0)
744 		return written;
745 
746 	return strlcpy(string, fullString.String(), maxSize);
747 }
748 
749 
750 ssize_t
751 BLocale::FormatMonetary(BString* string, double value) const
752 {
753 	if (string == NULL)
754 		return B_BAD_VALUE;
755 
756 	UErrorCode err;
757 	ObjectDeleter<NumberFormat> numberFormatter
758 		= NumberFormat::createCurrencyInstance(*fICULocale, err);
759 
760 	if (numberFormatter.Get() == NULL)
761 		return B_NO_MEMORY;
762 	if (U_FAILURE(err))
763 		return B_ERROR;
764 
765 	UnicodeString ICUString;
766 	ICUString = numberFormatter->format(value, ICUString);
767 
768 	string->Truncate(0);
769 	BStringByteSink stringConverter(string);
770 	ICUString.toUTF8(stringConverter);
771 
772 	return string->Length();
773 }
774 
775 
776 status_t
777 BLocale::FormatMonetary(BString* string, int*& fieldPositions,
778 	BNumberElement*& fieldTypes, int& fieldCount, double value) const
779 {
780 	UErrorCode err = U_ZERO_ERROR;
781 	ObjectDeleter<NumberFormat> numberFormatter
782 		= NumberFormat::createCurrencyInstance(*fICULocale, err);
783 	if (U_FAILURE(err))
784 		return B_NO_MEMORY;
785 
786 	string->Truncate(0);
787 
788 	fieldPositions = NULL;
789 	fieldTypes = NULL;
790 	ICU_VERSION::FieldPositionIterator positionIterator;
791 	UnicodeString ICUString;
792 	ICUString = numberFormatter->format(value, ICUString, &positionIterator,
793 		err);
794 
795 	if (err != U_ZERO_ERROR)
796 		return B_ERROR;
797 
798 	ICU_VERSION::FieldPosition field;
799 	std::vector<int> fieldPosStorage;
800 	std::vector<int> fieldTypeStorage;
801 	fieldCount  = 0;
802 	while (positionIterator.next(field)) {
803 		fieldTypeStorage.push_back(field.getField());
804 		fieldPosStorage.push_back(field.getBeginIndex() | (field.getEndIndex() << 16));
805 		fieldCount ++;
806 
807 	}
808 
809 	fieldPositions = (int*) malloc(fieldCount * sizeof(int));
810 	fieldTypes = (BNumberElement*) malloc(fieldCount * sizeof(BNumberElement));
811 
812 	for (int i = 0 ; i < fieldCount ; i++ ) {
813 		fieldPositions[i] = fieldPosStorage[i];
814 		switch (fieldTypeStorage[i]) {
815 			case NumberFormat::kCurrencyField:
816 				fieldTypes[i] = B_NUMBER_ELEMENT_CURRENCY;
817 				break;
818 			case NumberFormat::kIntegerField:
819 				fieldTypes[i] = B_NUMBER_ELEMENT_INTEGER;
820 				break;
821 			case NumberFormat::kFractionField:
822 				fieldTypes[i] = B_NUMBER_ELEMENT_FRACTIONAL;
823 				break;
824 			default:
825 				fieldTypes[i] = B_NUMBER_ELEMENT_INVALID;
826 				break;
827 		}
828 	}
829 
830 	BStringByteSink stringConverter(string);
831 
832 	ICUString.toUTF8(stringConverter);
833 
834 	return B_OK;
835 }
836 
837 
838 status_t
839 BLocale::GetCurrencySymbol(BString& result) const
840 {
841 	UErrorCode error = U_ZERO_ERROR;
842 	NumberFormat* format = NumberFormat::createCurrencyInstance(*fICULocale,
843 		error);
844 
845 	if (U_FAILURE(error))
846 		return B_ERROR;
847 
848 	char* symbol = (char*)malloc(20);
849 	u_strToUTF8(symbol, 20, NULL, format->getCurrency(), -1, &error);
850 	if (U_FAILURE(error))
851 		return B_BAD_DATA;
852 	result.Append(symbol);
853 	delete format;
854 	delete symbol;
855 	return B_OK;
856 }
857 
858 
859 // #pragma mark - Helpers
860 
861 
862 static DateFormat*
863 CreateDateFormat(bool longFormat, const Locale& locale,
864 	const BString& format)
865 {
866 	DateFormat* dateFormatter = DateFormat::createDateInstance(
867 		longFormat ? DateFormat::FULL : DateFormat::SHORT, locale);
868 
869 	if (format.Length() > 0) {
870 		SimpleDateFormat* dateFormatterImpl
871 			= static_cast<SimpleDateFormat*>(dateFormatter);
872 
873 		UnicodeString pattern(format.String());
874 		dateFormatterImpl->applyPattern(pattern);
875 	}
876 
877 	return dateFormatter;
878 }
879 
880 
881 static DateFormat*
882 CreateTimeFormat(bool longFormat, const Locale& locale,
883 	const BString& format)
884 {
885 	DateFormat* timeFormatter = DateFormat::createTimeInstance(
886 		longFormat ? DateFormat::MEDIUM : DateFormat::SHORT, locale);
887 
888 	if (format.Length() > 0) {
889 		SimpleDateFormat* timeFormatterImpl
890 			= static_cast<SimpleDateFormat*>(timeFormatter);
891 
892 		UnicodeString pattern(format.String());
893 		timeFormatterImpl->applyPattern(pattern);
894 	}
895 
896 	return timeFormatter;
897 }
898