diff --git a/OpenXmlPowerTools.Tests/ListItemTextGetter_de_DETests.cs b/OpenXmlPowerTools.Tests/ListItemTextGetter_de_DETests.cs
new file mode 100644
index 00000000..efc1e390
--- /dev/null
+++ b/OpenXmlPowerTools.Tests/ListItemTextGetter_de_DETests.cs
@@ -0,0 +1,129 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using Xunit;
+using OpenXmlPowerTools; 
+
+#if !ELIDE_XUNIT_TESTS
+
+namespace OpenXmlPowerTools.Tests
+{
+    public class ListItemTextGetter_de_DETests
+    {
+        [Theory]
+        [InlineData(0, "Zero")]
+        [InlineData(1, "1-ste")]
+        [InlineData(2, "2-te")]
+        [InlineData(3, "3-te")]
+        [InlineData(4, "4-te")]
+        [InlineData(5, "5-te")]
+        [InlineData(6, "6-te")]
+        [InlineData(7, "7-te")]
+        [InlineData(8, "8-te")]
+        [InlineData(9, "9-te")]
+        [InlineData(10, "10-te")]
+        [InlineData(11, "11-te")]
+        [InlineData(12, "12-te")]
+        [InlineData(13, "13-te")]
+        [InlineData(14, "14-te")]
+        [InlineData(16, "16-te")]
+        [InlineData(17, "17-te")]
+        [InlineData(18, "18-te")]
+        [InlineData(19, "19-te")]
+        [InlineData(20, "20-te")]
+        [InlineData(23, "23-te")]
+        [InlineData(25, "25-te")]
+        [InlineData(50, "50-te")]
+        [InlineData(56, "56-te")]
+        [InlineData(67, "67-te")]
+        [InlineData(78, "78-te")]
+        [InlineData(100, "100-te")]
+        [InlineData(123, "123-te")]
+        [InlineData(125, "125-te")]
+        [InlineData(1050, "1050-te")]
+        public void GetListItemText_Ordinal(int integer, string expectedText)
+        {
+            string actualText = ListItemTextGetter_de_DE.GetListItemText("", integer, "ordinal"); 
+
+            Assert.Equal(expectedText, actualText);
+        }
+
+        [Theory]
+        [InlineData(0, "Zero")]
+        [InlineData(1, "Erste")]
+        [InlineData(2, "Zweite")]
+        [InlineData(3, "Dritte")]
+        [InlineData(4, "Vierte")]
+        [InlineData(5, "Fünfte")]
+        [InlineData(6, "Sechste")]
+        [InlineData(7, "Siebte")]
+        [InlineData(8, "Achte")]
+        [InlineData(9, "Neunte")]
+        [InlineData(10, "Zehnte")]
+        [InlineData(11, "Elfte")]
+        [InlineData(12, "Zwölfte")]
+        [InlineData(13, "Dreizehnte")]
+        [InlineData(14, "Vierzehnte")]
+        [InlineData(16, "Sechzehnte")]
+        [InlineData(17, "Siebzehnte")]
+        [InlineData(18, "Achtzehnte")]
+        [InlineData(19, "Neunzehnte")]
+        [InlineData(20, "Zwanzigste")]
+        [InlineData(23, "Dreiundzwanzigste")]
+        [InlineData(25, "Fünfundzwanzigste")]
+        [InlineData(50, "Fünfzigste")]
+        [InlineData(56, "Sechsundfünfzigste")]
+        [InlineData(67, "Siebenundsechzigste")]
+        [InlineData(78, "Achtundsiebzigste")]
+        [InlineData(100, "Einhundertste")]
+        [InlineData(123, "Einhundertdreiundzwanzigste")]
+        [InlineData(125, "Einhundertfünfundzwanzigste")]
+        [InlineData(1050, "Eintausendfünfzigste")]
+        public void GetListItemText_OrdinalText(int integer, string expectedText)
+        {
+            string actualText = ListItemTextGetter_de_DE.GetListItemText("", integer, "ordinalText"); 
+
+            Assert.Equal(expectedText, actualText);
+        }
+
+        [Theory]
+        [InlineData(0, "Zero")]
+        [InlineData(1, "Eins")]
+        [InlineData(2, "Zwei")]
+        [InlineData(3, "Drei")]
+        [InlineData(4, "Vier")]
+        [InlineData(5, "Fünf")]
+        [InlineData(6, "Sechs")]
+        [InlineData(7, "Sieben")]
+        [InlineData(8, "Acht")]
+        [InlineData(9, "Neun")]
+        [InlineData(10, "Zehn")]
+        [InlineData(11, "Elf")]
+        [InlineData(12, "Zwölf")]
+        [InlineData(13, "Dreizehn")]
+        [InlineData(14, "Vierzehn")]
+        [InlineData(16, "Sechzehn")]
+        [InlineData(17, "Siebzehn")]
+        [InlineData(18, "Achtzehn")]
+        [InlineData(19, "Neunzehn")]
+        [InlineData(20, "Zwanzig")]
+        [InlineData(23, "Dreiundzwanzig")]
+        [InlineData(25, "Fünfundzwanzig")]
+        [InlineData(50, "Fünfzig")]
+        [InlineData(56, "Sechsundfünfzig")]
+        [InlineData(67, "Siebenundsechzig")]
+        [InlineData(78, "Achtundsiebzig")]
+        [InlineData(100, "Einhundert")]
+        [InlineData(123, "Einhundertdreiundzwanzig")]
+        [InlineData(125, "Einhundertfünfundzwanzig")]
+        [InlineData(1050, "Eintausendfünfzig")]
+        public void GetListItemText_CardinalText(int integer, string expectedText)
+        {
+            string actualText = ListItemTextGetter_de_DE.GetListItemText("", integer, "cardinalText"); 
+
+            Assert.Equal(expectedText, actualText);
+        }
+    }
+}
+
+#endif
diff --git a/OpenXmlPowerTools.Tests/ListItemTextGetter_es_ESTests.cs b/OpenXmlPowerTools.Tests/ListItemTextGetter_es_ESTests.cs
new file mode 100644
index 00000000..1e39c255
--- /dev/null
+++ b/OpenXmlPowerTools.Tests/ListItemTextGetter_es_ESTests.cs
@@ -0,0 +1,129 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using Xunit;
+using OpenXmlPowerTools; 
+
+#if !ELIDE_XUNIT_TESTS
+
+namespace OpenXmlPowerTools.Tests
+{
+    public class ListItemTextGetter_es_ESTests
+    {
+        [Theory]
+        [InlineData(0, "Cero")]
+        [InlineData(1, "1-o")]
+        [InlineData(2, "2-o")]
+        [InlineData(3, "3-o")]
+        [InlineData(4, "4-o")]
+        [InlineData(5, "5-o")]
+        [InlineData(6, "6-o")]
+        [InlineData(7, "7-o")]
+        [InlineData(8, "8-o")]
+        [InlineData(9, "9-o")]
+        [InlineData(10, "10-o")]
+        [InlineData(11, "11-o")]
+        [InlineData(12, "12-o")]
+        [InlineData(13, "13-o")]
+        [InlineData(14, "14-o")]
+        [InlineData(16, "16-o")]
+        [InlineData(17, "17-o")]
+        [InlineData(18, "18-o")]
+        [InlineData(19, "19-o")]
+        [InlineData(20, "20-o")]
+        [InlineData(23, "23-o")]
+        [InlineData(25, "25-o")]
+        [InlineData(50, "50-o")]
+        [InlineData(56, "56-o")]
+        [InlineData(67, "67-o")]
+        [InlineData(78, "78-o")]
+        [InlineData(100, "100-o")]
+        [InlineData(123, "123-o")]
+        [InlineData(125, "125-o")]
+        [InlineData(1050, "1050-o")]
+        public void GetListItemText_Ordinal(int integer, string expectedText)
+        {
+            string actualText = ListItemTextGetter_es_ES.GetListItemText("", integer, "ordinal"); 
+
+            Assert.Equal(expectedText, actualText);
+        }
+
+        [Theory]
+        [InlineData(0, "Cero")]
+        [InlineData(1, "Primero")]
+        [InlineData(2, "Segundo")]
+        [InlineData(3, "Tercero")]
+        [InlineData(4, "Cuarto")]
+        [InlineData(5, "Quinto")]
+        [InlineData(6, "Sexto")]
+        [InlineData(7, "Séptimo")]
+        [InlineData(8, "Octavo")]
+        [InlineData(9, "Noveno")]
+        [InlineData(10, "Décimo")]
+        [InlineData(11, "Undécimo")]
+        [InlineData(12, "Duodécimo")]
+        [InlineData(13, "Decimotercio")]
+        [InlineData(14, "Decimocuarto")]
+        [InlineData(16, "Decimosexto")]
+        [InlineData(17, "Decimoséptimo")]
+        [InlineData(18, "Decimoctavo")]
+        [InlineData(19, "Decimonoveno")]
+        [InlineData(20, "Vigésimo")]
+        [InlineData(23, "Vigésimo tercero")]
+        [InlineData(25, "Vigésimo quinto")]
+        [InlineData(50, "Quincuagésimo")]
+        [InlineData(56, "Quincuagésimo sexto")]
+        [InlineData(67, "Sexagésimo séptimo")]
+        [InlineData(78, "Septuagésimo octavo")]
+        [InlineData(100, "Centésimo")]
+        [InlineData(123, "Centésimo vigésimo tercero")]
+        [InlineData(125, "Centésimo vigésimo quinto")]
+        [InlineData(1050, "Milesimo quincuagésimo")]
+        public void GetListItemText_OrdinalText(int integer, string expectedText)
+        {
+            string actualText = ListItemTextGetter_es_ES.GetListItemText("", integer, "ordinalText"); 
+
+            Assert.Equal(expectedText, actualText);
+        }
+
+        [Theory]
+        [InlineData(0, "Cero")]
+        [InlineData(1, "Uno")]
+        [InlineData(2, "Dos")]
+        [InlineData(3, "Tres")]
+        [InlineData(4, "Cuatro")]
+        [InlineData(5, "Cinco")]
+        [InlineData(6, "Seis")]
+        [InlineData(7, "Siete")]
+        [InlineData(8, "Ocho")]
+        [InlineData(9, "Nueve")]
+        [InlineData(10, "Diez")]
+        [InlineData(11, "Once")]
+        [InlineData(12, "Doce")]
+        [InlineData(13, "Trece")]
+        [InlineData(14, "Catorce")]
+        [InlineData(16, "Dieciséis")]
+        [InlineData(17, "Diecisiete")]
+        [InlineData(18, "Dieciocho")]
+        [InlineData(19, "Diecinueve")]
+        [InlineData(20, "Veinte")]
+        [InlineData(23, "Veinte y tres")]
+        [InlineData(25, "Veinte y cinco")]
+        [InlineData(50, "Cincuenta")]
+        [InlineData(56, "Cincuenta y seis")]
+        [InlineData(67, "Sesenta y siete")]
+        [InlineData(78, "Setenta y ocho")]
+        [InlineData(100, "Cien")]
+        [InlineData(123, "Ciento veinte y tres")]
+        [InlineData(125, "Ciento veinte y cinco")]
+        [InlineData(1050, "Mil cincuenta")]
+        public void GetListItemText_CardinalText(int integer, string expectedText)
+        {
+            string actualText = ListItemTextGetter_es_ES.GetListItemText("", integer, "cardinalText"); 
+
+            Assert.Equal(expectedText, actualText);
+        }
+    }
+}
+
+#endif
diff --git a/OpenXmlPowerTools.Tests/ListItemTextGetter_ru_RUTests.cs b/OpenXmlPowerTools.Tests/ListItemTextGetter_ru_RUTests.cs
new file mode 100644
index 00000000..e7dcc8f7
--- /dev/null
+++ b/OpenXmlPowerTools.Tests/ListItemTextGetter_ru_RUTests.cs
@@ -0,0 +1,129 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using Xunit;
+using OpenXmlPowerTools; 
+
+#if !ELIDE_XUNIT_TESTS
+
+namespace OpenXmlPowerTools.Tests
+{
+    public class ListItemTextGetter_ru_RUTests
+    {
+        [Theory]
+        [InlineData(0, "Ноль")]
+        [InlineData(1, "1-ый")]
+        [InlineData(2, "2-ой")]
+        [InlineData(3, "3-ий")]
+        [InlineData(4, "4-ый")]
+        [InlineData(5, "5-ый")]
+        [InlineData(6, "6-ой")]
+        [InlineData(7, "7-ой")]
+        [InlineData(8, "8-ой")]
+        [InlineData(9, "9-ый")]
+        [InlineData(10, "10-ый")]
+        [InlineData(11, "11-ый")]
+        [InlineData(12, "12-ый")]
+        [InlineData(13, "13-ый")]
+        [InlineData(14, "14-ый")]
+        [InlineData(16, "16-ый")]
+        [InlineData(17, "17-ый")]
+        [InlineData(18, "18-ый")]
+        [InlineData(19, "19-ый")]
+        [InlineData(20, "20-ый")]
+        [InlineData(23, "23-ий")]
+        [InlineData(25, "25-ый")]
+        [InlineData(50, "50-ый")]
+        [InlineData(56, "56-ой")]
+        [InlineData(67, "67-ой")]
+        [InlineData(78, "78-ой")]
+        [InlineData(100, "100-ый")]
+        [InlineData(123, "123-ий")]
+        [InlineData(125, "125-ый")]
+        [InlineData(1050, "1050-ый")]
+        public void GetListItemText_Ordinal(int integer, string expectedText)
+        {
+            string actualText = ListItemTextGetter_ru_RU.GetListItemText("", integer, "ordinal"); 
+
+            Assert.Equal(expectedText, actualText);
+        }
+
+        [Theory]
+        [InlineData(0, "Ноль")]
+        [InlineData(1, "Первый")]
+        [InlineData(2, "Второй")]
+        [InlineData(3, "Третий")]
+        [InlineData(4, "Четвертый")]
+        [InlineData(5, "Пятый")]
+        [InlineData(6, "Шестой")]
+        [InlineData(7, "Седьмой")]
+        [InlineData(8, "Восьмой")]
+        [InlineData(9, "Девятый")]
+        [InlineData(10, "Десятый")]
+        [InlineData(11, "Одиннадцатый")]
+        [InlineData(12, "Двенадцатый")]
+        [InlineData(13, "Тринадцатый")]
+        [InlineData(14, "Четырнадцатый")]
+        [InlineData(16, "Шестнадцатый")]
+        [InlineData(17, "Семнадцатый")]
+        [InlineData(18, "Восемнадцатый")]
+        [InlineData(19, "Девятнадцатый")]
+        [InlineData(20, "Двадцатый")]
+        [InlineData(23, "Двадцать третий")]
+        [InlineData(25, "Двадцать пятый")]
+        [InlineData(50, "Пятидесятый")]
+        [InlineData(56, "Пятьдесят шестой")]
+        [InlineData(67, "Шестьдесят седьмой")]
+        [InlineData(78, "Семьдесят восьмой")]
+        [InlineData(100, "Сотый")]
+        [InlineData(123, "Сто двадцать третий")]
+        [InlineData(125, "Сто двадцать пятый")]
+        [InlineData(1050, "Одна тысяча пятидесятый")]
+        public void GetListItemText_OrdinalText(int integer, string expectedText)
+        {
+            string actualText = ListItemTextGetter_ru_RU.GetListItemText("", integer, "ordinalText"); 
+
+            Assert.Equal(expectedText, actualText);
+        }
+
+        [Theory]
+        [InlineData(0, "Ноль")]
+        [InlineData(1, "Один")]
+        [InlineData(2, "Два")]
+        [InlineData(3, "Три")]
+        [InlineData(4, "Четыре")]
+        [InlineData(5, "Пять")]
+        [InlineData(6, "Шесть")]
+        [InlineData(7, "Семь")]
+        [InlineData(8, "Восемь")]
+        [InlineData(9, "Девять")]
+        [InlineData(10, "Десять")]
+        [InlineData(11, "Одиннадцать")]
+        [InlineData(12, "Двенадцать")]
+        [InlineData(13, "Тринадцать")]
+        [InlineData(14, "Четырнадцать")]
+        [InlineData(16, "Шестнадцать")]
+        [InlineData(17, "Семнадцать")]
+        [InlineData(18, "Восемнадцать")]
+        [InlineData(19, "Девятнадцать")]
+        [InlineData(20, "Двадцать")]
+        [InlineData(23, "Двадцать три")]
+        [InlineData(25, "Двадцать пять")]
+        [InlineData(50, "Пятьдесят")]
+        [InlineData(56, "Пятьдесят шесть")]
+        [InlineData(67, "Шестьдесят семь")]
+        [InlineData(78, "Семьдесят восемь")]
+        [InlineData(100, "Сто")]
+        [InlineData(123, "Сто двадцать три")]
+        [InlineData(125, "Сто двадцать пять")]
+        [InlineData(1050, "Одна тысяча пятьдесят")]
+        public void GetListItemText_CardinalText(int integer, string expectedText)
+        {
+            string actualText = ListItemTextGetter_ru_RU.GetListItemText("", integer, "cardinalText"); 
+
+            Assert.Equal(expectedText, actualText);
+        }
+    }
+}
+
+#endif
diff --git a/OpenXmlPowerTools.Tests/OpenXmlPowerTools.Tests.csproj b/OpenXmlPowerTools.Tests/OpenXmlPowerTools.Tests.csproj
index 6bb94044..99ab2966 100644
--- a/OpenXmlPowerTools.Tests/OpenXmlPowerTools.Tests.csproj
+++ b/OpenXmlPowerTools.Tests/OpenXmlPowerTools.Tests.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFrameworks>net452;net461;netcoreapp2.0</TargetFrameworks>
+    <TargetFrameworks>net452;net461;netcoreapp3.1</TargetFrameworks>
     <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
     <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
     <GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
diff --git a/OpenXmlPowerTools/GetListItemText_ru_RU.cs b/OpenXmlPowerTools/GetListItemText_ru_RU.cs
deleted file mode 100644
index ccf1c3f4..00000000
--- a/OpenXmlPowerTools/GetListItemText_ru_RU.cs
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-namespace OpenXmlPowerTools
-{
-    public class ListItemTextGetter_ru_RU
-    {
-        private static string[] OneThroughNineteen = {
-            "один", "два", "три", "четыре", "пять", "шесть", "семь", "восемь",
-            "девять", "десять", "одиннадцать", "двенадцать", "тринадцать", "четырнадцать",
-            "пятнадцать", "шестнадцать", "семнадцать", "восемнадцать", "девятнадцать"
-        };
-
-        private static string[] Tens = {
-            "десять", "двадцать", "тридцать", "сорок", "пятьдесят", "шестьдесят", "семьдесят",
-            "восемьдесят", "девяносто"
-        };
-
-        private static string[] OrdinalOneThroughNineteen = {
-            "первый", "второй", "третий", "четвертый", "пятый", "шестой",
-            "седьмой", "восьмой", "девятый", "десятый", "одиннадцатый", "двенадцатый",
-            "тринадцатый", "четырнадцатый", "пятнадцатый", "шестнадцатый",
-            "семнадцатый", "восемнадцатый", "девятнадцатый"
-        };
-
-        private static string[] OrdinalTenths = {
-            "десятый", "двадцатый", "тридцатый", "сороковой", "пятидесятый",
-            "шестидесятый", "семидесятый", "восьмидесятый", "девяностый"
-        };
-
-        // TODO this is not correct for values above 99
-
-        public static string GetListItemText(string languageCultureName, int levelNumber, string numFmt)
-        {
-            if (numFmt == "cardinalText")
-            {
-                string result = "";
-                int t1 = levelNumber / 1000;
-                int t2 = levelNumber % 1000;
-                if (t1 >= 1)
-                    result += OneThroughNineteen[t1 - 1] + " thousand";
-                if (t1 >= 1 && t2 == 0)
-                    return result.Substring(0, 1).ToUpper() +
-                        result.Substring(1);
-                if (t1 >= 1)
-                    result += " ";
-                int h1 = (levelNumber % 1000) / 100;
-                int h2 = levelNumber % 100;
-                if (h1 >= 1)
-                    result += OneThroughNineteen[h1 - 1] + " hundred";
-                if (h1 >= 1 && h2 == 0)
-                    return result.Substring(0, 1).ToUpper() +
-                        result.Substring(1);
-                if (h1 >= 1)
-                    result += " ";
-                int z = levelNumber % 100;
-                if (z <= 19)
-                    result += OneThroughNineteen[z - 1];
-                else
-                {
-                    int x = z / 10;
-                    int r = z % 10;
-                    result += Tens[x - 1];
-                    if (r >= 1)
-                        result += "-" + OneThroughNineteen[r - 1];
-                }
-                return result.Substring(0, 1).ToUpper() +
-                    result.Substring(1);
-            }
-            if (numFmt == "ordinalText")
-            {
-                string result = "";
-                int t1 = levelNumber / 1000;
-                int t2 = levelNumber % 1000;
-                if (t1 >= 1 && t2 != 0)
-                    result += OneThroughNineteen[t1 - 1] + " thousand";
-                if (t1 >= 1 && t2 == 0)
-                {
-                    result += OneThroughNineteen[t1 - 1] + " thousandth";
-                    return result.Substring(0, 1).ToUpper() +
-                        result.Substring(1);
-                }
-                if (t1 >= 1)
-                    result += " ";
-                int h1 = (levelNumber % 1000) / 100;
-                int h2 = levelNumber % 100;
-                if (h1 >= 1 && h2 != 0)
-                    result += OneThroughNineteen[h1 - 1] + " hundred";
-                if (h1 >= 1 && h2 == 0)
-                {
-                    result += OneThroughNineteen[h1 - 1] + " hundredth";
-                    return result.Substring(0, 1).ToUpper() +
-                        result.Substring(1);
-                }
-                if (h1 >= 1)
-                    result += " ";
-                int z = levelNumber % 100;
-                if (z <= 19)
-                    result += OrdinalOneThroughNineteen[z - 1];
-                else
-                {
-                    int x = z / 10;
-                    int r = z % 10;
-                    if (r == 0)
-                        result += OrdinalTenths[x - 1];
-                    else
-                        result += Tens[x - 1];
-                    if (r >= 1)
-                        result += " " + OrdinalOneThroughNineteen[r - 1];
-                }
-                return result.Substring(0, 1).ToUpper() +
-                    result.Substring(1);
-            }
-            return null;
-        }
-    }
-}
diff --git a/OpenXmlPowerTools/ListItemRetriever.cs b/OpenXmlPowerTools/ListItemRetriever.cs
index 75ee0311..58e875b8 100644
--- a/OpenXmlPowerTools/ListItemRetriever.cs
+++ b/OpenXmlPowerTools/ListItemRetriever.cs
@@ -18,6 +18,8 @@ public class ListItemRetrieverSettings
                 {"fr-FR", ListItemTextGetter_fr_FR.GetListItemText},
                 {"tr-TR", ListItemTextGetter_tr_TR.GetListItemText},
                 {"ru-RU", ListItemTextGetter_ru_RU.GetListItemText}, 
+                {"de-DE", ListItemTextGetter_de_DE.GetListItemText}, 
+                {"es-ES", ListItemTextGetter_es_ES.GetListItemText}, 
                 {"sv-SE", ListItemTextGetter_sv_SE.GetListItemText},
                 {"zh-CN", ListItemTextGetter_zh_CN.GetListItemText},
             };
diff --git a/OpenXmlPowerTools/GetListItemText_Default.cs b/OpenXmlPowerTools/ListItemTextGetter_Default.cs
similarity index 100%
rename from OpenXmlPowerTools/GetListItemText_Default.cs
rename to OpenXmlPowerTools/ListItemTextGetter_Default.cs
diff --git a/OpenXmlPowerTools/ListItemTextGetter_de_DE.cs b/OpenXmlPowerTools/ListItemTextGetter_de_DE.cs
new file mode 100644
index 00000000..e7cebbea
--- /dev/null
+++ b/OpenXmlPowerTools/ListItemTextGetter_de_DE.cs
@@ -0,0 +1,142 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace OpenXmlPowerTools
+{
+    public class ListItemTextGetter_de_DE
+    {
+        private static string[] OneThroughNineteen = {
+            "eins", "zwei", "drei", "vier", "fünf", "sechs", "sieben", "acht",
+            "neun", "zehn", "elf", "zwölf", "dreizehn", "vierzehn",
+            "fünfzehn", "sechzehn", "siebzehn", "achtzehn", "neunzehn"
+        };
+
+        private static string[] Tens = {
+            "zehn", "zwanzig", "dreißig", "vierzig", "fünfzig", "sechzig", "siebzig",
+            "achtzig", "neunzig"
+        };
+        
+        private static string[] OrdinalOneThroughNineteen = {
+            "erste", "zweite", "dritte", "vierte", "fünfte", "sechste",
+            "siebte", "achte", "neunte", "zehnte", "elfte", "zwölfte",
+            "dreizehnte", "vierzehnte", "fünfzehnte", "sechzehnte",
+            "siebzehnte", "achtzehnte", "neunzehnte"
+        };
+
+        private static string[] OrdinalTens = {
+            "zehnte", "zwanzigste", "dreißigste", "vierzigste", "fünfzigste",
+            "sechzigste", "siebzigste", "achtzigste", "neunzigste"
+        };
+
+        public static string GetListItemText(string languageCultureName, int levelNumber, string numFmt)
+        {
+			if (levelNumber > 19999)
+				throw new ArgumentOutOfRangeException("levelNumber", "Converting a number greater than 19999 to text is not supported");
+			if (levelNumber == 0)
+				return "Zero";
+			if (levelNumber < 0)
+				throw new ArgumentOutOfRangeException("levelNumber", "Converting a negative number to text is not supported");
+
+            if (numFmt == "ordinal")
+                return GetOrdinal(levelNumber); 
+            if (numFmt == "cardinalText")
+                return GetCardinalText(levelNumber); 
+            if (numFmt == "ordinalText")
+                return GetOrdinalText(levelNumber); 
+            return null;
+        }
+
+        private static string GetOrdinal(int levelNumber)
+        {
+            string suffix;
+            if (levelNumber % 100 == 11)
+                suffix = "-te";
+            else if (levelNumber % 10 == 1)
+                suffix = "-ste";
+            else
+                suffix = "-te";
+            return levelNumber.ToString() + suffix;
+        }
+
+        private static string GetCardinalText(int levelNumber)
+        {
+            string result = "";
+
+            // Get thousands.
+            int t1 = levelNumber / 1000;
+            int t2 = levelNumber % 1000;
+            if (t1 >= 1)
+                result += (t1 == 1 ? "ein" : OneThroughNineteen[t1 - 1]) + "tausend";
+            if (t1 >= 1 && t2 == 0)
+                return result.Substring(0, 1).ToUpper() + result.Substring(1);
+            
+            // Get hundreds.
+            int h1 = (levelNumber % 1000) / 100;
+            int h2 = levelNumber % 100;
+            if (h1 >= 1)
+                result += (h1 == 1 ? "ein" : OneThroughNineteen[h1 - 1]) + "hundert";
+            if (h1 >= 1 && h2 == 0)
+                return result.Substring(0, 1).ToUpper() + result.Substring(1);
+            
+            // Tens and ones.
+            int z = levelNumber % 100;
+            if (z <= 19)
+                result += OneThroughNineteen[z - 1];
+            else
+            {
+                int x = z / 10;
+                int r = z % 10;
+                if (r >= 1)
+                    result += (r == 1 ? "ein" : OneThroughNineteen[r - 1]) + "und";
+                result += Tens[x - 1];
+            }
+            return result.Substring(0, 1).ToUpper() + result.Substring(1);
+        }
+
+        private static string GetOrdinalText(int levelNumber)
+        {
+            string result = "";
+
+            // Get thousands.
+            int t1 = levelNumber / 1000;
+            int t2 = levelNumber % 1000;
+            if (t1 >= 1 && t2 != 0)
+                result += (t1 == 1 ? "ein" : OneThroughNineteen[t1 - 1]) + "tausend";
+            if (t1 >= 1 && t2 == 0)
+            {
+                result += (t1 == 1 ? "ein" : OneThroughNineteen[t1 - 1]) + "tausendste";
+                return result.Substring(0, 1).ToUpper() + result.Substring(1);
+            }
+
+            // Get hundreds.
+            int h1 = (levelNumber % 1000) / 100;
+            int h2 = levelNumber % 100;
+            if (h1 >= 1 && h2 != 0)
+                result += (h1 == 1 ? "ein" : OneThroughNineteen[h1 - 1]) + "hundert";
+            if (h1 >= 1 && h2 == 0)
+            {
+                result += (h1 == 1 ? "ein" : OneThroughNineteen[h1 - 1])  + "hundertste";
+                return result.Substring(0, 1).ToUpper() + result.Substring(1);
+            }
+
+            // Get tens and ones.
+            int z = levelNumber % 100;
+            if (z <= 19)
+                result += OrdinalOneThroughNineteen[z - 1];
+            else
+            {
+                int x = z / 10;
+                int r = z % 10;
+                if (r >= 1)
+                    result += (r == 1 ? "ein" : OneThroughNineteen[r - 1]) + "und";
+                result += OrdinalTens[x - 1];
+            }
+            return result.Substring(0, 1).ToUpper() + result.Substring(1);
+        }
+    }
+}
diff --git a/OpenXmlPowerTools/ListItemTextGetter_es_ES.cs b/OpenXmlPowerTools/ListItemTextGetter_es_ES.cs
new file mode 100644
index 00000000..3e7a3ada
--- /dev/null
+++ b/OpenXmlPowerTools/ListItemTextGetter_es_ES.cs
@@ -0,0 +1,147 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace OpenXmlPowerTools
+{
+    public class ListItemTextGetter_es_ES
+    {
+        private static string[] OneThroughNineteen = {
+            "uno", "dos", "tres", "cuatro", "cinco", "seis", "siete", "ocho",
+            "nueve", "diez", "once", "doce", "trece", "catorce",
+            "quince", "dieciséis", "diecisiete", "dieciocho", "diecinueve"
+        };
+
+        private static string[] Tens = {
+            "diez", "veinte", "treinta", "cuarenta", "cincuenta", "sesenta", "setenta",
+            "ochenta", "noventa"
+        };
+
+        private static string[] Hundreds = {
+            "cien", "doscientos", "trescientos", "cuatrocientos", "quinientos", "seiscientos", "setecientos",
+            "ochocientos", "novecientos"
+        };
+
+        private static string[] OrdinalOneThroughNineteen = {
+            "primero", "segundo", "tercero", "cuarto", "quinto", "sexto",
+            "séptimo", "octavo", "noveno", "décimo", "undécimo", "duodécimo",
+            "decimotercio", "decimocuarto", "decimoquinto", "decimosexto",
+            "decimoséptimo", "decimoctavo", "decimonoveno"
+        };
+
+        private static string[] OrdinalTens = {
+            "décimo", "vigésimo", "trigésimo", "cuadragésimo", "quincuagésimo",
+            "sexagésimo", "septuagésimo", "octogésimo", "nonagésimo"
+        };
+        
+        private static string[] OrdinalHundreds = {
+            "centésimo", "ducentesimo", "tricentesimo", "cuadringentesimo", "quingentesimo", "sexcentesimo", "septingentesimo",
+            "octingentesimo", "noningentesimo"
+        };
+
+        public static string GetListItemText(string languageCultureName, int levelNumber, string numFmt)
+        {
+			if (levelNumber > 19999)
+				throw new ArgumentOutOfRangeException("levelNumber", "Converting a number greater than 19999 to text is not supported");
+			if (levelNumber == 0)
+				return "Cero";
+			if (levelNumber < 0)
+				throw new ArgumentOutOfRangeException("levelNumber", "Converting a negative number to text is not supported");
+
+            if (numFmt == "ordinal")
+                return GetOrdinal(levelNumber);
+            if (numFmt == "cardinalText")
+                return GetCardinalText(levelNumber);
+            if (numFmt == "ordinalText")
+                return GetOrdinalText(levelNumber);
+            return null;
+        }
+
+        private static string GetOrdinal(int levelNumber)
+        {
+            return levelNumber.ToString() + "-o";
+        }
+
+        private static string GetCardinalText(int levelNumber)
+        {
+            string result = "";
+
+            // Get thousands.
+            int t1 = levelNumber / 1000;
+            int t2 = levelNumber % 1000;
+            if (t1 >= 1)
+                result += (t1 == 1 ? "" : OneThroughNineteen[t1 - 1] + " ") + "mil";
+            if (t1 >= 1 && t2 == 0)
+                return result.Substring(0, 1).ToUpper() + result.Substring(1);
+            if (t1 >= 1)
+                result += " ";
+            
+            // Get hundreds.
+            int h1 = (levelNumber % 1000) / 100;
+            int h2 = levelNumber % 100;
+            if (h1 >= 1)
+                result += h1 == 1 && h2 != 0 ? "ciento" : Hundreds[h1 - 1];
+            if (h1 >= 1 && h2 == 0)
+                return result.Substring(0, 1).ToUpper() + result.Substring(1);
+            if (h1 >= 1)
+                result += " ";
+            
+            // Tens and ones.
+            int z = levelNumber % 100;
+            if (z <= 19)
+                result += OneThroughNineteen[z - 1];
+            else
+            {
+                int x = z / 10;
+                int r = z % 10;
+                result += Tens[x - 1];
+                if (r >= 1)
+                    result += " y " + OneThroughNineteen[r - 1];
+            }
+            return result.Substring(0, 1).ToUpper() + result.Substring(1);
+        }
+
+        private static string GetOrdinalText(int levelNumber)
+        {
+            string result = "";
+
+            // Get thousands.
+            int t1 = levelNumber / 1000;
+            int t2 = levelNumber % 1000;
+            if (t1 >= 1)
+                result += (t1 == 1 ? "" : OneThroughNineteen[t1 - 1] + " ") + "milesimo";
+            if (t1 >= 1 && t2 == 0)
+                return result.Substring(0, 1).ToUpper() + result.Substring(1);
+            if (t1 >= 1)
+                result += " ";
+
+            // Get hundreds.
+            int h1 = (levelNumber % 1000) / 100;
+            int h2 = levelNumber % 100;
+            if (h1 >= 1)
+                result += OrdinalHundreds[h1 - 1];
+            if (h1 >= 1 && h2 == 0)
+                return result.Substring(0, 1).ToUpper() + result.Substring(1);
+            if (h1 >= 1)
+                result += " ";
+
+            // Get tens and ones.
+            int z = levelNumber % 100;
+            if (z <= 19)
+                result += OrdinalOneThroughNineteen[z - 1];
+            else
+            {
+                int x = z / 10;
+                int r = z % 10;
+                result += OrdinalTens[x - 1];
+                if (r >= 1)
+                    result += " " + OrdinalOneThroughNineteen[r - 1];
+            }
+            return result.Substring(0, 1).ToUpper() + result.Substring(1);
+        }
+    }
+}
diff --git a/OpenXmlPowerTools/GetListItemText_fr_FR.cs b/OpenXmlPowerTools/ListItemTextGetter_fr_FR.cs
similarity index 100%
rename from OpenXmlPowerTools/GetListItemText_fr_FR.cs
rename to OpenXmlPowerTools/ListItemTextGetter_fr_FR.cs
diff --git a/OpenXmlPowerTools/ListItemTextGetter_ru_RU.cs b/OpenXmlPowerTools/ListItemTextGetter_ru_RU.cs
new file mode 100644
index 00000000..18548e4c
--- /dev/null
+++ b/OpenXmlPowerTools/ListItemTextGetter_ru_RU.cs
@@ -0,0 +1,185 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace OpenXmlPowerTools
+{
+    public class ListItemTextGetter_ru_RU
+    {
+        private static string[] OneThroughNineteen = {
+            "один", "два", "три", "четыре", "пять", "шесть", "семь", "восемь",
+            "девять", "десять", "одиннадцать", "двенадцать", "тринадцать", "четырнадцать",
+            "пятнадцать", "шестнадцать", "семнадцать", "восемнадцать", "девятнадцать"
+        };
+
+        private static string[] Tens = {
+            "десять", "двадцать", "тридцать", "сорок", "пятьдесят", "шестьдесят", "семьдесят",
+            "восемьдесят", "девяносто"
+        };
+
+        private static string[] Hundreds = {
+            "сто", "двести", "триста", "четыреста", "пятьсот", "шестьсот", "семьсот",
+            "восемьсот", "девятьсот"
+        };
+
+        private static string[] OrdinalOneThroughNineteen = {
+            "первый", "второй", "третий", "четвертый", "пятый", "шестой",
+            "седьмой", "восьмой", "девятый", "десятый", "одиннадцатый", "двенадцатый",
+            "тринадцатый", "четырнадцатый", "пятнадцатый", "шестнадцатый",
+            "семнадцатый", "восемнадцатый", "девятнадцатый"
+        };
+
+        private static string[] OrdinalTens = {
+            "десятый", "двадцатый", "тридцатый", "сороковой", "пятидесятый",
+            "шестидесятый", "семидесятый", "восьмидесятый", "девяностый"
+        };
+        
+        private static string[] OrdinalOneThroughNineteenHT = {
+            "одно", "двух", "трёх", "четырёх", "пяти", "шести", "семи", "восьми", "девяти", 
+            "десяти", "одиннадцати", "двеннадцати", "четырнадцати", "пятнадцати", "шестнадцати", 
+            "семнадцати", "восемьнадцати", "девятнадцати"
+        };
+
+        public static string GetListItemText(string languageCultureName, int levelNumber, string numFmt)
+        {
+			if (levelNumber > 19999)
+				throw new ArgumentOutOfRangeException("levelNumber", "Converting a number greater than 19999 to text is not supported");
+			if (levelNumber == 0)
+				return "Ноль";
+			if (levelNumber < 0)
+				throw new ArgumentOutOfRangeException("levelNumber", "Converting a negative number to text is not supported");
+
+            if (numFmt == "ordinal")
+                return GetOrdinal(levelNumber); 
+            if (numFmt == "cardinalText")
+                return GetCardinalText(levelNumber); 
+            if (numFmt == "ordinalText")
+                return GetOrdinalText(levelNumber); 
+            return null;
+        }
+
+        private static string GetOrdinal(int levelNumber)
+        {
+            string suffix;
+            if (levelNumber % 100 == 12 || levelNumber % 100 == 13 || levelNumber % 100 == 16 || 
+                levelNumber % 100 == 17 || levelNumber % 100 == 18)
+                suffix = "-ый";
+            else if (levelNumber % 10 == 2 || levelNumber % 10 == 6 || levelNumber % 10 == 7 || levelNumber % 10 == 8)
+                suffix = "-ой";
+            else if (levelNumber % 10 == 3)
+                suffix = "-ий";
+            else
+                suffix = "-ый";
+            return levelNumber.ToString() + suffix;
+        }
+
+        private static string GetCardinalText(int levelNumber)
+        {
+            string result = "";
+
+            // Get thousands.
+            int t1 = levelNumber / 1000;
+            int t2 = levelNumber % 1000;
+            if (t1 >= 1)
+            {
+                if (t1 == 1) 
+                    result += "одна тысяча";
+                else if (t1 == 2)
+                    result += "две тысячи";
+                else if (t1 == 3 || t1 == 4)
+                    result += OneThroughNineteen[t1 - 1] + " тысячи";
+                else
+                    result += OneThroughNineteen[t1 - 1] + " тысяч";
+            }
+            if (t1 >= 1 && t2 == 0)
+                return result.Substring(0, 1).ToUpper() + result.Substring(1);
+            if (t1 >= 1)
+                result += " ";
+            
+            // Get hundreds.
+            int h1 = (levelNumber % 1000) / 100;
+            int h2 = levelNumber % 100;
+            if (h1 >= 1)
+                result += Hundreds[h1 - 1];
+            if (h1 >= 1 && h2 == 0)
+                return result.Substring(0, 1).ToUpper() + result.Substring(1);
+            if (h1 >= 1)
+                result += " ";
+            
+            // Tens and ones.
+            int z = levelNumber % 100;
+            if (z <= 19)
+                result += OneThroughNineteen[z - 1];
+            else
+            {
+                int x = z / 10;
+                int r = z % 10;
+                result += Tens[x - 1];
+                if (r >= 1)
+                    result += " " + OneThroughNineteen[r - 1];
+            }
+            return result.Substring(0, 1).ToUpper() + result.Substring(1);
+        }
+
+        private static string GetOrdinalText(int levelNumber)
+        {
+            string result = "";
+
+            // Get thousands.
+            int t1 = levelNumber / 1000;
+            int t2 = levelNumber % 1000;
+            if (t1 >= 1 && t2 != 0)
+            {
+                if (t1 == 1) 
+                    result += "одна тысяча";
+                else if (t1 == 2)
+                    result += "две тысячи";
+                else if (t1 == 3 || t1 == 4)
+                    result += OneThroughNineteen[t1 - 1] + " тысячи";
+                else
+                    result += OneThroughNineteen[t1 - 1] + " тысяч";
+            }
+            if (t1 >= 1 && t2 == 0)
+            {
+                result += OrdinalOneThroughNineteenHT[t1 - 1] + "тысячный";
+                return result.Substring(0, 1).ToUpper() + result.Substring(1);
+            }
+            if (t1 >= 1)
+                result += " ";
+
+            // Get hundreds.
+            int h1 = (levelNumber % 1000) / 100;
+            int h2 = levelNumber % 100;
+            if (h1 >= 1 && h2 != 0)
+                result += Hundreds[h1 - 1];
+            if (h1 >= 1 && h2 == 0)
+            {
+                result += (h1 == 1 ? "" : OrdinalOneThroughNineteenHT[h1 - 1]) + "сотый";
+                return result.Substring(0, 1).ToUpper() + result.Substring(1);
+            }
+            if (h1 >= 1)
+                result += " ";
+
+            // Get tens and ones.
+            int z = levelNumber % 100;
+            if (z <= 19)
+                result += OrdinalOneThroughNineteen[z - 1];
+            else
+            {
+                int x = z / 10;
+                int r = z % 10;
+                if (r == 0)
+                    result += OrdinalTens[x - 1];
+                else
+                    result += Tens[x - 1];
+                if (r >= 1)
+                    result += " " + OrdinalOneThroughNineteen[r - 1];
+            }
+            return result.Substring(0, 1).ToUpper() + result.Substring(1);
+        }
+    }
+}
diff --git a/OpenXmlPowerTools/GetListItemText_sv_SE.cs b/OpenXmlPowerTools/ListItemTextGetter_sv_SE.cs
similarity index 96%
rename from OpenXmlPowerTools/GetListItemText_sv_SE.cs
rename to OpenXmlPowerTools/ListItemTextGetter_sv_SE.cs
index 04a90e21..c779d87d 100644
--- a/OpenXmlPowerTools/GetListItemText_sv_SE.cs
+++ b/OpenXmlPowerTools/ListItemTextGetter_sv_SE.cs
@@ -52,14 +52,13 @@ private static string NumberAsCardinalText(string languageCultureName, int level
 			int tens = int.Parse(sLevel.Substring(3, 1));
 			int ones = int.Parse(sLevel.Substring(4, 1));
 
-
 			//Validation
 			if (thousands > 19)
-				throw new ArgumentOutOfRangeException("levelNumber", "Convering a levelNumber to ordinal text that is greater then 19 999 is not supported");
+				throw new ArgumentOutOfRangeException("levelNumber", "Converting a number greater than 19999 to text is not supported");
 			if (levelNumber == 0)
 				return "Noll";
 			if (levelNumber < 0)
-				throw new ArgumentOutOfRangeException("levelNumber", "Converting a negative levelNumber to ordinal text is not supported");
+				throw new ArgumentOutOfRangeException("levelNumber", "Converting a negative number to text is not supported");
 
 			/* exact thousands */
 			if (levelNumber == 1000)
@@ -126,7 +125,7 @@ private static string NumberAsOrdinalText(string languageCultureName, int levelN
 			if (levelNumber <= 0)
 				throw new ArgumentOutOfRangeException("levelNumber", "Converting a zero or negative levelNumber to ordinal text is not supported");
 			if(levelNumber >= 10000)
-				throw new ArgumentOutOfRangeException("levelNumber", "Convering a levelNumber to ordinal text that is greater then 10000 is not supported");
+				throw new ArgumentOutOfRangeException("levelNumber", "Converting a levelNumber to ordinal text that is greater than 10000 is not supported");
 
 			if (levelNumber == 1)
 				return "Första";
diff --git a/OpenXmlPowerTools/GetListItemText_tr_TR.cs b/OpenXmlPowerTools/ListItemTextGetter_tr_TR.cs
similarity index 100%
rename from OpenXmlPowerTools/GetListItemText_tr_TR.cs
rename to OpenXmlPowerTools/ListItemTextGetter_tr_TR.cs
diff --git a/OpenXmlPowerTools/GetListItemText_zh_CN.cs b/OpenXmlPowerTools/ListItemTextGetter_zh_CN.cs
similarity index 100%
rename from OpenXmlPowerTools/GetListItemText_zh_CN.cs
rename to OpenXmlPowerTools/ListItemTextGetter_zh_CN.cs
diff --git a/OpenXmlPowerTools/OpenXmlPowerTools.csproj b/OpenXmlPowerTools/OpenXmlPowerTools.csproj
index c7220506..1956a282 100644
--- a/OpenXmlPowerTools/OpenXmlPowerTools.csproj
+++ b/OpenXmlPowerTools/OpenXmlPowerTools.csproj
@@ -1,6 +1,6 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
-    <TargetFrameworks>net45;net46;netstandard2.0</TargetFrameworks>
+    <TargetFrameworks>net45;net46;netstandard2.0;netcoreapp3.1</TargetFrameworks>
   </PropertyGroup>
 
   <ItemGroup>
@@ -21,4 +21,8 @@
   <ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0'">
     <PackageReference Include="System.Drawing.Common" Version="4.5.0" />
   </ItemGroup>
+
+  <ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.1'">
+    <PackageReference Include="System.Drawing.Common" Version="4.5.0" />
+  </ItemGroup>
 </Project>
\ No newline at end of file