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