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