22
22
23
23
#include < config.h>
24
24
25
+ #include < numeric>
26
+
25
27
#ifdef __MINGW32__
26
28
#define __USE_MINGW_ANSI_STDIO 1
27
29
#endif
43
45
#include < string.h>
44
46
#include < cinttypes>
45
47
#include < unicode/listformatter.h>
48
+ #include < boost/locale.hpp>
46
49
47
50
#include " qof.h"
48
51
#include " gnc-prefs.h"
54
57
#include " gnc-session.h"
55
58
#include " engine-helpers.h"
56
59
#include " gnc-locale-utils.h"
60
+ #include " gnc-locale-utils.hpp"
57
61
58
62
#define GNC_PREF_CURRENCY_CHOICE_LOCALE " currency-choice-locale"
59
63
#define GNC_PREF_CURRENCY_CHOICE_OTHER " currency-choice-other"
@@ -1496,106 +1500,18 @@ gnc_wrap_text_with_bidi_ltr_isolate (const char* text)
1496
1500
/* *******************************************************************\
1497
1501
********************************************************************/
1498
1502
1499
- #define FUDGE .00001
1500
-
1501
- /* This function is basically untranslatable. I'd
1502
- guess out of the 29 translations we have, 20 will have their number
1503
- wordings in a totally different way than English has (not to
1504
- mention gender-dependent number endings). Which means this
1505
- word-by-word translation will be useless or even plain
1506
- wrong. For this reason, we don't even start to pretend a
1507
- word-by-word translation would be of any use, so we don't mark any
1508
- of these strings for translation. cstim, 2007-04-15. */
1509
- static const char * small_numbers[] =
1510
- {
1511
- /* Translators: This section is for generating the "amount, in
1512
- words" field when printing a check. This function gets the
1513
- wording right for English, but unfortunately not for most other
1514
- languages. Decide for yourself whether the check printing is
1515
- actually needed in your language; if not, you can safely skip the
1516
- translation of all of these strings. */
1517
- " Zero" , " One" , " Two" , " Three" , " Four" ,
1518
- " Five" , " Six" , " Seven" , " Eight" , " Nine" ,
1519
- " Ten" , " Eleven" , " Twelve" , " Thirteen" , " Fourteen" ,
1520
- " Fifteen" , " Sixteen" , " Seventeen" , " Eighteen" , " Nineteen" ,
1521
- " Twenty"
1522
- };
1523
- static const char * medium_numbers[] =
1524
- {
1525
- " Zero" , " Ten" , " Twenty" , " Thirty" , " Forty" ,
1526
- " Fifty" , " Sixty" , " Seventy" , " Eighty" , " Ninety"
1527
- };
1528
- static const char * big_numbers[] =
1529
- {
1530
- /* Translators: This is the word for the number 10^2 */
1531
- " Hundred" ,
1532
- /* Translators: This is the word for the number 10^3 */
1533
- " Thousand" ,
1534
- /* Translators: This is the word for the number 10^6, one thousand
1535
- thousands. */
1536
- " Million" ,
1537
- /* Translators: This is the word for the number 10^9, one thousand
1538
- millions. WATCH OUT: In British English and many other languages
1539
- this word is used for 10^12 which is one million millions! In
1540
- contrast to this, here in GnuCash this is used in the American
1541
- English meaning of 10^9. */
1542
- " Billion" ,
1543
- /* Translators: This is the word for the number 10^12, one million
1544
- millions. */
1545
- " Trillion" ,
1546
- /* Translators: This is the word for the number 10^15 */
1547
- " Quadrillion" ,
1548
- /* Translators: This is the word for the number 10^18 */
1549
- " Quintillion"
1550
- };
1551
-
1552
- static char *
1553
- integer_to_words (gint64 val)
1503
+ static std::string
1504
+ number_to_words (double val, int64_t denom)
1554
1505
{
1555
- if (val == 0 )
1556
- return g_strdup (" zero" );
1557
- if (val < 0 )
1558
- val = -val;
1506
+ double int_part;
1507
+ const int frac_part = std::round (std::modf (std::fabs (val), &int_part) * denom);
1508
+ const std::vector<std::string> tail =
1509
+ { " " , _ (" and" ), " " , std::to_string (frac_part), " /" , std::to_string (denom) };
1510
+ std::ostringstream ss;
1559
1511
1560
- auto result = g_string_sized_new (100 );
1561
-
1562
- while (val >= 1000 )
1563
- {
1564
- int log_val = log10 (val) / 3 + FUDGE;
1565
- int pow_val = exp (log_val * 3 * G_LN10) + FUDGE;
1566
- int this_part = val / pow_val;
1567
- val -= this_part * pow_val;
1568
- auto tmp = integer_to_words (this_part);
1569
- g_string_append_printf (result, " %s %s " , tmp, gettext (big_numbers[log_val]));
1570
- g_free (tmp);
1571
- }
1572
-
1573
- if (val >= 100 )
1574
- {
1575
- int this_part = val / 100 ;
1576
- val -= this_part * 100 ;
1577
- g_string_append_printf (result, " %s %s " ,
1578
- gettext (small_numbers[this_part]),
1579
- gettext (big_numbers[0 ]));
1580
- }
1581
-
1582
- if (val > 20 )
1583
- {
1584
- int this_part = val / 10 ;
1585
- val -= this_part * 10 ;
1586
- g_string_append (result, gettext (medium_numbers[this_part]));
1587
- g_string_append_c (result, ' ' );
1588
- }
1589
-
1590
- if (val > 0 )
1591
- {
1592
- int this_part = val;
1593
- g_string_append (result, gettext (small_numbers[this_part]));
1594
- g_string_append_c (result, ' ' );
1595
- }
1596
-
1597
- result = g_string_truncate (result, result->len - 1 );
1598
- return g_string_free (result, FALSE );
1512
+ ss.imbue (gnc_get_boost_locale ());
1513
+ ss << boost::locale::as::spellout << int_part;
1514
+ return std::accumulate (tail.begin (), tail.end (), ss.str ());
1599
1515
}
1600
1516
1601
1517
#ifdef _MSC_VER
@@ -1606,39 +1522,12 @@ static double round(double x)
1606
1522
}
1607
1523
#endif
1608
1524
1609
- char *
1610
- number_to_words (double val, int64_t denom)
1611
- {
1612
- if (val < 0 ) val = -val;
1613
- if (denom < 0 ) denom = -denom;
1614
-
1615
- auto int_part = floor (val);
1616
- auto frac_part = static_cast <int64_t >(round ((val - int_part) * denom));
1617
-
1618
- auto int_string = integer_to_words (int_part);
1619
- /* Inside of the gettext macro _(...) we must not use any macros but
1620
- only plain string literals. For this reason, convert the strings
1621
- separately. */
1622
- auto nomin_string = g_strdup_printf (" %02" PRId64, frac_part);
1623
- auto denom_string = g_strdup_printf (" %" PRId64, denom);
1624
- auto full_string =
1625
- /* Translators: This is for the "amount, in words" field in check
1626
- printing. The first %s is the integer amount of dollars (or
1627
- whatever currency), the second and third %s the cent amount as
1628
- a fraction, e.g. 47/100. */
1629
- g_strdup_printf (" %s and %s/%s" ,
1630
- int_string, nomin_string, denom_string);
1631
- g_free (int_string);
1632
- g_free (nomin_string);
1633
- g_free (denom_string);
1634
- return full_string;
1635
- }
1636
-
1637
1525
char *
1638
1526
numeric_to_words (gnc_numeric val)
1639
1527
{
1640
- return number_to_words (gnc_numeric_to_double (val),
1641
- gnc_numeric_denom (val));
1528
+ auto words = number_to_words (gnc_numeric_to_double (val), gnc_numeric_denom (val));
1529
+ PWARN (" Number %s in words: %s" , gnc_num_dbg_to_string (val), words.c_str ());
1530
+ return g_strdup (words.c_str ());
1642
1531
}
1643
1532
1644
1533
const char *
0 commit comments