# Display numbers in German words

## Display numbers in German words

It may happen that we need to display the numbers in words, for instance 1= eins, 2016 = zweitausendsechzehn, etc.

The objective of this document is to provide a way to translate numbers into German words.

The formula described in this document supports number until 15 digits so the maximum value supported is 999999999999999.

So it’s large enough and if you need to have more digits then you can enrich the formula by adding new positions. Moreover, the formula supports positive and negative numbers.

To summarize, this Web Intelligence formula support units, hundreds, thousands, millions, billions, and trillions.

Prior to describe the formulas used in the document here are screenshots of translated numbers.

To do it we need 2 variables, but we can create more variables to simplify the formula that does the translation.

The first variable describes the units and is named [German units]. The variable is similar to a table of string where there is the corresponding word for a number. “zero” is not used because it only appears where the number is equal to 0 so there is a specific condition for it.

Here is the formula:

=”#0##1#eins#01#eins#2#zwei#02#zwei#3#drei#03#drei#4#vier#04#vier#5#fünf#05#fünf#6#sechs#06#sechs#7#sieben#07#sieben#8#acht#08#acht#9#neun#09#neun#10#zehn#11#elf#12#zwölf#13#dreizehn#14#vierzehn#15#fünfzehn#16#sechzehn#17#siebzehn#18#achtzehn#19#neunzehn#20#zwanzig#21#einundzwanzig#22#zweiundzwanzig#23#dreiundzwanzig#24#vierundzwanzig#25#fünfundzwanzig#26#sechsundzwanzig#27#siebenundzwanzig#28#achtundzwanzig#29#neunundzwanzig#30#dreißig#31#einunddreißig#32#zweiunddreißig#33#dreiunddreißig#34#vierunddreißig#35#fünfunddreißig#36#sechsunddreißig#37#siebenunddreißig#38#achtunddreißig#39#neununddreißig#40#vierzig#41#einundvierzig#42#zweiundvierzig#43#dreiundvierzig#44#vierundvierzig#45#fünfundvierzig#46#sechsundvierzig#47#siebenundvierzig#48#achtundvierzig#49#neunundvierzig#50#fünfzig#51#einundfünfzig#52#zweiundfünfzig#53#dreiundfünfzig#54#vierundfünfzig#55#fünfundfünfzig#56#sechsundfünfzig#57#siebenundfünfzig#58#achtundfünfzig#59#neunundfünfzig#60#sechzig#61#einundsechzig#62#zweiundsechzig#63#dreiundsechzig#64#vierundsechzig#65#fünfundsechzig#66#sechsundsechzig#67#siebenundsechzig#68#achtundsechzig#69#neunundsechzig#70#siebzig#71#einundsiebzig#72#zweiundsiebzig#73#dreiundsiebzig#74#vierundsiebzig#75#fünfundsiebzig#76#sechsundsiebzig#77#siebenundsiebzig#78#achtundsiebzig#79#neunundsiebzig#80#achtzig#81#einundachtzig#82#zweiundachtzig#83#dreiundachtzig#84#vierundachtzig#85#fünfundachtzig#86#sechsundachtzig#87#siebenundachtzig#88#achtundachtzig#89#neunundachtzig#90#neunzig#91#einundneunzig#92#zweiundneunzig#93#dreiundneunzig#94#vierundneunzig#95#fünfundneunzig#96#sechsundneunzig#97#siebenundneunzig#98#achtundneunzig#99#neunundneunzig#”

As you can notice there is separators (#) between each number and its associated word.

Now we just need the variable that does the conversion. This formula is complex so I added comments to explain what is the need of each paragraph (Main if statement).

To simplify the formula, you can create an intermediate variable and replace the following formula by the variable name you have created. This formula is used to format the number and remove the potential decimals and minus sign. The formula is used 84 times in the numbers to words translation:

FormatNumber(Abs([My Number]);”0″)

[My Number] is the numeric variable to translate into words.

Now here is the formula used for the translation:

=if Length(FormatNumber(Abs([My Number]);”0″)) > 15 then “*****”  /* Too large */

else if FormatNumber(Abs([My Number]);”0″) = “0” then “null”  /* Zero */

else (if [My Number] < 0 then “minus “)

+ Trim(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(

/* hundred of Trillion */

(if Length(FormatNumber(Abs([My Number]);”0″)) > 14 then

if Left(Right(FormatNumber(Abs([My Number]);”0″);15);1) = “1” then “hundert”

else if Left(Right(FormatNumber(Abs([My Number]);”0″);15);1) <> “0” then

Substr(Substr([German units]; Pos([German units];”#” + Left(Right(FormatNumber(Abs([My Number]);”0″);15);1) + “#”) + Length(Left(Right(FormatNumber(Abs([My Number]);”0″);15);1))+2; Length([German units]));1 ; Pos(Substr([German units]; Pos([German units];”#” + Left(Right(FormatNumber(Abs([My Number]);”0″);15);1) + “#”) + Length(Left(Right(FormatNumber(Abs([My Number]);”0″);15);1))+2 ; Length([German units])); “#”)-1 ) + “hundert”

else “”)

/* Trillion */

+ (if Length(FormatNumber(Abs([My Number]);”0″)) > 13 then

if Left(Right(FormatNumber(Abs([My Number]);”0″);14);2) <> “00” then

Substr(Substr([German units]; Pos([German units];”#” + Left(Right(FormatNumber(Abs([My Number]);”0″);14);2) + “#”) + Length(Left(Right(FormatNumber(Abs([My Number]);”0″);14);2))+2; Length([German units]));1 ; Pos(Substr([German units]; Pos([German units];”#” + Left(Right(FormatNumber(Abs([My Number]);”0″);14);2) + “#”) + Length(Left(Right(FormatNumber(Abs([My Number]);”0″);14);2))+2 ; Length([German units])); “#”)-1 ) + ” Billionen ”

else ” Billionen “

else if Length(FormatNumber(Abs([My Number]);”0″)) > 12 then

if Left(FormatNumber(Abs([My Number]);”0″);1) = “1” then “eine Billion “

else if Left(FormatNumber(Abs([My Number]);”0″);1) <> “0” then

Substr(Substr([German units]; Pos([German units];”#” + Left(FormatNumber(Abs([My Number]);”0″);1) + “#”) + Length(Left(FormatNumber(Abs([My Number]);”0″);1))+2; Length([German units]));1 ; Pos(Substr([German units]; Pos([German units];”#” + Left(FormatNumber(Abs([My Number]);”0″);1) + “#”) + Length(Left(FormatNumber(Abs([My Number]);”0″);1))+2 ; Length([German units])); “#”)-1 ) + ” Billionen ”

else “”)

/* hundred of Billion */

+ (if Length(FormatNumber(Abs([My Number]);”0″)) > 11 then

if Left(Right(FormatNumber(Abs([My Number]);”0″);12);1) = “1” then “hundert”

else if Left(Right(FormatNumber(Abs([My Number]);”0″);12);1) <> “0” then

Substr(Substr([German units]; Pos([German units];”#” + Left(Right(FormatNumber(Abs([My Number]);”0″);12);1) + “#”) + Length(Left(Right(FormatNumber(Abs([My Number]);”0″);12);1))+2; Length([German units]));1 ; Pos(Substr([German units]; Pos([German units];”#” + Left(Right(FormatNumber(Abs([My Number]);”0″);12);1) + “#”) + Length(Left(Right(FormatNumber(Abs([My Number]);”0″);12);1))+2 ; Length([German units])); “#”)-1 ) + “hundert”

else “”)

/* Billion */

+ (if Length(FormatNumber(Abs([My Number]);”0″)) > 10 then

if Left(Right(FormatNumber(Abs([My Number]);”0″);11);2) <> “00” then

Substr(Substr([German units]; Pos([German units];”#” + Left(Right(FormatNumber(Abs([My Number]);”0″);11);2) + “#”) + Length(Left(Right(FormatNumber(Abs([My Number]);”0″);11);2))+2; Length([German units]));1 ; Pos(Substr([German units]; Pos([German units];”#” + Left(Right(FormatNumber(Abs([My Number]);”0″);11);2) + “#”) + Length(Left(Right(FormatNumber(Abs([My Number]);”0″);11);2))+2 ; Length([German units])); “#”)-1 ) + ” Milliarden “

else ” Milliarden “

else if Length(FormatNumber(Abs([My Number]);”0″)) > 9 then

if Left(FormatNumber(Abs([My Number]);”0″);1) = “1” then “eine Milliarde “

else if Left(FormatNumber(Abs([My Number]);”0″);1) <> “0” then

Substr(Substr([German units]; Pos([German units];”#” + Left(FormatNumber(Abs([My Number]);”0″);1) + “#”) + Length(Left(FormatNumber(Abs([My Number]);”0″);1))+2; Length([German units]));1 ; Pos(Substr([German units]; Pos([German units];”#” + Left(FormatNumber(Abs([My Number]);”0″);1) + “#”) + Length(Left(FormatNumber(Abs([My Number]);”0″);1))+2 ; Length([German units])); “#”)-1 ) + ” Milliarden “

else “”)

/* hundred of Million */

+ (if Length(FormatNumber(Abs([My Number]);”0″)) > 8 then

if Left(Right(FormatNumber(Abs([My Number]);”0″);9);1) = “1” then “hundert”

else if Left(Right(FormatNumber(Abs([My Number]);”0″);9);1) <> “0” then

Substr(Substr([German units]; Pos([German units];”#” + Left(Right(FormatNumber(Abs([My Number]);”0″);9);1) + “#”) + Length(Left(Right(FormatNumber(Abs([My Number]);”0″);9);1))+2; Length([German units]));1 ; Pos(Substr([German units]; Pos([German units];”#” + Left(Right(FormatNumber(Abs([My Number]);”0″);9);1) + “#”) + Length(Left(Right(FormatNumber(Abs([My Number]);”0″);9);1))+2 ; Length([German units])); “#”)-1 ) + “hundert”

else “”)

/* Million */

+ (if Length(FormatNumber(Abs([My Number]);”0″)) > 7 then

if Left(Right(FormatNumber(Abs([My Number]);”0″);8);2) <> “00” then

Substr(Substr([German units]; Pos([German units];”#” + Left(Right(FormatNumber(Abs([My Number]);”0″);8);2) + “#”) + Length(Left(Right(FormatNumber(Abs([My Number]);”0″);8);2))+2; Length([German units]));1 ; Pos(Substr([German units]; Pos([German units];”#” + Left(Right(FormatNumber(Abs([My Number]);”0″);8);2) + “#”) + Length(Left(Right(FormatNumber(Abs([My Number]);”0″);8);2))+2 ; Length([German units])); “#”)-1 ) + ” Millionen “

else ” Millionen “

else if Length(FormatNumber(Abs([My Number]);”0″)) > 6 then

if Left(FormatNumber(Abs([My Number]);”0″);1) = “1” then “eine Million “

else if Left(FormatNumber(Abs([My Number]);”0″);1) <> “0” then

Substr(Substr([German units]; Pos([German units];”#” + Left(FormatNumber(Abs([My Number]);”0″);1) + “#”) + Length(Left(FormatNumber(Abs([My Number]);”0″);1))+2; Length([German units]));1 ; Pos(Substr([German units]; Pos([German units];”#” + Left(FormatNumber(Abs([My Number]);”0″);1) + “#”) + Length(Left(FormatNumber(Abs([My Number]);”0″);1))+2 ; Length([German units])); “#”)-1 ) + ” Millionen ”

else “”)

/* hundred of thousand */

+ (if Length(FormatNumber(Abs([My Number]);”0″)) > 5 then

if Left(Right(FormatNumber(Abs([My Number]);”0″);6);1) = “1” then “hundert”

else if Left(Right(FormatNumber(Abs([My Number]);”0″);6);1) <> “0” then

Substr(Substr([German units]; Pos([German units];”#” + Left(Right(FormatNumber(Abs([My Number]);”0″);6);1) + “#”) + Length(Left(Right(FormatNumber(Abs([My Number]);”0″);6);1))+2; Length([German units]));1 ; Pos(Substr([German units]; Pos([German units];”#” + Left(Right(FormatNumber(Abs([My Number]);”0″);6);1) + “#”) + Length(Left(Right(FormatNumber(Abs([My Number]);”0″);6);1))+2 ; Length([German units])); “#”)-1 ) + “hundert”

else “”)

/* thousand */

+ (if Length(FormatNumber(Abs([My Number]);”0″)) > 4 then

if Left(Right(FormatNumber(Abs([My Number]);”0″);5);2) = “01” then “eintausend”

else if Left(Right(FormatNumber(Abs([My Number]);”0″);5);2) <> “00” then

Substr(Substr([German units]; Pos([German units];”#” + Left(Right(FormatNumber(Abs([My Number]);”0″);5);2) + “#”) + Length(Left(Right(FormatNumber(Abs([My Number]);”0″);5);2))+2; Length([German units]));1 ; Pos(Substr([German units]; Pos([German units];”#” + Left(Right(FormatNumber(Abs([My Number]);”0″);5);2) + “#”) + Length(Left(Right(FormatNumber(Abs([My Number]);”0″);5);2))+2 ; Length([German units])); “#”)-1 ) + “tausend”

else “tausend”

else if Length(FormatNumber(Abs([My Number]);”0″)) > 3 then

if Left(FormatNumber(Abs([My Number]);”0″);1) = “1” then “eintausend”

else if Left(FormatNumber(Abs([My Number]);”0″);1) <> “0” then

Substr(Substr([German units]; Pos([German units];”#” + Left(FormatNumber(Abs([My Number]);”0″);1) + “#”) + Length(Left(FormatNumber(Abs([My Number]);”0″);1))+2; Length([German units]));1 ; Pos(Substr([German units]; Pos([German units];”#” + Left(FormatNumber(Abs([My Number]);”0″);1) + “#”) + Length(Left(FormatNumber(Abs([My Number]);”0″);1))+2 ; Length([German units])); “#”)-1 ) + “tausend”

else “”)

/* hundred */

+ (if Length(FormatNumber(Abs([My Number]);”0″)) > 2 then

if Left(Right(FormatNumber(Abs([My Number]);”0″);3);1) = “1” then “hundert”

else if Left(Right(FormatNumber(Abs([My Number]);”0″);3);1) <> “0” then

Substr(Substr([German units]; Pos([German units];”#” + Left(Right(FormatNumber(Abs([My Number]);”0″);3);1) + “#”) + Length(Left(Right(FormatNumber(Abs([My Number]);”0″);3);1))+2; Length([German units]));1 ; Pos(Substr([German units]; Pos([German units];”#” + Left(Right(FormatNumber(Abs([My Number]);”0″);3);1) + “#”) + Length(Left(Right(FormatNumber(Abs([My Number]);”0″);3);1))+2 ; Length([German units])); “#”)-1 ) + “hundert”

else “”)

/* units */

+ Substr(Substr([German units]; Pos([German units];”#” + Right(FormatNumber(Abs([My Number]);”0″);2) + “#”) + Length(Right(FormatNumber(Abs([My Number]);”0″);2))+2; Length([German units]));1 ; Pos(Substr([German units]; Pos([German units];”#” + Right(FormatNumber(Abs([My Number]);”0″);2) + “#”) + Length(Right(FormatNumber(Abs([My Number]);”0″);2))+2 ; Length([German units])); “#”)-1 )

;”  “; ” “);” Billionen Milliarden “;” Billionen “);” Billionen Milliarde “;” Billionen “);” Billion Milliarden “;” Billion “);” Billion Milliarde “;” Billion “);” Billionen Millionen “;” Billionen “);” Billionen Million” ;” Billionen “);” Billion Millionen “;” Billion “);” Billion Million “;” Billion “);” Billionen tausend”;” Billionen “);” Billion tausend”;” Billion “);” Milliarden Millionen “;” Milliarden “);” Milliarden Million “;” Milliarden “);” Milliarde Million “;” Milliarde “);” Milliarde Millionen “;” Milliarde “);” Milliarden tausend”;” Milliarden “);” Milliarde tausend”;” Milliarde “);” Millionen tausend”;” Millionen “);” Million tausend”;” Million “) )

As I said the formula is a bit complex but can be easily explained.

There is no performance issue. In the dataset I used there are 33413 different numbers all unique and it takes less than 2 seconds to translate all numbers.

• The first condition is used to test if the number is less or equal to 14 digits.
if Length(FormatNumber(Abs([My Number]);”0″)) > 15 then “*****”
• The second condition is used to test if the number is equal to 0.
if FormatNumber(Abs([My Number]);”0″) = “0” then “zero”
• As you can see there is also 6 different Replace statements used to remove inaccurate translations.
For instance with the number 100000, the initial translation writes “eins million tausend”.
We need to remove “tausend”, it has been detected but there is no unit associated so this is redundant.
We do the same for “Billion Milliarde”, “Billion Million”, “Billion tausend”, “Milliarde million”, “Milliard tausend”,
• Now lets’ have a look on the units detection (form 0 to 99).
For the latest digits, the formula is:
Substr(Substr([German units]; Pos([German units];”#” + Right(FormatNumber(Abs([My Number]);”0″);2) + “#”) + Length(Right(FormatNumber(Abs([My Number]);”0″);2))+2; Length([German units]));1 ; Pos(Substr([German units]; Pos([German units];”#” + Right(FormatNumber(Abs([My Number]);”0″);2) + “#”) + Length(Right(FormatNumber(Abs([My Number]);”0″);2))+2 ; Length([German units])); “#”)-1 )
I highlighted in red this part that is used in other places like for thousands, millions, billions, etc.
In the other places, the syntax is a bit different. It can be Left(Right(FormatNumber(Abs([My Number]);”0″);5);2or5);1).
The bold red characters represent the number of digits to extract, and the bold green represent the position in the number.
This part of the formula is always the same everywhere and is used to extract a unit like eleven, thirty two or eighty six, for instance.
• Lets’ have a look on the hundred detection (form 0 to 99).
In that case there is only one digit to extract and the formula is:
if Left(Right(FormatNumber(Abs([My Number]);”0″);12);1) <> “0” then Substr(Substr([German units]; Pos([German units];”#” + Left(Right(FormatNumber(Abs([My Number]);”0″);12);1) + “#”) + Length(Left(Right(FormatNumber(Abs([My Number]);”0″);12);1))+2; Length([German units]));1 ; Pos(Substr([German units]; Pos([German units];”#” + Left(Right(FormatNumber(Abs([My Number]);”0″);12);1) + “#”) + Length(Left(Right(FormatNumber(Abs([My Number]);”0″);12);1))+2 ; Length([German units])); “#”)-1 ) + ” hundert”
We first test if the digit is different from 0 to generate the “hundred” word.
• Concerning the thousands, millions, billions and trillions detection it works like the units.
We just add a text before to check that the digit is different from 0 to generate the appropriate word. If there is 2 digits then we always generate the appropriate word because we know that there is more than zero thousand, zero million, etc.
But in that case depending on the number of leading zeroes, this may lead to have a result with “million thousand” thus explaining the different
• There are also additional subtleties for numbers in German letters. As opposed to English we cannot say one before hundred when it’s only one: for instance in English we can say one hundred in German we need to say hundert (for one hundred). The other units (from 2 to 99) work like in English.
So there additional ReplaceLeft(FormatNumber(Abs([My Number]);”0″);1) = “1”
• Last we have also to consider the plural of words Billion, Milliarde and Million.

## Display numbers with decimals in German words

I also extended the translation formula to manage the decimals (2 decimals maximum).

This formula can be used with currencies to display amount in words such as neunhundertzwanzig euros und siebenundvierzig cents

Here is a screenshot of such translation:

Now here is the formula used for the translation. The core of the formula does not change except for the number formatting: we just need to remove all decimals.

So instead of having FormatNumber(Abs([My Number]);”0″), the new formula is FormatNumber(Truncate(Abs([My Decimal]);0);”0″)

Now the translation formula has changed. I replace and added the red part in the first part of the formula:

=if Length(FormatNumber(Abs([My Decimal]);”0″)) > 15 then “*****”  /* Too large */

else (if [My Decimal] < 0 then “minus ” else “”)

+ if FormatNumber(Truncate(Abs([My Decimal]);0);”0″) = “0” or FormatNumber(Truncate(Abs([My Decimal]);0);”0″) = “1” Then /* Zero or One */

(if FormatNumber(Truncate(Abs([My Decimal]);0);”0″) = “0” Then “zero euro” else “un euro”)

/* decimals */

+ (if Abs([My Decimal]) <> Truncate(Abs([My Decimal]);0) Then ” und”

+ Substr(Substr([German units]; Pos([German units];”#” + Substr(FormatNumber(Abs([My Decimal]) – Truncate(Abs([My Decimal]);0);”#.##”)+”0″;2;2) + “#”) + Length(Substr(FormatNumber(Abs([My Decimal]) – Truncate(Abs([My Decimal]);0);”#.##”)+”0″;2;2))+2; Length([German units]));1 ; Pos(Substr([German units]; Pos([German units];”#” + Substr(FormatNumber(Abs([My Decimal]) – Truncate(Abs([My Decimal]);0);”#.##”)+”0″;2;2) + “#”) + Length(Substr(FormatNumber(Abs([My Decimal]) – Truncate(Abs([My Decimal]);0);”#.##”)+”0″;2;2))+2 ; Length([German units])); “#”)-1 ) + if (Substr(FormatNumber(Abs([My Decimal]) – Truncate(Abs([My Decimal]);0);”#.##”)+”0″;2;2) = “01”) then ” cent” else ” cents” else “”)

else Trim(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(

And I added the new part (in red) at the end of the formula.

/* units */

+ Substr(Substr([German units]; Pos([German units];”#” + Right(FormatNumber(Truncate(Abs([My Decimal]);0);”0″);2) + “#”) + Length(Right(FormatNumber(Truncate(Abs([My Decimal]);0);”0″);2))+2; Length([German units]));1 ; Pos(Substr([German units]; Pos([German units];”#” + Right(FormatNumber(Truncate(Abs([My Decimal]);0);”0″);2) + “#”) + Length(Right(FormatNumber(Truncate(Abs([My Decimal]);0);”0″);2))+2 ; Length([German units])); “#”)-1 ) + ” euros”

/* decimals */

+ (if Abs([My Decimal]) <> Truncate(Abs([My Decimal]);0) Then ” und”

+ Substr(Substr([German units]; Pos([German units];”#” + Substr(FormatNumber(Abs([My Decimal]) – Truncate(Abs([My Decimal]);0);”#.##”)+”0″;2;2) + “#”) + Length(Substr(FormatNumber(Abs([My Decimal]) – Truncate(Abs([My Decimal]);0);”#.##”)+”0″;2;2))+2; Length([German units]));1 ; Pos(Substr([German units]; Pos([German units];”#” + Substr(FormatNumber(Abs([My Decimal]) – Truncate(Abs([My Decimal]);0);”#.##”)+”0″;2;2) + “#”) + Length(Substr(FormatNumber(Abs([My Decimal]) – Truncate(Abs([My Decimal]);0);”#.##”)+”0″;2;2))+2 ; Length([German units])); “#”)-1 ) + if (Substr(FormatNumber(Abs([My Decimal]) – Truncate(Abs([My Decimal]);0);”#.##”)+”0″;2;2) = “01”) then ” cent” else ” cents” else “”)

For the decimals translation I used the same technique than the units.

In conclusion, we have now a powerful way to translate any number in German words.

To use it you just need to replace [My number] or [My decimal] by your measure

You can download the Web Intelligence report attached to that publication.

Didier MAZOUE