Skip to content

Commit b706509

Browse files
[gnc-ui-utils.cpp] use icu::RBNF to convert numbers to long strings
1 parent 8c94132 commit b706509

File tree

3 files changed

+24
-130
lines changed

3 files changed

+24
-130
lines changed

bindings/app-utils.i

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ GNCPrintAmountInfo gnc_price_print_info (const gnc_commodity *curr,
8181
GNCPrintAmountInfo gnc_share_print_info_places (int decplaces);
8282
const char * xaccPrintAmount (gnc_numeric val, GNCPrintAmountInfo info);
8383

84-
gchar *number_to_words(gdouble val, gint64 denom);
8584
const gchar *printable_value (gdouble val, gint denom);
8685

8786
gboolean gnc_reverse_balance (const Account *account);

libgnucash/app-utils/gnc-ui-util.cpp

Lines changed: 24 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include <string.h>
4444
#include <cinttypes>
4545
#include <unicode/listformatter.h>
46+
#include <unicode/rbnf.h>
4647

4748
#include "qof.h"
4849
#include "gnc-prefs.h"
@@ -1496,149 +1497,44 @@ gnc_wrap_text_with_bidi_ltr_isolate (const char* text)
14961497
/********************************************************************\
14971498
********************************************************************/
14981499

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[] =
1500+
#ifdef _MSC_VER
1501+
static double round(double x)
15241502
{
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-
};
1503+
// A simple round() implementation because MSVC doesn't seem to have that
1504+
return floor(x + 0.5);
1505+
}
1506+
#endif
15511507

1552-
static char*
1553-
integer_to_words(gint64 val)
1508+
static std::string
1509+
number_to_words(double val)
15541510
{
1555-
if (val == 0)
1556-
return g_strdup("zero");
1557-
if (val < 0)
1558-
val = -val;
1559-
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)
1511+
UErrorCode status{U_ZERO_ERROR};
1512+
icu::RuleBasedNumberFormat formatter{icu::URBNF_SPELLOUT, icu::Locale{}, status};
1513+
icu::UnicodeString result;
1514+
std::string words;
1515+
if (U_FAILURE(status))
15831516
{
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, ' ');
1517+
PERR("Error creating formatter: %s", u_errorName(status));
1518+
return "";
15881519
}
15891520

1590-
if (val > 0)
1521+
formatter.format (std::fabs(val), result, status);
1522+
if (U_FAILURE(status))
15911523
{
1592-
int this_part = val;
1593-
g_string_append(result, gettext(small_numbers[this_part]));
1594-
g_string_append_c(result, ' ');
1524+
PERR("Error formatting number: %s", u_errorName(status));
1525+
return "";
15951526
}
15961527

1597-
result = g_string_truncate(result, result->len - 1);
1598-
return g_string_free(result, FALSE);
1599-
}
1600-
1601-
#ifdef _MSC_VER
1602-
static double round(double x)
1603-
{
1604-
// A simple round() implementation because MSVC doesn't seem to have that
1605-
return floor(x + 0.5);
1606-
}
1607-
#endif
1528+
result.toUTF8String(words);
1529+
DEBUG ("Number %f in words: %s", val, words.c_str());
16081530

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;
1531+
return words;
16351532
}
16361533

16371534
char*
16381535
numeric_to_words(gnc_numeric val)
16391536
{
1640-
return number_to_words(gnc_numeric_to_double(val),
1641-
gnc_numeric_denom(val));
1537+
return g_strdup(number_to_words (gnc_numeric_to_double(val)).c_str());
16421538
}
16431539

16441540
const char*

libgnucash/app-utils/gnc-ui-util.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,6 @@ const char* xaccPrintAmount (gnc_numeric val, GNCPrintAmountInfo info);
315315
int xaccSPrintAmount (char* buf, gnc_numeric val, GNCPrintAmountInfo info);
316316

317317
const char* printable_value(gdouble val, gint denom);
318-
char* number_to_words(gdouble val, gint64 denom);
319318
char* numeric_to_words(gnc_numeric val);
320319

321320
/** Parses in_str to obtain a numeric result. The

0 commit comments

Comments
 (0)