You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucenenet.apache.org by ni...@apache.org on 2021/05/04 12:16:20 UTC

[lucenenet] 01/04: BREAKING: Lucene.Net.QueryParser: Factored out NLS/IMessage/Message support and changed exceptions to use string messages so end users can elect whether to use .NET localization or not

This is an automated email from the ASF dual-hosted git repository.

nightowl888 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/lucenenet.git

commit 528f262346f881ded280c978f9bf516eb1b7bc2c
Author: Shad Storhaug <sh...@shadstorhaug.com>
AuthorDate: Sat May 1 05:40:02 2021 +0700

    BREAKING: Lucene.Net.QueryParser: Factored out NLS/IMessage/Message support and changed exceptions to use string messages so end users can elect whether to use .NET localization or not
---
 .../Flexible/Core/Builders/QueryTreeBuilder.cs     |   5 +-
 ...Designer.cs => QueryParserMessages.Designer.cs} |  54 +++++-----
 .../Flexible/Core/Messages/QueryParserMessages.cs  | 115 +++++++++++----------
 ...essagesBundle.resx => QueryParserMessages.resx} |  13 ++-
 .../Flexible/Core/Messages/package.md              |   2 +-
 .../Flexible/Core/Nodes/BoostQueryNode.cs          |  11 +-
 .../Flexible/Core/Nodes/GroupQueryNode.cs          |  11 +-
 .../Flexible/Core/Nodes/ModifierQueryNode.cs       |  12 +--
 .../Flexible/Core/Nodes/PhraseSlopQueryNode.cs     |  11 +-
 .../Flexible/Core/Nodes/ProximityQueryNode.cs      |   8 +-
 .../Flexible/Core/Nodes/QueryNodeImpl.cs           |  26 ++---
 .../Flexible/Core/Nodes/SlopQueryNode.cs           |  11 +-
 .../Flexible/Core/QueryNodeError.cs                |  92 +++++++++--------
 .../Flexible/Core/QueryNodeException.cs            |  81 +++++----------
 .../Flexible/Core/QueryNodeParseException.cs       |  51 ++++-----
 .../Standard/Builders/AnyQueryNodeBuilder.cs       |   7 +-
 .../Standard/Builders/BooleanQueryNodeBuilder.cs   |   4 +-
 .../Builders/MatchAllDocsQueryNodeBuilder.cs       |   4 +-
 .../Builders/MatchNoDocsQueryNodeBuilder.cs        |   4 +-
 .../Builders/NumericRangeQueryNodeBuilder.cs       |   4 +-
 .../Builders/StandardBooleanQueryNodeBuilder.cs    |   4 +-
 .../Standard/Nodes/NumericRangeQueryNode.cs        |   4 +-
 .../Standard/Parser/EscapeQuerySyntaxImpl.cs       |  14 +--
 .../Flexible/Standard/Parser/ParseException.cs     |  54 +++++-----
 .../Standard/Parser/StandardSyntaxParser.cs        |  18 ++--
 .../Processors/AllowLeadingWildcardProcessor.cs    |   4 +-
 .../Processors/NumericQueryNodeProcessor.cs        |   7 +-
 .../Processors/NumericRangeQueryNodeProcessor.cs   |   7 +-
 .../Lucene.Net.QueryParser.csproj                  |  17 +++
 .../ExceptionHandling/ExceptionExtensions.cs       |   3 +-
 .../Spans/SpansValidatorQueryNodeProcessor.cs      |   5 +-
 .../Flexible/Standard/TestQPHelper.cs              |   6 +-
 .../Support/TestApiConsistency.cs                  |   4 +-
 .../ExceptionHandling/ExceptionExtensions.cs       |   3 +-
 34 files changed, 341 insertions(+), 335 deletions(-)

diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Builders/QueryTreeBuilder.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Builders/QueryTreeBuilder.cs
index d8d69a3..3dbca49 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Core/Builders/QueryTreeBuilder.cs
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Builders/QueryTreeBuilder.cs
@@ -1,10 +1,8 @@
 using Lucene.Net.QueryParsers.Flexible.Core.Messages;
 using Lucene.Net.QueryParsers.Flexible.Core.Nodes;
-using Lucene.Net.QueryParsers.Flexible.Messages;
 using Lucene.Net.QueryParsers.Flexible.Standard.Parser;
 using System;
 using System.Collections.Generic;
-using System.Reflection;
 
 namespace Lucene.Net.QueryParsers.Flexible.Core.Builders
 {
@@ -164,7 +162,8 @@ namespace Lucene.Net.QueryParsers.Flexible.Core.Builders
         {
             if (builder == null)
             {
-                throw new QueryNodeException(new Message(
+                // LUCENENET: Factored out NLS/Message/IMessage so end users can optionally utilize the built-in .NET localization.
+                throw new QueryNodeException(string.Format(
                     QueryParserMessages.LUCENE_QUERY_CONVERSION_ERROR, node
                         .ToQueryString(new EscapeQuerySyntax()), node.GetType()
                         .Name));
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Messages/QueryParserMessagesBundle.Designer.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Messages/QueryParserMessages.Designer.cs
similarity index 88%
rename from src/Lucene.Net.QueryParser/Flexible/Core/Messages/QueryParserMessagesBundle.Designer.cs
rename to src/Lucene.Net.QueryParser/Flexible/Core/Messages/QueryParserMessages.Designer.cs
index 6a9698a..1275ba0 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Core/Messages/QueryParserMessagesBundle.Designer.cs
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Messages/QueryParserMessages.Designer.cs
@@ -1,25 +1,4 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
-*/
-
-//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 // <auto-generated>
 //     This code was generated by a tool.
 //     Runtime Version:4.0.30319.42000
@@ -31,9 +10,8 @@
 
 namespace Lucene.Net.QueryParsers.Flexible.Core.Messages {
     using System;
-    using System.Reflection;
-
-
+    
+    
     /// <summary>
     ///   A strongly-typed resource class, for looking up localized strings, etc.
     /// </summary>
@@ -41,17 +19,17 @@ namespace Lucene.Net.QueryParsers.Flexible.Core.Messages {
     // class via a tool like ResGen or Visual Studio.
     // To add or remove a member, edit your .ResX file then rerun ResGen
     // with the /str option, or rebuild your VS project.
-    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
     [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
-    internal class QueryParserMessagesBundle {
+    internal class QueryParserMessages {
         
         private static global::System.Resources.ResourceManager resourceMan;
         
         private static global::System.Globalization.CultureInfo resourceCulture;
         
         [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
-        internal QueryParserMessagesBundle() {
+        internal QueryParserMessages() {
         }
         
         /// <summary>
@@ -61,7 +39,7 @@ namespace Lucene.Net.QueryParsers.Flexible.Core.Messages {
         internal static global::System.Resources.ResourceManager ResourceManager {
             get {
                 if (object.ReferenceEquals(resourceMan, null)) {
-                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Lucene.Net.QueryParsers.Flexible.Core.Messages.QueryParserMessagesBundle", typeof(QueryParserMessagesBundle).GetTypeInfo().Assembly);
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Lucene.Net.QueryParsers.Flexible.Core.Messages.QueryParserMessages", typeof(QueryParserMessages).Assembly);
                     resourceMan = temp;
                 }
                 return resourceMan;
@@ -83,6 +61,15 @@ namespace Lucene.Net.QueryParsers.Flexible.Core.Messages {
         }
         
         /// <summary>
+        ///   Looks up a localized string similar to Value cannot be null..
+        /// </summary>
+        internal static string ARGUMENT_CANNOT_BE_NULL {
+            get {
+                return ResourceManager.GetString("ARGUMENT_CANNOT_BE_NULL", resourceCulture);
+            }
+        }
+        
+        /// <summary>
         ///   Looks up a localized string similar to Could not parse text &quot;{0}&quot; using {1}.
         /// </summary>
         internal static string COULD_NOT_PARSE_NUMBER {
@@ -191,6 +178,15 @@ namespace Lucene.Net.QueryParsers.Flexible.Core.Messages {
         }
         
         /// <summary>
+        ///   Looks up a localized string similar to The parameter must be greater than or equal to zero..
+        /// </summary>
+        internal static string NUMBER_CANNOT_BE_NEGATIVE {
+            get {
+                return ResourceManager.GetString("NUMBER_CANNOT_BE_NEGATIVE", resourceCulture);
+            }
+        }
+        
+        /// <summary>
         ///   Looks up a localized string similar to Number class not supported by NumericRangeQueryNode: {0}.
         /// </summary>
         internal static string NUMBER_CLASS_NOT_SUPPORTED_BY_NUMERIC_RANGE_QUERY {
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Messages/QueryParserMessages.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Messages/QueryParserMessages.cs
index 6a31e4c..103b981 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Core/Messages/QueryParserMessages.cs
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Messages/QueryParserMessages.cs
@@ -1,61 +1,64 @@
-using Lucene.Net.QueryParsers.Flexible.Messages;
+// LUCENENET specific - factored out this class to optionally use the built in .NET localization rather than
+// forcing the use of the oddly designed Message class with NLS.
 
-namespace Lucene.Net.QueryParsers.Flexible.Core.Messages
-{
-    /*
-     * Licensed to the Apache Software Foundation (ASF) under one or more
-     * contributor license agreements.  See the NOTICE file distributed with
-     * this work for additional information regarding copyright ownership.
-     * The ASF licenses this file to You under the Apache License, Version 2.0
-     * (the "License"); you may not use this file except in compliance with
-     * the License.  You may obtain a copy of the License at
-     *
-     *     http://www.apache.org/licenses/LICENSE-2.0
-     *
-     * Unless required by applicable law or agreed to in writing, software
-     * distributed under the License is distributed on an "AS IS" BASIS,
-     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     * See the License for the specific language governing permissions and
-     * limitations under the License.
-     */
+//using Lucene.Net.QueryParsers.Flexible.Messages;
 
-    /// <summary>
-    /// Flexible Query Parser message bundle class
-    /// </summary>
-    public class QueryParserMessages : NLS
-    {
-        private static readonly string BUNDLE_NAME = typeof(QueryParserMessages).Name;
+//namespace Lucene.Net.QueryParsers.Flexible.Core.Messages
+//{
+//    /*
+//     * Licensed to the Apache Software Foundation (ASF) under one or more
+//     * contributor license agreements.  See the NOTICE file distributed with
+//     * this work for additional information regarding copyright ownership.
+//     * The ASF licenses this file to You under the Apache License, Version 2.0
+//     * (the "License"); you may not use this file except in compliance with
+//     * the License.  You may obtain a copy of the License at
+//     *
+//     *     http://www.apache.org/licenses/LICENSE-2.0
+//     *
+//     * Unless required by applicable law or agreed to in writing, software
+//     * distributed under the License is distributed on an "AS IS" BASIS,
+//     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//     * See the License for the specific language governing permissions and
+//     * limitations under the License.
+//     */
 
-        private QueryParserMessages()
-        {
-            // Do not instantiate
-        }
+//    /// <summary>
+//    /// Flexible Query Parser message bundle class
+//    /// </summary>
+//    public class QueryParserMessages : NLS
+//    {
+//        private static readonly string BUNDLE_NAME = typeof(QueryParserMessages).Name;
 
-        static QueryParserMessages()
-        {
-            // register all string ids with NLS class and initialize static string
-            // values
-            NLS.InitializeMessages(BUNDLE_NAME, typeof(QueryParserMessages));
-        }
+//        private QueryParserMessages()
+//        {
+//            // Do not instantiate
+//        }
 
-        // static string must match the strings in the property files.
-        public static string INVALID_SYNTAX;
-        public static string INVALID_SYNTAX_CANNOT_PARSE;
-        public static string INVALID_SYNTAX_FUZZY_LIMITS;
-        public static string INVALID_SYNTAX_FUZZY_EDITS;
-        public static string INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION;
-        public static string INVALID_SYNTAX_ESCAPE_CHARACTER;
-        public static string INVALID_SYNTAX_ESCAPE_NONE_HEX_UNICODE;
-        public static string NODE_ACTION_NOT_SUPPORTED;
-        public static string PARAMETER_VALUE_NOT_SUPPORTED;
-        public static string LUCENE_QUERY_CONVERSION_ERROR;
-        public static string EMPTY_MESSAGE;
-        public static string WILDCARD_NOT_SUPPORTED;
-        public static string TOO_MANY_BOOLEAN_CLAUSES;
-        public static string LEADING_WILDCARD_NOT_ALLOWED;
-        public static string COULD_NOT_PARSE_NUMBER;
-        public static string NUMBER_CLASS_NOT_SUPPORTED_BY_NUMERIC_RANGE_QUERY;
-        public static string UNSUPPORTED_NUMERIC_DATA_TYPE;
-        public static string NUMERIC_CANNOT_BE_EMPTY;
-    }
-}
+//        static QueryParserMessages()
+//        {
+//            // register all string ids with NLS class and initialize static string
+//            // values
+//            NLS.InitializeMessages(BUNDLE_NAME, typeof(QueryParserMessages));
+//        }
+
+//        // static string must match the strings in the property files.
+//        public static string INVALID_SYNTAX;
+//        public static string INVALID_SYNTAX_CANNOT_PARSE;
+//        public static string INVALID_SYNTAX_FUZZY_LIMITS;
+//        public static string INVALID_SYNTAX_FUZZY_EDITS;
+//        public static string INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION;
+//        public static string INVALID_SYNTAX_ESCAPE_CHARACTER;
+//        public static string INVALID_SYNTAX_ESCAPE_NONE_HEX_UNICODE;
+//        public static string NODE_ACTION_NOT_SUPPORTED;
+//        public static string PARAMETER_VALUE_NOT_SUPPORTED;
+//        public static string LUCENE_QUERY_CONVERSION_ERROR;
+//        public static string EMPTY_MESSAGE;
+//        public static string WILDCARD_NOT_SUPPORTED;
+//        public static string TOO_MANY_BOOLEAN_CLAUSES;
+//        public static string LEADING_WILDCARD_NOT_ALLOWED;
+//        public static string COULD_NOT_PARSE_NUMBER;
+//        public static string NUMBER_CLASS_NOT_SUPPORTED_BY_NUMERIC_RANGE_QUERY;
+//        public static string UNSUPPORTED_NUMERIC_DATA_TYPE;
+//        public static string NUMERIC_CANNOT_BE_EMPTY;
+//    }
+//}
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Messages/QueryParserMessagesBundle.resx b/src/Lucene.Net.QueryParser/Flexible/Core/Messages/QueryParserMessages.resx
similarity index 95%
rename from src/Lucene.Net.QueryParser/Flexible/Core/Messages/QueryParserMessagesBundle.resx
rename to src/Lucene.Net.QueryParser/Flexible/Core/Messages/QueryParserMessages.resx
index de6a680..83f4fab 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Core/Messages/QueryParserMessagesBundle.resx
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Messages/QueryParserMessages.resx
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <!--
 
  Licensed to the Apache Software Foundation (ASF) under one
@@ -19,7 +19,6 @@
  under the License.
 
 -->
-
 <root>
   <!-- 
     Microsoft ResX Schema 
@@ -138,6 +137,10 @@
   <resheader name="writer">
     <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </resheader>
+  <data name="ARGUMENT_CANNOT_BE_NULL" xml:space="preserve">
+    <value>Value cannot be null.</value>
+    <comment>LUCENENET: Added to make the message more specific</comment>
+  </data>
   <data name="COULD_NOT_PARSE_NUMBER" xml:space="preserve">
     <value>Could not parse text "{0}" using {1}</value>
   </data>
@@ -177,6 +180,10 @@
   <data name="NODE_ACTION_NOT_SUPPORTED" xml:space="preserve">
     <value>This node does not support this action.</value>
   </data>
+  <data name="NUMBER_CANNOT_BE_NEGATIVE" xml:space="preserve">
+    <value>The parameter must be greater than or equal to zero.</value>
+    <comment>LUCENENET: Added to make the message more specific</comment>
+  </data>
   <data name="NUMBER_CLASS_NOT_SUPPORTED_BY_NUMERIC_RANGE_QUERY" xml:space="preserve">
     <value>Number class not supported by NumericRangeQueryNode: {0}</value>
   </data>
@@ -195,4 +202,4 @@
   <data name="WILDCARD_NOT_SUPPORTED" xml:space="preserve">
     <value>Wildcard is not supported for query: {0}</value>
   </data>
-</root>
+</root>
\ No newline at end of file
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Messages/package.md b/src/Lucene.Net.QueryParser/Flexible/Core/Messages/package.md
index 8f315a0..2b80db4 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Core/Messages/package.md
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Messages/package.md
@@ -26,4 +26,4 @@ Messages usually used by query parser implementations.
 ## Query Parser Messages
 
 
-Messages for the Flexible Query Parser use [Lucene.Net.QueryParsers.Flexible.Messages.NLS](xref:Lucene.Net.QueryParsers.Flexible.Messages.NLS) API.
\ No newline at end of file
+Messages for the Flexible Query Parser use .NET Resources. See [How to create user-defined exceptions with localized exception messages](https://docs.microsoft.com/en-us/dotnet/standard/exceptions/how-to-create-localized-exception-messages).
\ No newline at end of file
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/BoostQueryNode.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/BoostQueryNode.cs
index 0384a5f..d993112 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/BoostQueryNode.cs
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/BoostQueryNode.cs
@@ -1,6 +1,5 @@
 using Lucene.Net.QueryParsers.Flexible.Core.Messages;
 using Lucene.Net.QueryParsers.Flexible.Core.Parser;
-using Lucene.Net.QueryParsers.Flexible.Messages;
 using System.Collections.Generic;
 
 namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes
@@ -39,11 +38,11 @@ namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes
         /// <param name="value">the boost value, it may vary from 0.0 to 1.0</param>
         public BoostQueryNode(IQueryNode query, float value)
         {
-            if (query == null)
-            {
-                throw new QueryNodeError(new Message(
-                    QueryParserMessages.NODE_ACTION_NOT_SUPPORTED, "query", "null"));
-            }
+            // LUCENENET: Factored out NLS/Message/IMessage so end users can optionally utilize the built-in .NET localization.
+            // LUCENENET: Added paramName parameter and changed to the same error message as the default of ArgumentNullException.
+            // However, we still need this to be an error type so it is not caught in StandardSyntaxParser.
+            if (query is null)
+                throw new QueryNodeError(QueryParserMessages.ARGUMENT_CANNOT_BE_NULL, nameof(query));
 
             this.value = value;
             IsLeaf = false;
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/GroupQueryNode.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/GroupQueryNode.cs
index d5c5691..9504e0b 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/GroupQueryNode.cs
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/GroupQueryNode.cs
@@ -1,6 +1,5 @@
 using Lucene.Net.QueryParsers.Flexible.Core.Messages;
 using Lucene.Net.QueryParsers.Flexible.Core.Parser;
-using Lucene.Net.QueryParsers.Flexible.Messages;
 using System.Collections.Generic;
 
 namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes
@@ -36,11 +35,11 @@ namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes
         /// </summary>
         public GroupQueryNode(IQueryNode query)
         {
-            if (query == null)
-            {
-                throw new QueryNodeError(new Message(
-                    QueryParserMessages.PARAMETER_VALUE_NOT_SUPPORTED, "query", "null"));
-            }
+            // LUCENENET: Factored out NLS/Message/IMessage so end users can optionally utilize the built-in .NET localization.
+            // LUCENENET: Added paramName parameter and changed to the same error message as the default of ArgumentNullException.
+            // However, we still need this to be an error type so it is not caught in StandardSyntaxParser.
+            if (query is null)
+                throw new QueryNodeError(QueryParserMessages.ARGUMENT_CANNOT_BE_NULL, nameof(query));
 
             Allocate();
             IsLeaf = false;
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/ModifierQueryNode.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/ModifierQueryNode.cs
index a2c810c..7b22dcb 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/ModifierQueryNode.cs
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/ModifierQueryNode.cs
@@ -1,7 +1,5 @@
 using Lucene.Net.QueryParsers.Flexible.Core.Messages;
 using Lucene.Net.QueryParsers.Flexible.Core.Parser;
-using Lucene.Net.QueryParsers.Flexible.Messages;
-using System;
 using System.Collections.Generic;
 
 namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes
@@ -45,11 +43,11 @@ namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes
         /// <param name="mod">Modifier Value</param>
         public ModifierQueryNode(IQueryNode query, Modifier mod)
         {
-            if (query == null)
-            {
-                throw new QueryNodeError(new Message(
-                    QueryParserMessages.PARAMETER_VALUE_NOT_SUPPORTED, "query", "null"));
-            }
+            // LUCENENET: Factored out NLS/Message/IMessage so end users can optionally utilize the built-in .NET localization.
+            // LUCENENET: Added paramName parameter and changed to the same error message as the default of ArgumentNullException.
+            // However, we still need this to be an error type so it is not caught in StandardSyntaxParser.
+            if (query is null)
+                throw new QueryNodeError(QueryParserMessages.ARGUMENT_CANNOT_BE_NULL, nameof(query));
 
             Allocate();
             IsLeaf = false;
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/PhraseSlopQueryNode.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/PhraseSlopQueryNode.cs
index 2a7cd60..0560cc0 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/PhraseSlopQueryNode.cs
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/PhraseSlopQueryNode.cs
@@ -1,6 +1,5 @@
 using Lucene.Net.QueryParsers.Flexible.Core.Messages;
 using Lucene.Net.QueryParsers.Flexible.Core.Parser;
-using Lucene.Net.QueryParsers.Flexible.Messages;
 
 namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes
 {
@@ -36,11 +35,11 @@ namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes
         /// <exception cref="QueryNodeError">throw in overridden method to disallow</exception>
         public PhraseSlopQueryNode(IQueryNode query, int value)
         {
-            if (query == null)
-            {
-                throw new QueryNodeError(new Message(
-                    QueryParserMessages.NODE_ACTION_NOT_SUPPORTED, "query", "null"));
-            }
+            // LUCENENET: Factored out NLS/Message/IMessage so end users can optionally utilize the built-in .NET localization.
+            // LUCENENET: Added paramName parameter and changed to the same error message as the default of ArgumentNullException.
+            // However, we still need this to be an error type so it is not caught in StandardSyntaxParser.
+            if (query is null)
+                throw new QueryNodeError(QueryParserMessages.ARGUMENT_CANNOT_BE_NULL, nameof(query));
 
             this.value = value;
             IsLeaf = false;
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/ProximityQueryNode.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/ProximityQueryNode.cs
index 40fa7ba..45fe048 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/ProximityQueryNode.cs
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/ProximityQueryNode.cs
@@ -1,6 +1,5 @@
 using Lucene.Net.QueryParsers.Flexible.Core.Messages;
 using Lucene.Net.QueryParsers.Flexible.Core.Parser;
-using Lucene.Net.QueryParsers.Flexible.Messages;
 using System;
 using System.Collections.Generic;
 using System.Text;
@@ -71,9 +70,10 @@ namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes
             {
                 if (distance <= 0)
                 {
-                    throw new QueryNodeError(new Message(
-                        QueryParserMessages.PARAMETER_VALUE_NOT_SUPPORTED, "distance",
-                        distance));
+                    // LUCENENET: Factored out NLS/Message/IMessage so end users can optionally utilize the built-in .NET localization.
+                    // LUCENENET: Added paramName parameter and changed the error message.
+                    // However, we still need this to be an error type so it is not caught in StandardSyntaxParser.
+                    throw new QueryNodeError(QueryParserMessages.NUMBER_CANNOT_BE_NEGATIVE, nameof(distance));
                 }
                 else
                 {
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/QueryNodeImpl.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/QueryNodeImpl.cs
index 37de4e2..be6599d 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/QueryNodeImpl.cs
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/QueryNodeImpl.cs
@@ -1,7 +1,6 @@
 using Lucene.Net.QueryParsers.Flexible.Core.Messages;
 using Lucene.Net.QueryParsers.Flexible.Core.Parser;
 using Lucene.Net.QueryParsers.Flexible.Core.Util;
-using Lucene.Net.QueryParsers.Flexible.Messages;
 using System;
 using System.Collections.Generic;
 using System.Globalization;
@@ -60,8 +59,9 @@ namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes
         {
             if (IsLeaf || this.clauses == null || child == null)
             {
-                throw new ArgumentException(NLS
-                    .GetLocalizedMessage(QueryParserMessages.NODE_ACTION_NOT_SUPPORTED));
+                // LUCENENET: Factored out NLS/Message/IMessage so end users can optionally utilize the built-in .NET localization.
+                throw new ArgumentException(
+                    QueryParserMessages.NODE_ACTION_NOT_SUPPORTED);
             }
 
             this.clauses.Add(child);
@@ -72,8 +72,9 @@ namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes
         {
             if (IsLeaf || this.clauses == null)
             {
-                throw new ArgumentException(NLS
-                    .GetLocalizedMessage(QueryParserMessages.NODE_ACTION_NOT_SUPPORTED));
+                // LUCENENET: Factored out NLS/Message/IMessage so end users can optionally utilize the built-in .NET localization.
+                throw new ArgumentException(
+                    QueryParserMessages.NODE_ACTION_NOT_SUPPORTED);
             }
 
             foreach (IQueryNode child in children)
@@ -92,19 +93,8 @@ namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes
         {
             if (IsLeaf || this.clauses == null)
             {
-                var factory = NLS.GetResourceManagerFactory();
-                ResourceManager bundle = factory.Create(typeof(QueryParserMessages));
-                string message;
-                try
-                {
-                    message = bundle.GetString(QueryParserMessages.NODE_ACTION_NOT_SUPPORTED);
-                }
-                finally
-                {
-                    factory.Release(bundle);
-                }
-
-                throw new ArgumentException(message);
+                // LUCENENET: Factored out NLS/Message/IMessage so end users can optionally utilize the built-in .NET localization.
+                throw new ArgumentException(QueryParserMessages.NODE_ACTION_NOT_SUPPORTED);
             }
 
             // reset parent value
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/SlopQueryNode.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/SlopQueryNode.cs
index 664cc1d..71f0c7e 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/SlopQueryNode.cs
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/SlopQueryNode.cs
@@ -1,6 +1,5 @@
 using Lucene.Net.QueryParsers.Flexible.Core.Messages;
 using Lucene.Net.QueryParsers.Flexible.Core.Parser;
-using Lucene.Net.QueryParsers.Flexible.Messages;
 
 namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes
 {
@@ -42,11 +41,11 @@ namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes
         /// <param name="value">slop value</param>
         public SlopQueryNode(IQueryNode query, int value)
         {
-            if (query == null)
-            {
-                throw new QueryNodeError(new Message(
-                    QueryParserMessages.NODE_ACTION_NOT_SUPPORTED, "query", "null"));
-            }
+            // LUCENENET: Factored out NLS/Message/IMessage so end users can optionally utilize the built-in .NET localization.
+            // LUCENENET: Added paramName parameter and changed to the same error message as the default of ArgumentNullException.
+            // However, we still need this to be an error type so it is not caught in StandardSyntaxParser.
+            if (query is null)
+                throw new QueryNodeError(QueryParserMessages.ARGUMENT_CANNOT_BE_NULL, nameof(query));
 
             this.value = value;
             IsLeaf = false;
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/QueryNodeError.cs b/src/Lucene.Net.QueryParser/Flexible/Core/QueryNodeError.cs
index 329d306..b02e2d1 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Core/QueryNodeError.cs
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/QueryNodeError.cs
@@ -1,9 +1,8 @@
-using Lucene.Net.QueryParsers.Flexible.Messages;
-using System;
+using System;
 #if FEATURE_SERIALIZABLE_EXCEPTIONS
 using System.Runtime.Serialization;
-using System.Security.Permissions;
 #endif
+#nullable enable
 
 namespace Lucene.Net.QueryParsers.Flexible.Core
 {
@@ -25,54 +24,78 @@ namespace Lucene.Net.QueryParsers.Flexible.Core
      */
 
     /// <summary>
-    /// Error class with NLS support
+    /// A query node error.
     /// </summary>
-    /// <seealso cref="NLS"/>
-    /// <seealso cref="IMessage"/>
     // LUCENENET: It is no longer good practice to use binary serialization. 
     // See: https://github.com/dotnet/corefx/issues/23584#issuecomment-325724568
 #if FEATURE_SERIALIZABLE_EXCEPTIONS
     [Serializable]
 #endif
-    public class QueryNodeError : Exception, INLSException, IError // LUCENENET specific: Added IError for identification of the Java superclass in .NET
+    // LUCENENET specific: Added IError for identification of the Java superclass in .NET.
+    // LUCENENET specific: Subclassed ArgumentException, since in all cases, we are validating arguments. However, this exception is also filtered using the IsException() extension method in catch blocks.
+    // LUCENENET specific: Refactored constructors to be more like a .NET type and eliminated IMessage/NLS support.
+    public class QueryNodeError : ArgumentException, IError
     {
-        private readonly IMessage message; // LUCENENET: marked readonly
-
         /// <summary>
-        /// 
+        /// Initializes a new instance of <see cref="QueryNodeError"/>
+        /// with the specified <paramref name="message"/> and <paramref name="paramName"/>.
         /// </summary>
-        /// <param name="message">NLS Message Object</param>
-        public QueryNodeError(IMessage message)
-            : base(message.Key)
+        /// <param name="paramName">The name of the parameter that caused the current error.</param>
+        /// <param name="message">The message that describes the error.</param>
+        public QueryNodeError(string? message, string? paramName)
+            : base(message, paramName)
         {
-            this.message = message;
+        }
 
+        /// <summary>
+        /// Initializes a new instance of <see cref="QueryNodeError"/>
+        /// with the specified <paramref name="message"/>, <paramref name="paramName"/> and <paramref name="innerException"/>.
+        /// </summary>
+        /// <param name="paramName">The name of the parameter that caused the current error.</param>
+        /// <param name="message">The message that describes the error.</param>
+        /// <param name="innerException">The exception that is the cause of the current exception.
+        /// If the <paramref name="innerException"/> parameter is not a <c>null</c> reference, the
+        /// current exception is raised in a catch block that handles the inner exception.</param>
+        public QueryNodeError(string? message, string? paramName, Exception? innerException)
+            : base(message, paramName, innerException)
+        {
         }
 
         /// <summary>
-        /// 
+        /// Initializes a new instance of <see cref="QueryNodeError"/>
+        /// with the specified <paramref name="message"/>.
         /// </summary>
-        /// <param name="throwable">An exception instance to wrap</param>
-        public QueryNodeError(Exception throwable)
-            : base(throwable.Message, throwable)
+        /// <param name="message">The message that describes the error.</param>
+        public QueryNodeError(string? message)
+            : base(message)
         {
         }
 
         /// <summary>
-        /// 
+        /// Initializes a new instance of <see cref="QueryNodeError"/>
+        /// with a specified inner exception that is the cause of this exception.
         /// </summary>
-        /// <param name="message">NLS Message Object</param>
-        /// <param name="throwable">An exception instance to wrap</param>
-        public QueryNodeError(IMessage message, Exception throwable)
-            : base(message.Key, throwable)
+        /// <param name="innerException">The exception that is the cause of the current exception.
+        /// If the <paramref name="innerException"/> parameter is not a <c>null</c> reference, the
+        /// current exception is raised in a catch block that handles the inner exception.</param>
+        public QueryNodeError(Exception? innerException)
+            : base(innerException?.Message, innerException)
         {
-            this.message = message;
         }
 
-        // LUCENENET: For testing purposes
-        internal QueryNodeError(string message)
-            : base(message)
-        { }
+        /// <summary>
+        /// Initializes a new instance of <see cref="QueryNodeError"/>
+        /// with a specified error message and a reference to the inner exception
+        /// that is the cause of this exception.
+        /// </summary>
+        /// <param name="message">The message that describes the error.</param>
+        /// <param name="innerException">The exception that is the cause of the current exception.
+        /// If the <paramref name="innerException"/> parameter is not a <c>null</c> reference, the
+        /// current exception is raised in a catch block that handles the inner exception.</param>
+        public QueryNodeError(string? message, Exception? innerException)
+            : base(message, innerException)
+        {
+        }
 
 #if FEATURE_SERIALIZABLE_EXCEPTIONS
         /// <summary>
@@ -83,20 +106,7 @@ namespace Lucene.Net.QueryParsers.Flexible.Core
         protected QueryNodeError(SerializationInfo info, StreamingContext context)
             : base(info, context)
         {
-            message = (IMessage)info.GetValue("message", typeof(IMessage));
-        }
-
-        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
-        public override void GetObjectData(SerializationInfo info, StreamingContext context)
-        {
-            base.GetObjectData(info, context);
-            info.AddValue("message", message, typeof(IMessage));
         }
 #endif
-
-        /// <summary>
-        /// <see cref="INLSException.MessageObject"/> 
-        /// </summary>
-        public virtual IMessage MessageObject => this.message;
     }
 }
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/QueryNodeException.cs b/src/Lucene.Net.QueryParser/Flexible/Core/QueryNodeException.cs
index 29b9080..fec0003 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Core/QueryNodeException.cs
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/QueryNodeException.cs
@@ -1,11 +1,8 @@
-using Lucene.Net.QueryParsers.Flexible.Core.Messages;
-using Lucene.Net.QueryParsers.Flexible.Messages;
-using System;
-using System.Globalization;
+using System;
 #if FEATURE_SERIALIZABLE_EXCEPTIONS
 using System.Runtime.Serialization;
-using System.Security.Permissions;
 #endif
+#nullable enable
 
 namespace Lucene.Net.QueryParsers.Flexible.Core
 {
@@ -29,44 +26,49 @@ namespace Lucene.Net.QueryParsers.Flexible.Core
     /// <summary>
     /// This exception should be thrown if something wrong happens when dealing with
     /// <see cref="Nodes.IQueryNode"/>s.
-    /// <para>
-    /// It also supports NLS messages.
-    /// </para>
     /// </summary>
-    /// <seealso cref="IMessage"/>
-    /// <seealso cref="NLS"/>
-    /// <seealso cref="INLSException"/>
     /// <seealso cref="Nodes.IQueryNode"/>
     // LUCENENET: It is no longer good practice to use binary serialization. 
     // See: https://github.com/dotnet/corefx/issues/23584#issuecomment-325724568
 #if FEATURE_SERIALIZABLE_EXCEPTIONS
     [Serializable]
 #endif
-    public class QueryNodeException : Exception, INLSException
+    // LUCENENET specific: Refactored constructors to be more like a .NET type and eliminated IMessage/NLS support.
+    public class QueryNodeException : Exception
     {
-        protected IMessage m_message = new Message(QueryParserMessages.EMPTY_MESSAGE);
-
-        public QueryNodeException(IMessage message)
-            : base(message.Key)
+        /// <summary>
+        /// Initializes a new instance of <see cref="QueryNodeException"/>
+        /// with the specified <paramref name="message"/>.
+        /// </summary>
+        /// <param name="message">The message that describes the error.</param>
+        public QueryNodeException(string? message)
+            : base(message)
         {
-            this.m_message = message;
         }
 
-        public QueryNodeException(Exception throwable)
-            : base(throwable.Message, throwable)
+        /// <summary>
+        /// Initializes a new instance of <see cref="QueryNodeException"/>
+        /// with a specified inner exception
+        /// that is the cause of this exception.
+        /// </summary>
+        /// <param name="cause">An exception instance to wrap</param>
+        public QueryNodeException(Exception? cause)
+            : base(cause?.Message, cause)
         {
         }
 
-        public QueryNodeException(IMessage message, Exception throwable)
-            : base(message.Key, throwable)
+        /// <summary>
+        /// Initializes a new instance of <see cref="QueryNodeException"/>
+        /// with a specified error message and a reference to the inner exception
+        /// that is the cause of this exception.
+        /// </summary>
+        /// <param name="message">The message that describes the error.</param>
+        /// <param name="innerException">An exception instance to wrap</param>
+        public QueryNodeException(string? message, Exception? innerException)
+            : base(message, innerException)
         {
-            this.m_message = message;
         }
 
-        // LUCENENET: For testing purposes
-        internal QueryNodeException(string message)
-            : base(message)
-        { }
 
 #if FEATURE_SERIALIZABLE_EXCEPTIONS
         /// <summary>
@@ -77,34 +79,7 @@ namespace Lucene.Net.QueryParsers.Flexible.Core
         protected QueryNodeException(SerializationInfo info, StreamingContext context)
             : base(info, context)
         {
-            m_message = (IMessage)info.GetValue("m_message", typeof(IMessage));
-        }
-
-        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
-        public override void GetObjectData(SerializationInfo info, StreamingContext context)
-        {
-            base.GetObjectData(info, context);
-            info.AddValue("m_message", m_message, typeof(IMessage));
         }
 #endif
-
-        public virtual IMessage MessageObject => this.m_message;
-
-        public override string Message => GetLocalizedMessage();
-
-        public virtual string GetLocalizedMessage()
-        {
-            return GetLocalizedMessage(CultureInfo.InvariantCulture);
-        }
-
-        public virtual string GetLocalizedMessage(CultureInfo locale)
-        {
-            return this.m_message.GetLocalizedMessage(locale);
-        }
-
-        public override string ToString()
-        {
-            return this.m_message.Key + ": " + GetLocalizedMessage();
-        }
     }
 }
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/QueryNodeParseException.cs b/src/Lucene.Net.QueryParser/Flexible/Core/QueryNodeParseException.cs
index 8b9f615..df3faf7 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Core/QueryNodeParseException.cs
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/QueryNodeParseException.cs
@@ -1,10 +1,9 @@
-using Lucene.Net.QueryParsers.Flexible.Core.Messages;
-using Lucene.Net.QueryParsers.Flexible.Messages;
-using System;
+using System;
 #if FEATURE_SERIALIZABLE_EXCEPTIONS
 using System.Runtime.Serialization;
 using System.Security.Permissions;
 #endif
+#nullable enable
 
 namespace Lucene.Net.QueryParsers.Flexible.Core
 {
@@ -37,36 +36,44 @@ namespace Lucene.Net.QueryParsers.Flexible.Core
 #if FEATURE_SERIALIZABLE_EXCEPTIONS
     [Serializable]
 #endif
+    // LUCENENET specific: Refactored constructors to be more like a .NET type and eliminated IMessage/NLS support.
     public class QueryNodeParseException : QueryNodeException
     {
-        private string query;
+#if FEATURE_SERIALIZABLE_EXCEPTIONS
+        [NonSerialized]
+#endif
+        private string? query;
 
+#if FEATURE_SERIALIZABLE_EXCEPTIONS
+        [NonSerialized]
+#endif
         private int beginColumn = -1;
 
+#if FEATURE_SERIALIZABLE_EXCEPTIONS
+        [NonSerialized]
+#endif
         private int beginLine = -1;
 
+#if FEATURE_SERIALIZABLE_EXCEPTIONS
+        [NonSerialized]
+#endif
         private string errorToken = "";
 
-        public QueryNodeParseException(IMessage message)
+        public QueryNodeParseException(string? message)
             : base(message)
         {
         }
 
-        public QueryNodeParseException(Exception throwable)
-            : base(throwable)
+        public QueryNodeParseException(Exception? cause)
+            : base(cause)
         {
         }
 
-        public QueryNodeParseException(IMessage message, Exception throwable)
-            : base(message, throwable)
+        public QueryNodeParseException(string? message, Exception? innerException)
+            : base(message, innerException)
         {
         }
 
-        // LUCENENET: For testing purposes
-        internal QueryNodeParseException(string message)
-            : base(message)
-        { }
-
 #if FEATURE_SERIALIZABLE_EXCEPTIONS
         /// <summary>
         /// Initializes a new instance of this class with serialized data.
@@ -93,28 +100,22 @@ namespace Lucene.Net.QueryParsers.Flexible.Core
         }
 #endif
 
-        public virtual void SetQuery(string query)
+        public virtual string? Query
         {
-            this.query = query;
-            this.m_message = new Message(
-                QueryParserMessages.INVALID_SYNTAX_CANNOT_PARSE, query, "");
+            get => this.query;
+            set => this.query = value; // LUCENENET specific - set the message only in the constructor
         }
 
-        public virtual string Query => this.query;
-
         /// <summary>
         /// The errorToken in the query
         /// </summary>
         public virtual string ErrorToken
         {
             get => this.errorToken;
-            protected set => this.errorToken = value;
+            protected set => this.errorToken = value ?? throw new ArgumentNullException(nameof(ErrorToken)); // LUCENENET specific - added null guard clause
         }
 
-        public virtual void SetNonLocalizedMessage(IMessage message)
-        {
-            this.m_message = message;
-        }
+        // LUCENENET specific - removed SetNonLocalizedMessage() because we only set the message in the constructor
 
         /// <summary>
         /// For EndOfLine and EndOfFile ("&lt;EOF&gt;") parsing problems the last char in the
diff --git a/src/Lucene.Net.QueryParser/Flexible/Standard/Builders/AnyQueryNodeBuilder.cs b/src/Lucene.Net.QueryParser/Flexible/Standard/Builders/AnyQueryNodeBuilder.cs
index 339cb09..1ed4d46 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Standard/Builders/AnyQueryNodeBuilder.cs
+++ b/src/Lucene.Net.QueryParser/Flexible/Standard/Builders/AnyQueryNodeBuilder.cs
@@ -2,7 +2,6 @@
 using Lucene.Net.QueryParsers.Flexible.Core.Builders;
 using Lucene.Net.QueryParsers.Flexible.Core.Messages;
 using Lucene.Net.QueryParsers.Flexible.Core.Nodes;
-using Lucene.Net.QueryParsers.Flexible.Messages;
 using Lucene.Net.Search;
 using System.Collections.Generic;
 
@@ -59,11 +58,13 @@ namespace Lucene.Net.QueryParsers.Flexible.Standard.Builders
                         }
                         catch (BooleanQuery.TooManyClausesException ex)
                         {
-                            throw new QueryNodeException(new Message(
+                            // LUCENENET: Factored out NLS/Message/IMessage so end users can optionally utilize the built-in .NET localization.
+                            throw new QueryNodeException(
                                 /*
                                  * IQQQ.Q0028E_TOO_MANY_BOOLEAN_CLAUSES,
                                  * BooleanQuery.getMaxClauseCount()
-                                 */QueryParserMessages.EMPTY_MESSAGE), ex);
+                                 */
+                                QueryParserMessages.EMPTY_MESSAGE, ex);
                         }
                     }
                 }
diff --git a/src/Lucene.Net.QueryParser/Flexible/Standard/Builders/BooleanQueryNodeBuilder.cs b/src/Lucene.Net.QueryParser/Flexible/Standard/Builders/BooleanQueryNodeBuilder.cs
index 8385685..64f19c3 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Standard/Builders/BooleanQueryNodeBuilder.cs
+++ b/src/Lucene.Net.QueryParser/Flexible/Standard/Builders/BooleanQueryNodeBuilder.cs
@@ -2,7 +2,6 @@
 using Lucene.Net.QueryParsers.Flexible.Core.Builders;
 using Lucene.Net.QueryParsers.Flexible.Core.Messages;
 using Lucene.Net.QueryParsers.Flexible.Core.Nodes;
-using Lucene.Net.QueryParsers.Flexible.Messages;
 using Lucene.Net.QueryParsers.Flexible.Standard.Parser;
 using Lucene.Net.Search;
 using System.Collections.Generic;
@@ -66,7 +65,8 @@ namespace Lucene.Net.QueryParsers.Flexible.Standard.Builders
                         }
                         catch (BooleanQuery.TooManyClausesException ex)
                         {
-                            throw new QueryNodeException(new Message(
+                            // LUCENENET: Factored out NLS/Message/IMessage so end users can optionally utilize the built-in .NET localization.
+                            throw new QueryNodeException(string.Format(
                                 QueryParserMessages.TOO_MANY_BOOLEAN_CLAUSES, BooleanQuery
                                     .MaxClauseCount, queryNode
                                     .ToQueryString(new EscapeQuerySyntax())), ex);
diff --git a/src/Lucene.Net.QueryParser/Flexible/Standard/Builders/MatchAllDocsQueryNodeBuilder.cs b/src/Lucene.Net.QueryParser/Flexible/Standard/Builders/MatchAllDocsQueryNodeBuilder.cs
index 791b23e..79e5cd7 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Standard/Builders/MatchAllDocsQueryNodeBuilder.cs
+++ b/src/Lucene.Net.QueryParser/Flexible/Standard/Builders/MatchAllDocsQueryNodeBuilder.cs
@@ -1,7 +1,6 @@
 using Lucene.Net.QueryParsers.Flexible.Core;
 using Lucene.Net.QueryParsers.Flexible.Core.Messages;
 using Lucene.Net.QueryParsers.Flexible.Core.Nodes;
-using Lucene.Net.QueryParsers.Flexible.Messages;
 using Lucene.Net.QueryParsers.Flexible.Standard.Parser;
 using Lucene.Net.Search;
 
@@ -40,7 +39,8 @@ namespace Lucene.Net.QueryParsers.Flexible.Standard.Builders
             // validates node
             if (!(queryNode is MatchAllDocsQueryNode))
             {
-                throw new QueryNodeException(new Message(
+                // LUCENENET: Factored out NLS/Message/IMessage so end users can optionally utilize the built-in .NET localization.
+                throw new QueryNodeException(string.Format(
                     QueryParserMessages.LUCENE_QUERY_CONVERSION_ERROR, queryNode
                         .ToQueryString(new EscapeQuerySyntax()), queryNode.GetType()
                         .Name));
diff --git a/src/Lucene.Net.QueryParser/Flexible/Standard/Builders/MatchNoDocsQueryNodeBuilder.cs b/src/Lucene.Net.QueryParser/Flexible/Standard/Builders/MatchNoDocsQueryNodeBuilder.cs
index 8da02f7..67ce7bd 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Standard/Builders/MatchNoDocsQueryNodeBuilder.cs
+++ b/src/Lucene.Net.QueryParser/Flexible/Standard/Builders/MatchNoDocsQueryNodeBuilder.cs
@@ -1,7 +1,6 @@
 using Lucene.Net.QueryParsers.Flexible.Core;
 using Lucene.Net.QueryParsers.Flexible.Core.Messages;
 using Lucene.Net.QueryParsers.Flexible.Core.Nodes;
-using Lucene.Net.QueryParsers.Flexible.Messages;
 using Lucene.Net.QueryParsers.Flexible.Standard.Parser;
 using Lucene.Net.Search;
 
@@ -40,7 +39,8 @@ namespace Lucene.Net.QueryParsers.Flexible.Standard.Builders
             // validates node
             if (!(queryNode is MatchNoDocsQueryNode))
             {
-                throw new QueryNodeException(new Message(
+                // LUCENENET: Factored out NLS/Message/IMessage so end users can optionally utilize the built-in .NET localization.
+                throw new QueryNodeException(string.Format(
                     QueryParserMessages.LUCENE_QUERY_CONVERSION_ERROR, queryNode
                         .ToQueryString(new EscapeQuerySyntax()), queryNode.GetType()
                         .Name));
diff --git a/src/Lucene.Net.QueryParser/Flexible/Standard/Builders/NumericRangeQueryNodeBuilder.cs b/src/Lucene.Net.QueryParser/Flexible/Standard/Builders/NumericRangeQueryNodeBuilder.cs
index ae8197a..37b4e48 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Standard/Builders/NumericRangeQueryNodeBuilder.cs
+++ b/src/Lucene.Net.QueryParser/Flexible/Standard/Builders/NumericRangeQueryNodeBuilder.cs
@@ -3,7 +3,6 @@ using Lucene.Net.QueryParsers.Flexible.Core;
 using Lucene.Net.QueryParsers.Flexible.Core.Messages;
 using Lucene.Net.QueryParsers.Flexible.Core.Nodes;
 using Lucene.Net.QueryParsers.Flexible.Core.Util;
-using Lucene.Net.QueryParsers.Flexible.Messages;
 using Lucene.Net.QueryParsers.Flexible.Standard.Config;
 using Lucene.Net.QueryParsers.Flexible.Standard.Nodes;
 using Lucene.Net.Search;
@@ -83,7 +82,8 @@ namespace Lucene.Net.QueryParsers.Flexible.Standard.Builders
                         maxInclusive);
 
                 default:
-                    throw new QueryNodeException(new Message(
+                    // LUCENENET: Factored out NLS/Message/IMessage so end users can optionally utilize the built-in .NET localization.
+                    throw new QueryNodeException(string.Format(
                       QueryParserMessages.UNSUPPORTED_NUMERIC_DATA_TYPE, numberType));
             }
         }
diff --git a/src/Lucene.Net.QueryParser/Flexible/Standard/Builders/StandardBooleanQueryNodeBuilder.cs b/src/Lucene.Net.QueryParser/Flexible/Standard/Builders/StandardBooleanQueryNodeBuilder.cs
index d30e03f..8d93f16 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Standard/Builders/StandardBooleanQueryNodeBuilder.cs
+++ b/src/Lucene.Net.QueryParser/Flexible/Standard/Builders/StandardBooleanQueryNodeBuilder.cs
@@ -2,7 +2,6 @@
 using Lucene.Net.QueryParsers.Flexible.Core.Builders;
 using Lucene.Net.QueryParsers.Flexible.Core.Messages;
 using Lucene.Net.QueryParsers.Flexible.Core.Nodes;
-using Lucene.Net.QueryParsers.Flexible.Messages;
 using Lucene.Net.QueryParsers.Flexible.Standard.Nodes;
 using Lucene.Net.QueryParsers.Flexible.Standard.Parser;
 using Lucene.Net.Search;
@@ -65,7 +64,8 @@ namespace Lucene.Net.QueryParsers.Flexible.Standard.Builders
                         }
                         catch (BooleanQuery.TooManyClausesException ex)
                         {
-                            throw new QueryNodeException(new Message(
+                            // LUCENENET: Factored out NLS/Message/IMessage so end users can optionally utilize the built-in .NET localization.
+                            throw new QueryNodeException(string.Format(
                                 QueryParserMessages.TOO_MANY_BOOLEAN_CLAUSES, BooleanQuery
                                     .MaxClauseCount, queryNode
                                     .ToQueryString(new EscapeQuerySyntax())), ex);
diff --git a/src/Lucene.Net.QueryParser/Flexible/Standard/Nodes/NumericRangeQueryNode.cs b/src/Lucene.Net.QueryParser/Flexible/Standard/Nodes/NumericRangeQueryNode.cs
index 34e4d33..71b3d00 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Standard/Nodes/NumericRangeQueryNode.cs
+++ b/src/Lucene.Net.QueryParser/Flexible/Standard/Nodes/NumericRangeQueryNode.cs
@@ -1,6 +1,5 @@
 using Lucene.Net.QueryParsers.Flexible.Core;
 using Lucene.Net.QueryParsers.Flexible.Core.Messages;
-using Lucene.Net.QueryParsers.Flexible.Messages;
 using Lucene.Net.QueryParsers.Flexible.Standard.Config;
 using System;
 using System.Text;
@@ -71,8 +70,9 @@ namespace Lucene.Net.QueryParsers.Flexible.Standard.Nodes
             }
             else
             {
+                // LUCENENET: Factored out NLS/Message/IMessage so end users can optionally utilize the built-in .NET localization.
                 throw new QueryNodeException(
-                    new Message(
+                    string.Format(
                         QueryParserMessages.NUMBER_CLASS_NOT_SUPPORTED_BY_NUMERIC_RANGE_QUERY,
                         number.GetType()));
             }
diff --git a/src/Lucene.Net.QueryParser/Flexible/Standard/Parser/EscapeQuerySyntaxImpl.cs b/src/Lucene.Net.QueryParser/Flexible/Standard/Parser/EscapeQuerySyntaxImpl.cs
index 315e32b..a478fa3 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Standard/Parser/EscapeQuerySyntaxImpl.cs
+++ b/src/Lucene.Net.QueryParser/Flexible/Standard/Parser/EscapeQuerySyntaxImpl.cs
@@ -3,7 +3,6 @@ using J2N.Text;
 using Lucene.Net.QueryParsers.Flexible.Core.Messages;
 using Lucene.Net.QueryParsers.Flexible.Core.Parser;
 using Lucene.Net.QueryParsers.Flexible.Core.Util;
-using Lucene.Net.QueryParsers.Flexible.Messages;
 using System;
 using System.Globalization;
 using System.Text;
@@ -323,14 +322,16 @@ namespace Lucene.Net.QueryParsers.Flexible.Standard.Parser
 
             if (codePointMultiplier > 0)
             {
-                throw new ParseException(new Message(
-                    QueryParserMessages.INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION));
+                // LUCENENET: Factored out NLS/Message/IMessage so end users can optionally utilize the built-in .NET localization.
+                throw new ParseException(
+                    QueryParserMessages.INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION);
             }
 
             if (lastCharWasEscapeChar)
             {
-                throw new ParseException(new Message(
-                    QueryParserMessages.INVALID_SYNTAX_ESCAPE_CHARACTER));
+                // LUCENENET: Factored out NLS/Message/IMessage so end users can optionally utilize the built-in .NET localization.
+                throw new ParseException(
+                    QueryParserMessages.INVALID_SYNTAX_ESCAPE_CHARACTER);
             }
 
             return new UnescapedCharSequence(output, wasEscaped, 0, length);
@@ -357,7 +358,8 @@ namespace Lucene.Net.QueryParsers.Flexible.Standard.Parser
             }
             else
             {
-                throw new ParseException(new Message(
+                // LUCENENET: Factored out NLS/Message/IMessage so end users can optionally utilize the built-in .NET localization.
+                throw new ParseException(string.Format(
                     QueryParserMessages.INVALID_SYNTAX_ESCAPE_NONE_HEX_UNICODE, c));
             }
         }
diff --git a/src/Lucene.Net.QueryParser/Flexible/Standard/Parser/ParseException.cs b/src/Lucene.Net.QueryParser/Flexible/Standard/Parser/ParseException.cs
index 609cb55..519645d 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Standard/Parser/ParseException.cs
+++ b/src/Lucene.Net.QueryParser/Flexible/Standard/Parser/ParseException.cs
@@ -1,14 +1,15 @@
 using Lucene.Net.QueryParsers.Flexible.Core;
 using Lucene.Net.QueryParsers.Flexible.Core.Messages;
-using Lucene.Net.QueryParsers.Flexible.Messages;
 using Lucene.Net.Support;
 using System;
+using System.Collections.Generic;
 using System.Diagnostics.CodeAnalysis;
 #if FEATURE_SERIALIZABLE_EXCEPTIONS
 using System.Runtime.Serialization;
 using System.Security.Permissions;
 #endif
 using System.Text;
+#nullable enable
 
 namespace Lucene.Net.QueryParsers.Flexible.Standard.Parser
 {
@@ -43,22 +44,23 @@ namespace Lucene.Net.QueryParsers.Flexible.Standard.Parser
 #if FEATURE_SERIALIZABLE_EXCEPTIONS
     [Serializable]
 #endif
+    // LUCENENET specific: Refactored constructors to be more like a .NET type and eliminated IMessage/NLS support.
     public class ParseException : QueryNodeParseException
     {
         /// <summary>
-        /// This constructor is used by the method "generateParseException"
+        /// This constructor is used by the method "GenerateParseException"
         /// in the generated parser.  Calling this constructor generates
-        /// a new object of this type with the fields "currentToken",
-        /// "expectedTokenSequences", and "tokenImage" set.
+        /// a new object of this type with the fields <see cref="CurrentToken"/>,
+        /// <see cref="ExpectedTokenSequences"/>, and <see cref="TokenImage"/> set.
         /// </summary>
-        public ParseException(Token currentTokenVal,
-            int[][] expectedTokenSequencesVal, string[] tokenImageVal)
-            : base(new Message(QueryParserMessages.INVALID_SYNTAX, Initialize(
-                currentTokenVal, expectedTokenSequencesVal, tokenImageVal)))
+        public ParseException(Token currentToken,
+            int[][] expectedTokenSequences, string[] tokenImage)
+            : base(string.Format(QueryParserMessages.INVALID_SYNTAX, Initialize(
+                currentToken, expectedTokenSequences, tokenImage)))
         {
-            this.CurrentToken = currentTokenVal;
-            this.ExpectedTokenSequences = expectedTokenSequencesVal;
-            this.TokenImage = tokenImageVal;
+            this.CurrentToken = currentToken;
+            this.ExpectedTokenSequences = expectedTokenSequences;
+            this.TokenImage = tokenImage;
         }
 
         /// <summary>
@@ -71,18 +73,27 @@ namespace Lucene.Net.QueryParsers.Flexible.Standard.Parser
         /// these constructors.
         /// </summary>
         public ParseException()
-            : base(new Message(QueryParserMessages.INVALID_SYNTAX, "Error"))
+            : base(string.Format(QueryParserMessages.INVALID_SYNTAX, "Error"))
         {
         }
 
         /// <summary>
         /// Constructor with message.
         /// </summary>
-        public ParseException(IMessage message)
+        public ParseException(string? message)
             : base(message)
         {
         }
 
+        /// <summary>
+        /// Constructor with message and inner exception.
+        /// </summary>
+        // LUCENENET specific - to allow inner exception to be added to the stack trace.
+        public ParseException(string? message, Exception? innerException)
+            : base(message, innerException)
+        {
+        }
+
 #if FEATURE_SERIALIZABLE_EXCEPTIONS
         /// <summary>
         /// Initializes a new instance of this class with serialized data.
@@ -112,7 +123,7 @@ namespace Lucene.Net.QueryParsers.Flexible.Standard.Parser
         /// this object has been created due to a parse error, the token
         /// followng this token will (therefore) be the first error token.
         /// </summary>
-        public Token CurrentToken { get; set; }
+        public Token? CurrentToken { get; private set; }
 
         /// <summary>
         /// Each entry in this array is an array of integers.  Each array
@@ -121,7 +132,7 @@ namespace Lucene.Net.QueryParsers.Flexible.Standard.Parser
         /// </summary>
         [WritableArray]
         [SuppressMessage("Microsoft.Performance", "CA1819", Justification = "Lucene's design requires some writable array properties")]
-        public int[][] ExpectedTokenSequences { get; set; }
+        public int[][]? ExpectedTokenSequences { get; private set; }
 
         /// <summary>
         /// This is a reference to the "tokenImage" array of the generated
@@ -130,7 +141,7 @@ namespace Lucene.Net.QueryParsers.Flexible.Standard.Parser
         /// </summary>
         [WritableArray]
         [SuppressMessage("Microsoft.Performance", "CA1819", Justification = "Lucene's design requires some writable array properties")]
-        public string[] TokenImage { get; set; }
+        public string[]? TokenImage { get; private set; }
 
         /// <summary>
         /// It uses <paramref name="currentToken"/> and <paramref name="expectedTokenSequences"/> to generate a parse
@@ -144,13 +155,13 @@ namespace Lucene.Net.QueryParsers.Flexible.Standard.Parser
         /// <param name="tokenImage"></param>
         /// <returns></returns>
         private static string Initialize(Token currentToken,
-                                 int[][] expectedTokenSequences,
+                                 IList<int[]> expectedTokenSequences,
                                  string[] tokenImage)
         {
             string eol = Environment.NewLine;
             StringBuilder expected = new StringBuilder();
             int maxSize = 0;
-            for (int i = 0; i < expectedTokenSequences.Length; i++)
+            for (int i = 0; i < expectedTokenSequences.Count; i++)
             {
                 if (maxSize < expectedTokenSequences[i].Length)
                 {
@@ -184,7 +195,7 @@ namespace Lucene.Net.QueryParsers.Flexible.Standard.Parser
             }
             retval += "\" at line " + currentToken.Next.BeginLine + ", column " + currentToken.Next.BeginColumn;
             retval += "." + eol;
-            if (expectedTokenSequences.Length == 1)
+            if (expectedTokenSequences.Count == 1)
             {
                 retval += "Was expecting:" + eol + "    ";
             }
@@ -196,10 +207,7 @@ namespace Lucene.Net.QueryParsers.Flexible.Standard.Parser
             return retval;
         }
 
-        /// <summary>
-        /// The end of line string for this machine.
-        /// </summary>
-        protected string m_eol = Environment.NewLine;
+        // LUCENENET: Removed eol field, since this is available on Environment.NewLine;
 
         /// <summary>
         /// Used to convert raw characters to their escaped version
diff --git a/src/Lucene.Net.QueryParser/Flexible/Standard/Parser/StandardSyntaxParser.cs b/src/Lucene.Net.QueryParser/Flexible/Standard/Parser/StandardSyntaxParser.cs
index 43af963..ca61adb 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Standard/Parser/StandardSyntaxParser.cs
+++ b/src/Lucene.Net.QueryParser/Flexible/Standard/Parser/StandardSyntaxParser.cs
@@ -2,7 +2,6 @@
 using Lucene.Net.QueryParsers.Flexible.Core.Messages;
 using Lucene.Net.QueryParsers.Flexible.Core.Nodes;
 using Lucene.Net.QueryParsers.Flexible.Core.Parser;
-using Lucene.Net.QueryParsers.Flexible.Messages;
 using Lucene.Net.QueryParsers.Flexible.Standard.Nodes;
 using System;
 using System.Collections.Generic;
@@ -69,16 +68,15 @@ namespace Lucene.Net.QueryParsers.Flexible.Standard.Parser
             }
             catch (Lucene.Net.QueryParsers.Flexible.Standard.Parser.ParseException tme) // LUCENENET: Flexible QueryParser has its own ParseException that is different than the one in Support
             {
-                tme.SetQuery(query);
-                throw; // LUCENENET: CA2200: Rethrow to preserve stack details (https://docs.microsoft.com/en-us/visualstudio/code-quality/ca2200-rethrow-to-preserve-stack-details)
+                // LUCENENET specific - removed NLS support (since .NET already has localization) so we need to re-throw the exception here with a different message. However,
+                // unlike the original Lucene code we also preserve the original message in the InnerException.
+                throw new Lucene.Net.QueryParsers.Flexible.Standard.Parser.ParseException(string.Format(QueryParserMessages.INVALID_SYNTAX_CANNOT_PARSE, query, string.Empty), tme) { Query = query };
             }
             catch (Exception tme) when (tme.IsError())
             {
-                IMessage message = new Message(QueryParserMessages.INVALID_SYNTAX_CANNOT_PARSE, query, tme.Message);
-                QueryNodeParseException e = new QueryNodeParseException(tme);
-                e.SetQuery(query);
-                e.SetNonLocalizedMessage(message);
-                throw e;
+                // LUCENENET specific - removed NLS support (since .NET already has localization) so we pass everything through the constructor of the
+                // exception.
+                throw new QueryNodeParseException(string.Format(QueryParserMessages.INVALID_SYNTAX_CANNOT_PARSE, query, tme.Message), tme) { Query = query };
             }
         }
 
@@ -637,11 +635,11 @@ namespace Lucene.Net.QueryParsers.Flexible.Standard.Parser
                         float fms = float.TryParse(fuzzySlop.Image.Substring(1), NumberStyles.Float, CultureInfo.InvariantCulture, out float temp) ? temp : defaultMinSimilarity;
                         if (fms < 0.0f)
                         {
-                            { if (true) throw new ParseException(new Message(QueryParserMessages.INVALID_SYNTAX_FUZZY_LIMITS)); }
+                            { if (true) throw new ParseException(QueryParserMessages.INVALID_SYNTAX_FUZZY_LIMITS); }
                         }
                         else if (fms >= 1.0f && fms != (int)fms)
                         {
-                            { if (true) throw new ParseException(new Message(QueryParserMessages.INVALID_SYNTAX_FUZZY_EDITS)); }
+                            { if (true) throw new ParseException(QueryParserMessages.INVALID_SYNTAX_FUZZY_EDITS); }
                         }
                         q = new FuzzyQueryNode(field, EscapeQuerySyntax.DiscardEscapeChar(term.Image), fms, term.BeginColumn, term.EndColumn);
                     }
diff --git a/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/AllowLeadingWildcardProcessor.cs b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/AllowLeadingWildcardProcessor.cs
index 253a51e..3ce4f55 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/AllowLeadingWildcardProcessor.cs
+++ b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/AllowLeadingWildcardProcessor.cs
@@ -3,7 +3,6 @@ using Lucene.Net.QueryParsers.Flexible.Core.Messages;
 using Lucene.Net.QueryParsers.Flexible.Core.Nodes;
 using Lucene.Net.QueryParsers.Flexible.Core.Processors;
 using Lucene.Net.QueryParsers.Flexible.Core.Util;
-using Lucene.Net.QueryParsers.Flexible.Messages;
 using Lucene.Net.QueryParsers.Flexible.Standard.Config;
 using Lucene.Net.QueryParsers.Flexible.Standard.Nodes;
 using Lucene.Net.QueryParsers.Flexible.Standard.Parser;
@@ -72,7 +71,8 @@ namespace Lucene.Net.QueryParsers.Flexible.Standard.Processors
                     {
                         case '*':
                         case '?':
-                            throw new QueryNodeException(new Message(
+                            // LUCENENET: Factored out NLS/Message/IMessage so end users can optionally utilize the built-in .NET localization.
+                            throw new QueryNodeException(string.Format(
                                 QueryParserMessages.LEADING_WILDCARD_NOT_ALLOWED, node
                                     .ToQueryString(new EscapeQuerySyntax())));
                     }
diff --git a/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/NumericQueryNodeProcessor.cs b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/NumericQueryNodeProcessor.cs
index 8475cd7..861db16 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/NumericQueryNodeProcessor.cs
+++ b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/NumericQueryNodeProcessor.cs
@@ -4,7 +4,6 @@ using Lucene.Net.QueryParsers.Flexible.Core.Config;
 using Lucene.Net.QueryParsers.Flexible.Core.Messages;
 using Lucene.Net.QueryParsers.Flexible.Core.Nodes;
 using Lucene.Net.QueryParsers.Flexible.Core.Processors;
-using Lucene.Net.QueryParsers.Flexible.Messages;
 using Lucene.Net.QueryParsers.Flexible.Standard.Config;
 using Lucene.Net.QueryParsers.Flexible.Standard.Nodes;
 using Lucene.Net.Util;
@@ -91,7 +90,8 @@ namespace Lucene.Net.QueryParsers.Flexible.Standard.Processors
                                 }
                                 catch (FormatException e) // LUCENENET: In .NET we are expecting the framework to throw FormatException, not ParseException
                                 {
-                                    throw new QueryNodeParseException(new Message(
+                                    // LUCENENET: Factored out NLS/Message/IMessage so end users can optionally utilize the built-in .NET localization.
+                                    throw new QueryNodeParseException(string.Format(
                                         QueryParserMessages.COULD_NOT_PARSE_NUMBER, fieldNode
                                             .GetTextAsString(), numberFormat.GetType()
                                             .AssemblyQualifiedName), e);
@@ -116,7 +116,8 @@ namespace Lucene.Net.QueryParsers.Flexible.Standard.Processors
                             }
                             else
                             {
-                                throw new QueryNodeParseException(new Message(
+                                // LUCENENET: Factored out NLS/Message/IMessage so end users can optionally utilize the built-in .NET localization.
+                                throw new QueryNodeParseException(string.Format(
                                     QueryParserMessages.NUMERIC_CANNOT_BE_EMPTY, fieldNode.GetFieldAsString()));
                             }
 
diff --git a/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/NumericRangeQueryNodeProcessor.cs b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/NumericRangeQueryNodeProcessor.cs
index c1e2dda..2f89e68 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/NumericRangeQueryNodeProcessor.cs
+++ b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/NumericRangeQueryNodeProcessor.cs
@@ -5,7 +5,6 @@ using Lucene.Net.QueryParsers.Flexible.Core.Messages;
 using Lucene.Net.QueryParsers.Flexible.Core.Nodes;
 using Lucene.Net.QueryParsers.Flexible.Core.Processors;
 using Lucene.Net.QueryParsers.Flexible.Core.Util;
-using Lucene.Net.QueryParsers.Flexible.Messages;
 using Lucene.Net.QueryParsers.Flexible.Standard.Config;
 using Lucene.Net.QueryParsers.Flexible.Standard.Nodes;
 using Lucene.Net.Util;
@@ -89,7 +88,8 @@ namespace Lucene.Net.QueryParsers.Flexible.Standard.Processors
                                 }
                                 catch (FormatException e) // LUCENENET: In .NET we are expecting the framework to throw FormatException, not ParseException
                                 {
-                                    throw new QueryNodeParseException(new Message(
+                                    // LUCENENET: Factored out NLS/Message/IMessage so end users can optionally utilize the built-in .NET localization.
+                                    throw new QueryNodeParseException(string.Format(
                                         QueryParserMessages.COULD_NOT_PARSE_NUMBER, lower
                                             .GetTextAsString(), numberFormat.ToString()), e);
                                 }
@@ -103,7 +103,8 @@ namespace Lucene.Net.QueryParsers.Flexible.Standard.Processors
                                 }
                                 catch (FormatException e) // LUCENENET: In .NET we are expecting the framework to throw FormatException, not ParseException
                                 {
-                                    throw new QueryNodeParseException(new Message(
+                                    // LUCENENET: Factored out NLS/Message/IMessage so end users can optionally utilize the built-in .NET localization.
+                                    throw new QueryNodeParseException(string.Format(
                                         QueryParserMessages.COULD_NOT_PARSE_NUMBER, upper
                                             .GetTextAsString(), numberFormat.ToString()), e);
                                 }
diff --git a/src/Lucene.Net.QueryParser/Lucene.Net.QueryParser.csproj b/src/Lucene.Net.QueryParser/Lucene.Net.QueryParser.csproj
index de5097b..20f51fe 100644
--- a/src/Lucene.Net.QueryParser/Lucene.Net.QueryParser.csproj
+++ b/src/Lucene.Net.QueryParser/Lucene.Net.QueryParser.csproj
@@ -27,6 +27,8 @@
     <TargetFrameworks>netstandard2.1;netstandard2.0</TargetFrameworks>
     <TargetFrameworks Condition="$([MSBuild]::IsOsPlatform('Windows'))">$(TargetFrameworks);net45</TargetFrameworks>
 
+    <RootNamespace>Lucene.Net.QueryParsers</RootNamespace>
+    
     <AssemblyTitle>Lucene.Net.QueryParser</AssemblyTitle>
     <Description>Query parsers and parsing framework for the Lucene.Net full-text search engine library from The Apache Software Foundation.</Description>
     <PackageTags>$(PackageTags);query;queryparser</PackageTags>
@@ -50,4 +52,19 @@
     <InternalsVisibleTo Include="Lucene.Net.Tests.QueryParser" />
   </ItemGroup>
 
+  <ItemGroup>
+    <Compile Update="Flexible\Core\Messages\QueryParserMessages.Designer.cs">
+      <DesignTime>True</DesignTime>
+      <AutoGen>True</AutoGen>
+      <DependentUpon>QueryParserMessages.resx</DependentUpon>
+    </Compile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <EmbeddedResource Update="Flexible\Core\Messages\QueryParserMessages.resx">
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>QueryParserMessages.Designer.cs</LastGenOutput>
+    </EmbeddedResource>
+  </ItemGroup>
+
 </Project>
diff --git a/src/Lucene.Net.TestFramework/Support/ExceptionHandling/ExceptionExtensions.cs b/src/Lucene.Net.TestFramework/Support/ExceptionHandling/ExceptionExtensions.cs
index f4fdd2c..e31d55d 100644
--- a/src/Lucene.Net.TestFramework/Support/ExceptionHandling/ExceptionExtensions.cs
+++ b/src/Lucene.Net.TestFramework/Support/ExceptionHandling/ExceptionExtensions.cs
@@ -53,7 +53,8 @@ namespace Lucene.Net
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public static bool IsIllegalArgumentException(this Exception e)
         {
-            if (e is null || e.IsAlwaysIgnored()) return false;
+            // If our exception implements IError and subclasses ArgumentException, we will ignore it.
+            if (e is null || e.IsError() || e.IsAlwaysIgnored()) return false;
 
             return e is ArgumentException &&
                 !(e is ArgumentNullException) &&     // Corresponds to NullPointerException, so we don't catch it here.
diff --git a/src/Lucene.Net.Tests.QueryParser/Flexible/Spans/SpansValidatorQueryNodeProcessor.cs b/src/Lucene.Net.Tests.QueryParser/Flexible/Spans/SpansValidatorQueryNodeProcessor.cs
index 5b69a8a..79b8327 100644
--- a/src/Lucene.Net.Tests.QueryParser/Flexible/Spans/SpansValidatorQueryNodeProcessor.cs
+++ b/src/Lucene.Net.Tests.QueryParser/Flexible/Spans/SpansValidatorQueryNodeProcessor.cs
@@ -45,8 +45,9 @@ namespace Lucene.Net.QueryParsers.Flexible.Spans
             if (!((node is BooleanQueryNode && !(node is AndQueryNode)) || node
                 .GetType() == typeof(FieldQueryNode)))
             {
-                throw new QueryNodeException(new Message(
-                    QueryParserMessages.NODE_ACTION_NOT_SUPPORTED));
+                // LUCENENET: Factored out NLS/Message/IMessage so end users can optionally utilize the built-in .NET localization.
+                throw new QueryNodeException(
+                    QueryParserMessages.NODE_ACTION_NOT_SUPPORTED);
             }
 
             return node;
diff --git a/src/Lucene.Net.Tests.QueryParser/Flexible/Standard/TestQPHelper.cs b/src/Lucene.Net.Tests.QueryParser/Flexible/Standard/TestQPHelper.cs
index dd3e9b5..7174662 100644
--- a/src/Lucene.Net.Tests.QueryParser/Flexible/Standard/TestQPHelper.cs
+++ b/src/Lucene.Net.Tests.QueryParser/Flexible/Standard/TestQPHelper.cs
@@ -163,9 +163,9 @@ namespace Lucene.Net.QueryParsers.Flexible.Standard
 
                     if (node is WildcardQueryNode || node is FuzzyQueryNode)
                     {
-
-                        throw new QueryNodeException(new Message(
-                            QueryParserMessages.EMPTY_MESSAGE));
+                        // LUCENENET: Factored out NLS/Message/IMessage so end users can optionally utilize the built-in .NET localization.
+                        throw new QueryNodeException(
+                            QueryParserMessages.EMPTY_MESSAGE);
 
                     }
 
diff --git a/src/Lucene.Net.Tests.QueryParser/Support/TestApiConsistency.cs b/src/Lucene.Net.Tests.QueryParser/Support/TestApiConsistency.cs
index 28639b1..e6b625e 100644
--- a/src/Lucene.Net.Tests.QueryParser/Support/TestApiConsistency.cs
+++ b/src/Lucene.Net.Tests.QueryParser/Support/TestApiConsistency.cs
@@ -1,4 +1,4 @@
-using Lucene.Net.Attributes;
+using Lucene.Net.Attributes;
 using Lucene.Net.Util;
 using NUnit.Framework;
 using System;
@@ -45,7 +45,7 @@ namespace Lucene.Net.QueryParsers
         [TestCase(typeof(Lucene.Net.QueryParsers.Classic.ICharStream))]
         public override void TestPublicFields(Type typeFromTargetAssembly)
         {
-            base.TestPublicFields(typeFromTargetAssembly);
+            base.TestPublicFields(typeFromTargetAssembly, @"^System\.Runtime\.CompilerServices");
         }
 
         [Test, LuceneNetSpecific]
diff --git a/src/Lucene.Net/Support/ExceptionHandling/ExceptionExtensions.cs b/src/Lucene.Net/Support/ExceptionHandling/ExceptionExtensions.cs
index eef397c..3795b7a 100644
--- a/src/Lucene.Net/Support/ExceptionHandling/ExceptionExtensions.cs
+++ b/src/Lucene.Net/Support/ExceptionHandling/ExceptionExtensions.cs
@@ -358,7 +358,8 @@ namespace Lucene
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public static bool IsIllegalArgumentException(this Exception e)
         {
-            if (e is null || e.IsAlwaysIgnored()) return false;
+            // If our exception implements IError and subclasses ArgumentException, we will ignore it.
+            if (e is null || e.IsError() || e.IsAlwaysIgnored()) return false;
 
             // LUCENENET: In production, there is a chance that we will upgrade to ArgumentNullExcpetion or ArgumentOutOfRangeException
             // and it is still important that those are caught. However, we have a copy of this method in the test environment