xref: /haiku/src/kits/locale/Country.cpp (revision 45b01eb84189a623981270a02d21c7a8cb93a9e1)
1 /*
2  * Copyright 2003-2009, Axel Dörfler, axeld@pinc-software.de.
3  * Copyright 2009, Destugues, pulkomandy@gmail.com.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 
8 #include <Country.h>
9 
10 #include <assert.h>
11 
12 #include <IconUtils.h>
13 #include <Resources.h>
14 #include <String.h>
15 
16 #include <unicode/datefmt.h>
17 #include <unicode/dcfmtsym.h>
18 #include <unicode/decimfmt.h>
19 #include <unicode/dtfmtsym.h>
20 #include <unicode/smpdtfmt.h>
21 #include <ICUWrapper.h>
22 
23 #include <monetary.h>
24 #include <stdarg.h>
25 
26 
27 const char* gStrings[] = {
28 	// date/time format
29 	"",
30 	"",
31 	// short date/time format
32 	"",
33 	"",
34 	// am/pm string
35 	"AM",
36 	"PM",
37 	// separators
38 	".",
39 	":",
40 
41 	// currency/monetary
42 	"."
43 	","
44 };
45 
46 
47 BCountry::BCountry(const char* languageCode, const char* countryCode)
48 	:
49 	fStrings(gStrings)
50 {
51 	fICULocale = new icu_4_2::Locale(languageCode, countryCode);
52 }
53 
54 
55 BCountry::BCountry(const char* languageAndCountryCode)
56 	:
57 	fStrings(gStrings)
58 {
59 	fICULocale = new icu_4_2::Locale(languageAndCountryCode);
60 	fICULongDateFormatter = DateFormat::createDateInstance(
61 		DateFormat::FULL, *fICULocale);
62  	fICUShortDateFormatter = DateFormat::createDateInstance(
63 		DateFormat::SHORT, *fICULocale);
64 }
65 
66 
67 BCountry::~BCountry()
68 {
69 	delete fICULocale;
70 }
71 
72 
73 bool
74 BCountry::Name(BString& name) const
75 {
76 	UnicodeString uString;
77 	fICULocale->getDisplayName(uString);
78 	BStringByteSink stringConverter(&name);
79 	uString.toUTF8(stringConverter);
80 	return true;
81 }
82 
83 
84 const char*
85 BCountry::Code() const
86 {
87 	return fICULocale->getName();
88 }
89 
90 
91 status_t
92 BCountry::GetIcon(BBitmap* result)
93 {
94 	if (result == NULL)
95 		return B_BAD_DATA;
96 	// TODO: a proper way to locate the library being used ?
97 	BResources storage("/boot/system/lib/liblocale.so");
98 	if (storage.InitCheck() != B_OK)
99    		return B_ERROR;
100    	size_t size;
101    	const char* code = fICULocale->getCountry();
102 	if (code != NULL) {
103 		printf("this is %s drawing\n",code);
104    		const void* buffer = storage.LoadResource(B_VECTOR_ICON_TYPE, code,
105    			&size);
106    		if (buffer != NULL && size != 0) {
107    			puts("    icon found!");
108 			return BIconUtils::GetVectorIcon(static_cast<const uint8*>(buffer),
109 				size, result);
110    		}
111 	}
112    	return B_BAD_DATA;
113 }
114 
115 
116 // TODO use ICU backend keywords instead
117 const char*
118 BCountry::GetString(uint32 id) const
119 {
120 	if (id < B_COUNTRY_STRINGS_BASE || id >= B_NUM_COUNTRY_STRINGS)
121 		return NULL;
122 
123 	return gStrings[id - B_COUNTRY_STRINGS_BASE];
124 }
125 
126 
127 void
128 BCountry::FormatDate(char* string, size_t maxSize, time_t time, bool longFormat)
129 {
130 	BString fullString;
131 	FormatDate(&fullString, time, longFormat);
132 	strncpy(string, fullString.String(), maxSize);
133 }
134 
135 
136 void
137 BCountry::FormatDate(BString *string, time_t time, bool longFormat)
138 {
139 	// TODO: ICU allows for 4 different levels of expansion :
140 	// short, medium, long, and full. Our bool parameter is not enough...
141 	icu_4_2::DateFormat* dateFormatter
142 		= longFormat ? fICULongDateFormatter : fICUShortDateFormatter;
143 	UnicodeString ICUString;
144 	ICUString = dateFormatter->format((UDate)time * 1000, ICUString);
145 
146 	string->Truncate(0);
147 	BStringByteSink stringConverter(string);
148 
149 	ICUString.toUTF8(stringConverter);
150 }
151 
152 
153 void
154 BCountry::FormatTime(char* string, size_t maxSize, time_t time, bool longFormat)
155 {
156 	BString fullString;
157 	FormatTime(&fullString, time, longFormat);
158 	strncpy(string, fullString.String(), maxSize);
159 }
160 
161 
162 void
163 BCountry::FormatTime(BString* string, time_t time, bool longFormat)
164 {
165 	// TODO: ICU allows for 4 different levels of expansion :
166 	// short, medium, long, and full. Our bool parameter is not enough...
167 	icu_4_2::DateFormat* timeFormatter;
168  	timeFormatter = DateFormat::createTimeInstance(
169 		longFormat ? DateFormat::FULL : DateFormat::SHORT,
170 		*fICULocale);
171 	UnicodeString ICUString;
172 	ICUString = timeFormatter->format((UDate)time * 1000, ICUString);
173 
174 	string->Truncate(0);
175 	BStringByteSink stringConverter(string);
176 
177 	ICUString.toUTF8(stringConverter);
178 }
179 
180 
181 bool
182 BCountry::DateFormat(BString& format, bool longFormat) const
183 {
184 	icu_4_2::DateFormat* dateFormatter
185 		= longFormat ? fICULongDateFormatter : fICUShortDateFormatter;
186 	SimpleDateFormat* dateFormatterImpl
187 		= static_cast<SimpleDateFormat*>(dateFormatter);
188 
189 	UnicodeString ICUString;
190 	ICUString = dateFormatterImpl->toPattern(ICUString);
191 
192 	BStringByteSink stringConverter(&format);
193 
194 	ICUString.toUTF8(stringConverter);
195 
196 	return true;
197 }
198 
199 
200 void
201 BCountry::SetDateFormat(const char* formatString, bool longFormat)
202 {
203 	icu_4_2::DateFormat* dateFormatter
204 		= longFormat ? fICULongDateFormatter : fICUShortDateFormatter;
205 	SimpleDateFormat* dateFormatterImpl
206 		= static_cast<SimpleDateFormat*>(dateFormatter);
207 
208 	UnicodeString pattern(formatString);
209 	dateFormatterImpl->applyPattern(pattern);
210 }
211 
212 
213 bool
214 BCountry::TimeFormat(BString& format, bool longFormat) const
215 {
216 	icu_4_2::DateFormat* dateFormatter;
217  	dateFormatter = DateFormat::createTimeInstance(
218 		longFormat ? DateFormat::FULL : DateFormat::SHORT,
219 		*fICULocale);
220 	SimpleDateFormat* dateFormatterImpl
221 		= static_cast<SimpleDateFormat*>(dateFormatter);
222 
223 	UnicodeString ICUString;
224 	ICUString = dateFormatterImpl->toPattern(ICUString);
225 
226 	BStringByteSink stringConverter(&format);
227 
228 	ICUString.toUTF8(stringConverter);
229 
230 	return true;
231 }
232 
233 
234 // TODO find how to get it from ICU (setting it is ok, we use the pattern-string
235 // for that)
236 // Or remove this function ?
237 const char*
238 BCountry::DateSeparator() const
239 {
240 	return fStrings[B_DATE_SEPARATOR];
241 }
242 
243 
244 const char*
245 BCountry::TimeSeparator() const
246 {
247 	return fStrings[B_TIME_SEPARATOR];
248 }
249 
250 
251 void
252 BCountry::FormatNumber(char* string, size_t maxSize, double value)
253 {
254 	BString fullString;
255 	FormatNumber(&fullString, value);
256 	strncpy(string, fullString.String(), maxSize);
257 }
258 
259 
260 status_t
261 BCountry::FormatNumber(BString* string, double value)
262 {
263 	UErrorCode err = U_ZERO_ERROR;
264 	NumberFormat* numberFormatter
265 		= NumberFormat::createInstance(*fICULocale, NumberFormat::kNumberStyle,
266 			err);
267 
268 	// Warning: we're returning an ICU error here but the type is status_t.
269 	if (U_FAILURE(err)) return err;
270 
271 	UnicodeString ICUString;
272 	ICUString = numberFormatter->format(value, ICUString);
273 
274 	string->Truncate(0);
275 	BStringByteSink stringConverter(string);
276 
277 	ICUString.toUTF8(stringConverter);
278 
279 	return U_ZERO_ERROR;
280 }
281 
282 
283 void
284 BCountry::FormatNumber(char* string, size_t maxSize, int32 value)
285 {
286 	BString fullString;
287 	FormatNumber(&fullString, value);
288 	strncpy(string, fullString.String(), maxSize);
289 }
290 
291 
292 void
293 BCountry::FormatNumber(BString* string, int32 value)
294 {
295 	UErrorCode err;
296 	NumberFormat* numberFormatter
297 		= NumberFormat::createInstance(*fICULocale, err);
298 
299 	assert(err == U_ZERO_ERROR);
300 
301 	UnicodeString ICUString;
302 	ICUString = numberFormatter->format((int32_t)value, ICUString);
303 
304 	string->Truncate(0);
305 	BStringByteSink stringConverter(string);
306 
307 	ICUString.toUTF8(stringConverter);
308 }
309 
310 
311 // This will only work for locales using the decimal system...
312 bool
313 BCountry::DecimalPoint(BString& format) const
314 {
315 	UErrorCode err;
316 	NumberFormat* numberFormatter
317 		= NumberFormat::createInstance(*fICULocale, err);
318 
319 	assert(err == U_ZERO_ERROR);
320 
321 	DecimalFormat* decimalFormatter
322 		= dynamic_cast<DecimalFormat*>(numberFormatter);
323 
324 	assert(decimalFormatter != NULL);
325 
326 	const DecimalFormatSymbols* syms
327 		= decimalFormatter->getDecimalFormatSymbols();
328 
329 	UnicodeString ICUString;
330 	ICUString = syms->getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
331 
332 	BStringByteSink stringConverter(&format);
333 
334 	ICUString.toUTF8(stringConverter);
335 
336 	return true;
337 }
338 
339 
340 bool
341 BCountry::ThousandsSeparator(BString& separator) const
342 {
343 	UErrorCode err;
344 	NumberFormat* numberFormatter
345 		= NumberFormat::createInstance(*fICULocale, err);
346 	assert(err == U_ZERO_ERROR);
347 	DecimalFormat* decimalFormatter
348 		= dynamic_cast<DecimalFormat*>(numberFormatter);
349 
350 	assert(decimalFormatter != NULL);
351 
352 	const DecimalFormatSymbols* syms
353 		= decimalFormatter->getDecimalFormatSymbols();
354 
355 	UnicodeString ICUString;
356 	ICUString = syms->getSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol);
357 
358 	BStringByteSink stringConverter(&separator);
359 
360 	ICUString.toUTF8(stringConverter);
361 
362 	return true;
363 }
364 
365 
366 bool
367 BCountry::Grouping(BString& grouping) const
368 {
369 	UErrorCode err;
370 	NumberFormat* numberFormatter
371 		= NumberFormat::createInstance(*fICULocale, err);
372 	assert(err == U_ZERO_ERROR);
373 	DecimalFormat* decimalFormatter
374 		= dynamic_cast<DecimalFormat*>(numberFormatter);
375 
376 	assert(decimalFormatter != NULL);
377 
378 	const DecimalFormatSymbols* syms
379 		= decimalFormatter->getDecimalFormatSymbols();
380 
381 	UnicodeString ICUString;
382 	ICUString = syms->getSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol);
383 
384 	BStringByteSink stringConverter(&grouping);
385 
386 	ICUString.toUTF8(stringConverter);
387 
388 	return true;
389 }
390 
391 
392 bool
393 BCountry::PositiveSign(BString& sign) const
394 {
395 	UErrorCode err;
396 	NumberFormat* numberFormatter
397 		= NumberFormat::createInstance(*fICULocale, err);
398 	assert(err == U_ZERO_ERROR);
399 	DecimalFormat* decimalFormatter
400 		= dynamic_cast<DecimalFormat*>(numberFormatter);
401 
402 	assert(decimalFormatter != NULL);
403 
404 	const DecimalFormatSymbols* syms
405 		= decimalFormatter->getDecimalFormatSymbols();
406 
407 	UnicodeString ICUString;
408 	ICUString = syms->getSymbol(DecimalFormatSymbols::kPlusSignSymbol);
409 
410 	BStringByteSink stringConverter(&sign);
411 
412 	ICUString.toUTF8(stringConverter);
413 
414 	return true;
415 }
416 
417 
418 bool
419 BCountry::NegativeSign(BString& sign) const
420 {
421 	UErrorCode err;
422 	NumberFormat* numberFormatter
423 		= NumberFormat::createInstance(*fICULocale, err);
424 	assert(err == U_ZERO_ERROR);
425 	DecimalFormat* decimalFormatter
426 		= dynamic_cast<DecimalFormat*>(numberFormatter);
427 
428 	assert(decimalFormatter != NULL);
429 
430 	const DecimalFormatSymbols* syms
431 		= decimalFormatter->getDecimalFormatSymbols();
432 
433 	UnicodeString ICUString;
434 	ICUString = syms->getSymbol(DecimalFormatSymbols::kMinusSignSymbol);
435 
436 	BStringByteSink stringConverter(&sign);
437 
438 	ICUString.toUTF8(stringConverter);
439 
440 	return true;
441 }
442 
443 
444 // TODO does ICU even support this ? Is it in the keywords ?
445 int8
446 BCountry::Measurement() const
447 {
448 	return B_US;
449 }
450 
451 
452 ssize_t
453 BCountry::FormatMonetary(char* string, size_t maxSize, double value)
454 {
455 	BString fullString;
456 	ssize_t written = FormatMonetary(&fullString, value);
457 	if (written < 0)
458 		return written;
459 
460 	return strlcpy(string, fullString.String(), maxSize);
461 }
462 
463 
464 ssize_t
465 BCountry::FormatMonetary(BString* string, double value)
466 {
467 	if (string == NULL)
468 		return B_BAD_VALUE;
469 
470 	UErrorCode err;
471 	NumberFormat* numberFormatter
472 		= NumberFormat::createCurrencyInstance(*fICULocale, err);
473 
474 	assert(err == U_ZERO_ERROR);
475 
476 	UnicodeString ICUString;
477 	ICUString = numberFormatter->format(value, ICUString);
478 
479 	string->Truncate(0);
480 	BStringByteSink stringConverter(string);
481 
482 	ICUString.toUTF8(stringConverter);
483 
484 	return string->Length();
485 }
486 
487 
488 bool
489 BCountry::CurrencySymbol(BString& symbol) const
490 {
491 	UErrorCode err;
492 	NumberFormat* numberFormatter
493 		= NumberFormat::createCurrencyInstance(*fICULocale, err);
494 	assert(err == U_ZERO_ERROR);
495 	DecimalFormat* decimalFormatter
496 		= dynamic_cast<DecimalFormat*>(numberFormatter);
497 
498 	assert(decimalFormatter != NULL);
499 
500 	const DecimalFormatSymbols* syms
501 		= decimalFormatter->getDecimalFormatSymbols();
502 
503 	UnicodeString ICUString;
504 	ICUString = syms->getSymbol(DecimalFormatSymbols::kCurrencySymbol);
505 
506 	BStringByteSink stringConverter(&symbol);
507 
508 	ICUString.toUTF8(stringConverter);
509 
510 	return true;
511 }
512 
513 
514 bool
515 BCountry::InternationalCurrencySymbol(BString& symbol) const
516 {
517 	UErrorCode err;
518 	NumberFormat* numberFormatter
519 		= NumberFormat::createCurrencyInstance(*fICULocale, err);
520 	assert(err == U_ZERO_ERROR);
521 	DecimalFormat* decimalFormatter
522 		= dynamic_cast<DecimalFormat*>(numberFormatter);
523 
524 	assert(decimalFormatter != NULL);
525 
526 	const DecimalFormatSymbols* syms
527 		= decimalFormatter->getDecimalFormatSymbols();
528 
529 	UnicodeString ICUString;
530 	ICUString = syms->getSymbol(DecimalFormatSymbols::kIntlCurrencySymbol);
531 
532 	BStringByteSink stringConverter(&symbol);
533 
534 	ICUString.toUTF8(stringConverter);
535 
536 	return true;
537 }
538 
539 
540 bool
541 BCountry::MonDecimalPoint(BString& decimal) const
542 {
543 	UErrorCode err;
544 	NumberFormat* numberFormatter
545 		= NumberFormat::createCurrencyInstance(*fICULocale, err);
546 	assert(err == U_ZERO_ERROR);
547 	DecimalFormat* decimalFormatter
548 		= dynamic_cast<DecimalFormat*>(numberFormatter);
549 
550 	assert(decimalFormatter != NULL);
551 
552 	const DecimalFormatSymbols* syms
553 		= decimalFormatter->getDecimalFormatSymbols();
554 
555 	UnicodeString ICUString;
556 	ICUString = syms->getSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol);
557 
558 	BStringByteSink stringConverter(&decimal);
559 
560 	ICUString.toUTF8(stringConverter);
561 
562 	return true;
563 }
564 
565 
566 bool
567 BCountry::MonThousandsSeparator(BString& separator) const
568 {
569 	UErrorCode err;
570 	NumberFormat* numberFormatter
571 		= NumberFormat::createCurrencyInstance(*fICULocale, err);
572 	assert(err == U_ZERO_ERROR);
573 	DecimalFormat* decimalFormatter
574 		= dynamic_cast<DecimalFormat*>(numberFormatter);
575 
576 	assert(decimalFormatter != NULL);
577 
578 	const DecimalFormatSymbols* syms
579 		= decimalFormatter->getDecimalFormatSymbols();
580 
581 	UnicodeString ICUString;
582 	ICUString = syms->getSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol);
583 
584 	BStringByteSink stringConverter(&separator);
585 
586 	ICUString.toUTF8(stringConverter);
587 
588 	return true;
589 }
590 
591 
592 bool
593 BCountry::MonGrouping(BString& grouping) const
594 {
595 	UErrorCode err;
596 	NumberFormat* numberFormatter
597 		= NumberFormat::createCurrencyInstance(*fICULocale, err);
598 	assert(err == U_ZERO_ERROR);
599 	DecimalFormat* decimalFormatter
600 		= dynamic_cast<DecimalFormat*>(numberFormatter);
601 
602 	assert(decimalFormatter != NULL);
603 
604 	const DecimalFormatSymbols* syms
605 		= decimalFormatter->getDecimalFormatSymbols();
606 
607 	UnicodeString ICUString;
608 	ICUString = syms->getSymbol(
609 		DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol);
610 
611 	BStringByteSink stringConverter(&grouping);
612 
613 	ICUString.toUTF8(stringConverter);
614 
615 	return true;
616 }
617 
618 
619 // TODO: is this possible to get from ICU ?
620 int32
621 BCountry::MonFracDigits() const
622 {
623 	return 2;
624 }
625 
626