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