xref: /haiku/src/kits/locale/Locale.cpp (revision f8da8f3477d3c18142e59d17d05a545982faa5a8)
1 /*
2  * Copyright 2003, Axel Dörfler, axeld@pinc-software.de.
3  * Copyright 2010-2011, Oliver Tappe, zooey@hirschkaefer.de.
4  * Copyright 2012, John Scipione, jscipione@gmail.com
5  * All rights reserved. Distributed under the terms of the OpenBeOS License.
6  */
7 
8 
9 #include <AutoDeleter.h>
10 #include <Autolock.h>
11 #include <CalendarView.h>
12 #include <Catalog.h>
13 #include <FormattingConventionsPrivate.h>
14 #include <LanguagePrivate.h>
15 #include <Locale.h>
16 #include <LocaleRoster.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 BLocaleRoster::Default()->GetDefaultLocale();
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 ssize_t
513 BLocale::FormatTime(char* string, size_t maxSize, time_t time,
514 	BString format) const
515 {
516 	BAutolock lock(fLock);
517 	if (!lock.IsLocked())
518 		return B_ERROR;
519 
520 	if (format == NULL || format.CountChars() <= 0)
521 		return B_BAD_VALUE;
522 
523 	ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format));
524 	if (timeFormatter.Get() == NULL)
525 		return B_NO_MEMORY;
526 
527 	UnicodeString icuString;
528 	timeFormatter->format((UDate)time * 1000, icuString);
529 
530 	CheckedArrayByteSink stringConverter(string, maxSize);
531 	icuString.toUTF8(stringConverter);
532 
533 	if (stringConverter.Overflowed())
534 		return B_BAD_VALUE;
535 
536 	return stringConverter.NumberOfBytesWritten();
537 }
538 
539 
540 status_t
541 BLocale::FormatTime(BString* string, time_t time, BTimeFormatStyle style,
542 	const BTimeZone* timeZone) const
543 {
544 	BAutolock lock(fLock);
545 	if (!lock.IsLocked())
546 		return B_ERROR;
547 
548 	BString format;
549 	fConventions.GetTimeFormat(style, format);
550 	ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format));
551 	if (timeFormatter.Get() == NULL)
552 		return B_NO_MEMORY;
553 
554 	if (timeZone != NULL) {
555 		ObjectDeleter<TimeZone> icuTimeZone(
556 			TimeZone::createTimeZone(timeZone->ID().String()));
557 		if (icuTimeZone.Get() == NULL)
558 			return B_NO_MEMORY;
559 		timeFormatter->setTimeZone(*icuTimeZone.Get());
560 	}
561 
562 	UnicodeString icuString;
563 	timeFormatter->format((UDate)time * 1000, icuString);
564 
565 	string->Truncate(0);
566 	BStringByteSink stringConverter(string);
567 	icuString.toUTF8(stringConverter);
568 
569 	return B_OK;
570 }
571 
572 
573 status_t
574 BLocale::FormatTime(BString* string, time_t time, BString format,
575 	const BTimeZone* timeZone) const
576 {
577 	BAutolock lock(fLock);
578 	if (!lock.IsLocked())
579 		return B_ERROR;
580 
581 	if (format == NULL || format.CountChars() <= 0)
582 		return B_BAD_VALUE;
583 
584 	ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format));
585 	if (timeFormatter.Get() == NULL)
586 		return B_NO_MEMORY;
587 
588 	if (timeZone != NULL) {
589 		ObjectDeleter<TimeZone> icuTimeZone(
590 			TimeZone::createTimeZone(timeZone->ID().String()));
591 		if (icuTimeZone.Get() == NULL)
592 			return B_NO_MEMORY;
593 		timeFormatter->setTimeZone(*icuTimeZone.Get());
594 	}
595 
596 	UnicodeString icuString;
597 	timeFormatter->format((UDate)time * 1000, icuString);
598 
599 	string->Truncate(0);
600 	BStringByteSink stringConverter(string);
601 	icuString.toUTF8(stringConverter);
602 
603 	return B_OK;
604 }
605 
606 
607 status_t
608 BLocale::FormatTime(BString* string, int*& fieldPositions, int& fieldCount,
609 	time_t time, BTimeFormatStyle style) const
610 {
611 	BAutolock lock(fLock);
612 	if (!lock.IsLocked())
613 		return B_ERROR;
614 
615 	BString format;
616 	fConventions.GetTimeFormat(style, format);
617 	ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format));
618 	if (timeFormatter.Get() == NULL)
619 		return B_NO_MEMORY;
620 
621 	fieldPositions = NULL;
622 	UErrorCode error = U_ZERO_ERROR;
623 	icu::FieldPositionIterator positionIterator;
624 	UnicodeString icuString;
625 	timeFormatter->format((UDate)time * 1000, icuString, &positionIterator,
626 		error);
627 
628 	if (error != U_ZERO_ERROR)
629 		return B_BAD_VALUE;
630 
631 	icu::FieldPosition field;
632 	std::vector<int> fieldPosStorage;
633 	fieldCount  = 0;
634 	while (positionIterator.next(field)) {
635 		fieldPosStorage.push_back(field.getBeginIndex());
636 		fieldPosStorage.push_back(field.getEndIndex());
637 		fieldCount += 2;
638 	}
639 
640 	fieldPositions = (int*) malloc(fieldCount * sizeof(int));
641 
642 	for (int i = 0 ; i < fieldCount ; i++ )
643 		fieldPositions[i] = fieldPosStorage[i];
644 
645 	string->Truncate(0);
646 	BStringByteSink stringConverter(string);
647 	icuString.toUTF8(stringConverter);
648 
649 	return B_OK;
650 }
651 
652 
653 status_t
654 BLocale::GetTimeFields(BDateElement*& fields, int& fieldCount,
655 	BTimeFormatStyle style) const
656 {
657 	BAutolock lock(fLock);
658 	if (!lock.IsLocked())
659 		return B_ERROR;
660 
661 	BString format;
662 	fConventions.GetTimeFormat(style, format);
663 	ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format));
664 	if (timeFormatter.Get() == NULL)
665 		return B_NO_MEMORY;
666 
667 	fields = NULL;
668 	UErrorCode error = U_ZERO_ERROR;
669 	icu::FieldPositionIterator positionIterator;
670 	UnicodeString icuString;
671 	time_t now;
672 	timeFormatter->format((UDate)time(&now) * 1000, icuString,
673 		&positionIterator, error);
674 
675 	if (error != U_ZERO_ERROR)
676 		return B_BAD_VALUE;
677 
678 	icu::FieldPosition field;
679 	std::vector<int> fieldPosStorage;
680 	fieldCount  = 0;
681 	while (positionIterator.next(field)) {
682 		fieldPosStorage.push_back(field.getField());
683 		fieldCount ++;
684 	}
685 
686 	fields = (BDateElement*) malloc(fieldCount * sizeof(BDateElement));
687 
688 	for (int i = 0 ; i < fieldCount ; i++ ) {
689 		switch (fieldPosStorage[i]) {
690 			case UDAT_HOUR_OF_DAY1_FIELD:
691 			case UDAT_HOUR_OF_DAY0_FIELD:
692 			case UDAT_HOUR1_FIELD:
693 			case UDAT_HOUR0_FIELD:
694 				fields[i] = B_DATE_ELEMENT_HOUR;
695 				break;
696 			case UDAT_MINUTE_FIELD:
697 				fields[i] = B_DATE_ELEMENT_MINUTE;
698 				break;
699 			case UDAT_SECOND_FIELD:
700 				fields[i] = B_DATE_ELEMENT_SECOND;
701 				break;
702 			case UDAT_AM_PM_FIELD:
703 				fields[i] = B_DATE_ELEMENT_AM_PM;
704 				break;
705 			default:
706 				fields[i] = B_DATE_ELEMENT_INVALID;
707 				break;
708 		}
709 	}
710 
711 	return B_OK;
712 }
713 
714 
715 // #pragma mark - Numbers
716 
717 
718 ssize_t
719 BLocale::FormatNumber(char* string, size_t maxSize, double value) const
720 {
721 	BString fullString;
722 	status_t status = FormatNumber(&fullString, value);
723 	if (status != B_OK)
724 		return status;
725 
726 	return strlcpy(string, fullString.String(), maxSize);
727 }
728 
729 
730 status_t
731 BLocale::FormatNumber(BString* string, double value) const
732 {
733 	BAutolock lock(fLock);
734 	if (!lock.IsLocked())
735 		return B_ERROR;
736 
737 	UErrorCode err = U_ZERO_ERROR;
738 	ObjectDeleter<NumberFormat> numberFormatter(NumberFormat::createInstance(
739 		*BFormattingConventions::Private(&fConventions).ICULocale(),
740 		UNUM_DECIMAL, err));
741 
742 	if (numberFormatter.Get() == NULL)
743 		return B_NO_MEMORY;
744 	if (U_FAILURE(err))
745 		return B_BAD_VALUE;
746 
747 	UnicodeString icuString;
748 	numberFormatter->format(value, icuString);
749 
750 	string->Truncate(0);
751 	BStringByteSink stringConverter(string);
752 	icuString.toUTF8(stringConverter);
753 
754 	return B_OK;
755 }
756 
757 
758 ssize_t
759 BLocale::FormatNumber(char* string, size_t maxSize, int32 value) const
760 {
761 	BString fullString;
762 	status_t status = FormatNumber(&fullString, value);
763 	if (status != B_OK)
764 		return status;
765 
766 	return strlcpy(string, fullString.String(), maxSize);
767 }
768 
769 
770 status_t
771 BLocale::FormatNumber(BString* string, int32 value) const
772 {
773 	BAutolock lock(fLock);
774 	if (!lock.IsLocked())
775 		return B_ERROR;
776 
777 	UErrorCode err = U_ZERO_ERROR;
778 	ObjectDeleter<NumberFormat> numberFormatter(NumberFormat::createInstance(
779 		*BFormattingConventions::Private(&fConventions).ICULocale(),
780 		UNUM_DECIMAL, err));
781 
782 	if (numberFormatter.Get() == NULL)
783 		return B_NO_MEMORY;
784 	if (U_FAILURE(err))
785 		return B_BAD_VALUE;
786 
787 	UnicodeString icuString;
788 	numberFormatter->format((int32_t)value, icuString);
789 
790 	string->Truncate(0);
791 	BStringByteSink stringConverter(string);
792 	icuString.toUTF8(stringConverter);
793 
794 	return B_OK;
795 }
796 
797 
798 ssize_t
799 BLocale::FormatMonetary(char* string, size_t maxSize, double value) const
800 {
801 	BString fullString;
802 	status_t status = FormatMonetary(&fullString, value);
803 	if (status != B_OK)
804 		return status;
805 
806 	return strlcpy(string, fullString.String(), maxSize);
807 }
808 
809 
810 status_t
811 BLocale::FormatMonetary(BString* string, double value) const
812 {
813 	if (string == NULL)
814 		return B_BAD_VALUE;
815 
816 	BAutolock lock(fLock);
817 	if (!lock.IsLocked())
818 		return B_ERROR;
819 
820 	UErrorCode err = U_ZERO_ERROR;
821 	ObjectDeleter<NumberFormat> numberFormatter(
822 		NumberFormat::createCurrencyInstance(
823 			*BFormattingConventions::Private(&fConventions).ICULocale(),
824 			err));
825 
826 	if (numberFormatter.Get() == NULL)
827 		return B_NO_MEMORY;
828 	if (U_FAILURE(err))
829 		return B_BAD_VALUE;
830 
831 	UnicodeString icuString;
832 	numberFormatter->format(value, icuString);
833 
834 	string->Truncate(0);
835 	BStringByteSink stringConverter(string);
836 	icuString.toUTF8(stringConverter);
837 
838 	return B_OK;
839 }
840 
841 
842 DateFormat*
843 BLocale::_CreateDateFormatter(const BString& format) const
844 {
845 	Locale* icuLocale
846 		= fConventions.UseStringsFromPreferredLanguage()
847 			? BLanguage::Private(&fLanguage).ICULocale()
848 			: BFormattingConventions::Private(&fConventions).ICULocale();
849 
850 	DateFormat* dateFormatter
851 		= DateFormat::createDateInstance(DateFormat::kShort, *icuLocale);
852 	if (dateFormatter == NULL)
853 		return NULL;
854 
855 	SimpleDateFormat* dateFormatterImpl
856 		= static_cast<SimpleDateFormat*>(dateFormatter);
857 
858 	UnicodeString pattern(format.String());
859 	dateFormatterImpl->applyPattern(pattern);
860 
861 	return dateFormatter;
862 }
863 
864 
865 DateFormat*
866 BLocale::_CreateTimeFormatter(const BString& format) const
867 {
868 	Locale* icuLocale
869 		= fConventions.UseStringsFromPreferredLanguage()
870 			? BLanguage::Private(&fLanguage).ICULocale()
871 			: BFormattingConventions::Private(&fConventions).ICULocale();
872 
873 	DateFormat* timeFormatter
874 		= DateFormat::createTimeInstance(DateFormat::kShort, *icuLocale);
875 	if (timeFormatter == NULL)
876 		return NULL;
877 
878 	SimpleDateFormat* timeFormatterImpl
879 		= static_cast<SimpleDateFormat*>(timeFormatter);
880 
881 	UnicodeString pattern(format.String());
882 	timeFormatterImpl->applyPattern(pattern);
883 
884 	return timeFormatter;
885 }
886