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