1 ///
2 module arsd.english;
3 
4 string plural(int count, string word, string pluralWord = null) {
5 	if(count == 1 || word.length == 0)
6 		return word; // it isn't actually plural
7 
8 	if(pluralWord !is null)
9 		return pluralWord;
10 
11 	switch(word[$ - 1]) {
12 		case 's':
13 		case 'a', 'e', 'i', 'o', 'u':
14 			return word ~ "es";
15 		case 'f':
16 			return word[0 .. $-1] ~ "ves";
17 		case 'y':
18 			return word[0 .. $-1] ~ "ies";
19 		default:
20 			return word ~ "s";
21 	}
22 }
23 
24 string numberToEnglish(long number) {
25 	string word;
26 	if(number == 0)
27 		return "zero";
28 
29 	if(number < 0) {
30 		word = "negative";
31 		number = -number;
32 	}
33 
34 	while(number) {
35 		if(number < 100) {
36 			if(number < singleWords.length) {
37 				word ~= singleWords[cast(int) number];
38 				break;
39 			} else {
40 				auto tens = number / 10;
41 				word ~= tensPlaceWords[cast(int) tens];
42 				number = number % 10;
43 				if(number)
44 					word ~= "-";
45 			}
46 		} else if(number < 1000) {
47 			auto hundreds = number / 100;
48 			word ~= onesPlaceWords[cast(int) hundreds] ~ " hundred";
49 			number = number % 100;
50 			if(number)
51 				word ~= " and ";
52 		} else if(number < 1000000) {
53 			auto thousands = number / 1000;
54 			word ~= numberToEnglish(thousands) ~ " thousand";
55 			number = number % 1000;
56 			if(number)
57 				word ~= ", ";
58 		} else if(number < 1_000_000_000) {
59 			auto millions = number / 1000000;
60 			word ~= numberToEnglish(millions) ~ " million";
61 			number = number % 1000000;
62 			if(number)
63 				word ~= ", ";
64 		} else if(number < 1_000_000_000_000) {
65 			auto n = number / 1000000000;
66 			word ~= numberToEnglish(n) ~ " billion";
67 			number = number % 1000000000;
68 			if(number)
69 				word ~= ", ";
70 		} else if(number < 1_000_000_000_000_000) {
71 			auto n = number / 1000000000000;
72 			word ~= numberToEnglish(n) ~ " trillion";
73 			number = number % 1000000000000;
74 			if(number)
75 				word ~= ", ";
76 		} else {
77 			import std.conv;
78 			return to!string(number);
79 		}
80 	}
81 
82 	return word;
83 }
84 
85 unittest {
86 	assert(numberToEnglish(1) == "one");
87 	assert(numberToEnglish(5) == "five");
88 	assert(numberToEnglish(13) == "thirteen");
89 	assert(numberToEnglish(54) == "fifty-four");
90 	assert(numberToEnglish(178) == "one hundred and seventy-eight");
91 	assert(numberToEnglish(592) == "five hundred and ninety-two");
92 	assert(numberToEnglish(1234) == "one thousand, two hundred and thirty-four");
93 	assert(numberToEnglish(10234) == "ten thousand, two hundred and thirty-four");
94 	assert(numberToEnglish(105234) == "one hundred and five thousand, two hundred and thirty-four");
95 }
96 
97 enum onesPlaceWords = [
98 	"zero",
99 	"one",
100 	"two",
101 	"three",
102 	"four",
103 	"five",
104 	"six",
105 	"seven",
106 	"eight",
107 	"nine",
108 ];
109 
110 enum singleWords = onesPlaceWords ~ [
111 	"ten",
112 	"eleven",
113 	"twelve",
114 	"thirteen",
115 	"fourteen",
116 	"fifteen",
117 	"sixteen",
118 	"seventeen",
119 	"eighteen",
120 	"nineteen",
121 ];
122 
123 enum tensPlaceWords = [
124 	null,
125 	"ten",
126 	"twenty",
127 	"thirty",
128 	"forty",
129 	"fifty",
130 	"sixty",
131 	"seventy",
132 	"eighty",
133 	"ninety",
134 ];
135 
136 /*
137 void main() {
138 	import std.stdio;
139 	foreach(i; 3433000 ..3433325)
140 	writeln(numberToEnglish(i));
141 }
142 */