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