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