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 c15328f68ef46503d96f3f011f9ab2a3001acc24 Author: Shad Storhaug <[email protected]> AuthorDate: Tue May 4 06:44:36 2021 +0700 Lucene.Net.QueryParsers.Flexible.Core.Messages: Redesigned QueryParserMessages.cs so that it is just a facade around a IResourceProvider implementation that provides the actual fallback logic. Added a QueryParserResourceProvider implementation that can be passed zero to many ResourceProvider instances to override and optionally localize the default resource messages. --- .../Core/Messages/QueryParserMessages.Designer.cs | 243 ------------------- .../Flexible/Core/Messages/QueryParserMessages.cs | 263 ++++++++++++++++----- .../Core/Messages/QueryParserResourceProvider.cs | 191 +++++++++++++++ .../Lucene.Net.QueryParser.csproj | 13 +- .../Lucene.Net.Tests.QueryParser.csproj | 29 ++- .../Resources/LUCENE_NET_ICON_32x32.png | Bin 0 -> 233 bytes .../Core/Messages/MessagesTest.Designer.cs | 100 ++++++++ .../Flexible/Core/Messages/MessagesTest.ja.resx | 126 ++++++++++ .../Flexible/Core/Messages/MessagesTest.resx | 133 +++++++++++ .../Messages/TestQueryParserMessagesDefault.cs | 105 ++++++++ .../Messages/TestQueryParserMessagesOverridden.cs | 123 ++++++++++ .../Messages/TestQueryParserResourceProvider.cs | 113 +++++++++ .../Core/Messages/lucene-net-icon-32x32.png | Bin 0 -> 1136 bytes src/Lucene.Net/Support/Util/IResourceProvider.cs | 94 ++++++++ 14 files changed, 1214 insertions(+), 319 deletions(-) diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Messages/QueryParserMessages.Designer.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Messages/QueryParserMessages.Designer.cs deleted file mode 100644 index 1275ba0..0000000 --- a/src/Lucene.Net.QueryParser/Flexible/Core/Messages/QueryParserMessages.Designer.cs +++ /dev/null @@ -1,243 +0,0 @@ -//------------------------------------------------------------------------------ -// <auto-generated> -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// </auto-generated> -//------------------------------------------------------------------------------ - -namespace Lucene.Net.QueryParsers.Flexible.Core.Messages { - using System; - - - /// <summary> - /// A strongly-typed resource class, for looking up localized strings, etc. - /// </summary> - // This class was auto-generated by the StronglyTypedResourceBuilder - // 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", "16.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - 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 QueryParserMessages() { - } - - /// <summary> - /// Returns the cached ResourceManager instance used by this class. - /// </summary> - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - 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.QueryParserMessages", typeof(QueryParserMessages).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// <summary> - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// </summary> - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// <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 "{0}" using {1}. - /// </summary> - internal static string COULD_NOT_PARSE_NUMBER { - get { - return ResourceManager.GetString("COULD_NOT_PARSE_NUMBER", resourceCulture); - } - } - - /// <summary> - /// Looks up a localized string similar to . - /// </summary> - internal static string EMPTY_MESSAGE { - get { - return ResourceManager.GetString("EMPTY_MESSAGE", resourceCulture); - } - } - - /// <summary> - /// Looks up a localized string similar to Syntax Error: {0}. - /// </summary> - internal static string INVALID_SYNTAX { - get { - return ResourceManager.GetString("INVALID_SYNTAX", resourceCulture); - } - } - - /// <summary> - /// Looks up a localized string similar to Syntax Error, cannot parse {0}: {1}. - /// </summary> - internal static string INVALID_SYNTAX_CANNOT_PARSE { - get { - return ResourceManager.GetString("INVALID_SYNTAX_CANNOT_PARSE", resourceCulture); - } - } - - /// <summary> - /// Looks up a localized string similar to Term can not end with escape character.. - /// </summary> - internal static string INVALID_SYNTAX_ESCAPE_CHARACTER { - get { - return ResourceManager.GetString("INVALID_SYNTAX_ESCAPE_CHARACTER", resourceCulture); - } - } - - /// <summary> - /// Looks up a localized string similar to Non-hex character in Unicode escape sequence: {0}. - /// </summary> - internal static string INVALID_SYNTAX_ESCAPE_NONE_HEX_UNICODE { - get { - return ResourceManager.GetString("INVALID_SYNTAX_ESCAPE_NONE_HEX_UNICODE", resourceCulture); - } - } - - /// <summary> - /// Looks up a localized string similar to Truncated unicode escape sequence.. - /// </summary> - internal static string INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION { - get { - return ResourceManager.GetString("INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION", resourceCulture); - } - } - - /// <summary> - /// Looks up a localized string similar to Fractional edit distances are not allowed.. - /// </summary> - internal static string INVALID_SYNTAX_FUZZY_EDITS { - get { - return ResourceManager.GetString("INVALID_SYNTAX_FUZZY_EDITS", resourceCulture); - } - } - - /// <summary> - /// Looks up a localized string similar to The similarity value for a fuzzy search must be between 0.0 and 1.0.. - /// </summary> - internal static string INVALID_SYNTAX_FUZZY_LIMITS { - get { - return ResourceManager.GetString("INVALID_SYNTAX_FUZZY_LIMITS", resourceCulture); - } - } - - /// <summary> - /// Looks up a localized string similar to Leading wildcard is not allowed: {0}. - /// </summary> - internal static string LEADING_WILDCARD_NOT_ALLOWED { - get { - return ResourceManager.GetString("LEADING_WILDCARD_NOT_ALLOWED", resourceCulture); - } - } - - /// <summary> - /// Looks up a localized string similar to Cannot convert query to lucene syntax: {0} error: {1}. - /// </summary> - internal static string LUCENE_QUERY_CONVERSION_ERROR { - get { - return ResourceManager.GetString("LUCENE_QUERY_CONVERSION_ERROR", resourceCulture); - } - } - - /// <summary> - /// Looks up a localized string similar to This node does not support this action.. - /// </summary> - internal static string NODE_ACTION_NOT_SUPPORTED { - get { - return ResourceManager.GetString("NODE_ACTION_NOT_SUPPORTED", resourceCulture); - } - } - - /// <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 { - get { - return ResourceManager.GetString("NUMBER_CLASS_NOT_SUPPORTED_BY_NUMERIC_RANGE_QUERY", resourceCulture); - } - } - - /// <summary> - /// Looks up a localized string similar to Field "{0}" is numeric and cannot have an empty value.. - /// </summary> - internal static string NUMERIC_CANNOT_BE_EMPTY { - get { - return ResourceManager.GetString("NUMERIC_CANNOT_BE_EMPTY", resourceCulture); - } - } - - /// <summary> - /// Looks up a localized string similar to Parameter {1} with value {0} not supported.. - /// </summary> - internal static string PARAMETER_VALUE_NOT_SUPPORTED { - get { - return ResourceManager.GetString("PARAMETER_VALUE_NOT_SUPPORTED", resourceCulture); - } - } - - /// <summary> - /// Looks up a localized string similar to Too many boolean clauses, the maximum supported is {0}: {1}. - /// </summary> - internal static string TOO_MANY_BOOLEAN_CLAUSES { - get { - return ResourceManager.GetString("TOO_MANY_BOOLEAN_CLAUSES", resourceCulture); - } - } - - /// <summary> - /// Looks up a localized string similar to Unsupported NumericField.DataType: {0}. - /// </summary> - internal static string UNSUPPORTED_NUMERIC_DATA_TYPE { - get { - return ResourceManager.GetString("UNSUPPORTED_NUMERIC_DATA_TYPE", resourceCulture); - } - } - - /// <summary> - /// Looks up a localized string similar to Wildcard is not supported for query: {0}. - /// </summary> - internal static string WILDCARD_NOT_SUPPORTED { - get { - return ResourceManager.GetString("WILDCARD_NOT_SUPPORTED", resourceCulture); - } - } - } -} diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Messages/QueryParserMessages.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Messages/QueryParserMessages.cs index 103b981..02f38f7 100644 --- a/src/Lucene.Net.QueryParser/Flexible/Core/Messages/QueryParserMessages.cs +++ b/src/Lucene.Net.QueryParser/Flexible/Core/Messages/QueryParserMessages.cs @@ -1,64 +1,199 @@ -// 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. - -//using Lucene.Net.QueryParsers.Flexible.Messages; - -//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. -// */ - -// /// <summary> -// /// Flexible Query Parser message bundle class -// /// </summary> -// public class QueryParserMessages : NLS -// { -// private static readonly string BUNDLE_NAME = typeof(QueryParserMessages).Name; - -// private QueryParserMessages() -// { -// // Do not instantiate -// } - -// 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; -// } -//} +// LUCENENET specific - This is the content of QueryParserMessages.Designer that was generated, with customizations. +// The NLS derived class was replaced with this one to make interop with .NET resources easier. +// +// We turned off auto-generation of this file and added a SetResourceProvider() to supply a class that can supply string/object localized resources. +// This allows end users to supply localized messages. +// +// 1. Add a Resource (.resx) to the project. +// 2. Add any of the below properties as the resource names, and supply messages as desired. +// 3. Call QueryParserMessages.SetResourceProvider(new QueryParserResourceProvider(SomeResource.ResourceManager)) at application startup and supply the ResourceManager of the custom Resource's designer. + + +using Lucene.Net.Util; +using System; +using System.ComponentModel; +using System.Globalization; +#nullable enable + +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. + */ + + /// <summary> + /// A strongly-typed resource class, for looking up localized strings, etc. + /// <para/> + /// The localized resources can be replaced by end users by calling the <see cref="SetResourceProvider(IResourceProvider)"/> + /// method and supplying an instance of <see cref="QueryParserResourceProvider"/> with custom + /// <see cref="System.Resources.ResourceManager"/> instances provided in its constructor. + /// <code> + /// QueryParserMessages.SetResourceProvider(new QueryParserResourceProvider(SomeResource.ResourceManager, SomeOtherResource.ResourceManager)); + /// </code> + /// <c>SomeResource</c> and <c>SomeOtherResource</c> are auto-generated designer classes which can be generated by Visual Studio when adding + /// resource files (.resx) to a project. These resources can optionally be localized in different cultures and optionally be distributed as satellite + /// assemblies. See the <see cref="System.Resources.ResourceManager"/> documentation for tips on how to get started, but do note this is a broad topic. + /// <para/> + /// <see cref="QueryParserResourceProvider"/> makes no assumptions on the method used to generate or deploy resources, the only requirement is that you provide + /// a <see cref="System.Resources.ResourceManager"/> that can find them. Note that it is also possible to subclass <see cref="QueryParserResourceProvider"/> + /// or implement <see cref="IResourceProvider"/> directly to provide resources from any source. + /// </summary> + // LUCENENET NOTE: Since we are not using a custom tool to generate this file, any additions/deletions to the + // QueryParserMessages.resx file must be done to this class manually. + public static class QueryParserMessages + { + private static CultureInfo? resourceCulture; + private static IResourceProvider resourceProvider = new QueryParserResourceProvider(); + + /// <summary> + /// Gets the associated resource provider. + /// </summary> + /// <returns>The current resource provider.</returns> + /// <seealso cref="SetResourceProvider(IResourceProvider)"/> + public static IResourceProvider GetResourceProvider() + { + return resourceProvider; + } + + /// <summary> + /// Sets the <see cref="IResourceProvider"/> instance used to provide + /// localized <see cref="string"/>s and <see cref="object"/>s. + /// </summary> + /// <param name="provider">The new <see cref="IResourceProvider"/>.</param> + /// <exception cref="ArgumentNullException">The <paramref name="provider"/> parameter is <c>null</c>.</exception> + /// <seealso cref="GetResourceProvider()"/> + public static void SetResourceProvider(IResourceProvider provider) + { + resourceProvider = provider ?? throw new ArgumentNullException(nameof(provider)); + } + + private static string? GetString(string name, CultureInfo? culture) + { + return resourceProvider.GetString(name, culture); + } + + /// <summary> + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// </summary> + [EditorBrowsableAttribute(EditorBrowsableState.Advanced)] + public static CultureInfo? Culture + { + get => resourceCulture; + set => resourceCulture = value; + } + + /// <summary> + /// Looks up a localized string similar to Value cannot be null.. + /// </summary> + public static string? ARGUMENT_CANNOT_BE_NULL => GetString("ARGUMENT_CANNOT_BE_NULL", resourceCulture); + + /// <summary> + /// Looks up a localized string similar to Could not parse text "{0}" using {1}. + /// </summary> + public static string? COULD_NOT_PARSE_NUMBER => GetString("COULD_NOT_PARSE_NUMBER", resourceCulture); + + /// <summary> + /// Looks up a localized string similar to . + /// </summary> + public static string? EMPTY_MESSAGE => GetString("EMPTY_MESSAGE", resourceCulture); + + /// <summary> + /// Looks up a localized string similar to Syntax Error: {0}. + /// </summary> + public static string? INVALID_SYNTAX => GetString("INVALID_SYNTAX", resourceCulture); + + /// <summary> + /// Looks up a localized string similar to Syntax Error, cannot parse {0}: {1}. + /// </summary> + public static string? INVALID_SYNTAX_CANNOT_PARSE => GetString("INVALID_SYNTAX_CANNOT_PARSE", resourceCulture); + + /// <summary> + /// Looks up a localized string similar to Term can not end with escape character.. + /// </summary> + public static string? INVALID_SYNTAX_ESCAPE_CHARACTER => GetString("INVALID_SYNTAX_ESCAPE_CHARACTER", resourceCulture); + + /// <summary> + /// Looks up a localized string similar to Non-hex character in Unicode escape sequence: {0}. + /// </summary> + public static string? INVALID_SYNTAX_ESCAPE_NONE_HEX_UNICODE => GetString("INVALID_SYNTAX_ESCAPE_NONE_HEX_UNICODE", resourceCulture); + + /// <summary> + /// Looks up a localized string similar to Truncated unicode escape sequence.. + /// </summary> + public static string? INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION => GetString("INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION", resourceCulture); + + /// <summary> + /// Looks up a localized string similar to Fractional edit distances are not allowed.. + /// </summary> + public static string? INVALID_SYNTAX_FUZZY_EDITS => GetString("INVALID_SYNTAX_FUZZY_EDITS", resourceCulture); + + /// <summary> + /// Looks up a localized string similar to The similarity value for a fuzzy search must be between 0.0 and 1.0.. + /// </summary> + public static string? INVALID_SYNTAX_FUZZY_LIMITS => GetString("INVALID_SYNTAX_FUZZY_LIMITS", resourceCulture); + + /// <summary> + /// Looks up a localized string similar to Leading wildcard is not allowed: {0}. + /// </summary> + public static string? LEADING_WILDCARD_NOT_ALLOWED => GetString("LEADING_WILDCARD_NOT_ALLOWED", resourceCulture); + + /// <summary> + /// Looks up a localized string similar to Cannot convert query to lucene syntax: {0} error: {1}. + /// </summary> + public static string? LUCENE_QUERY_CONVERSION_ERROR => GetString("LUCENE_QUERY_CONVERSION_ERROR", resourceCulture); + + /// <summary> + /// Looks up a localized string similar to This node does not support this action.. + /// </summary> + public static string? NODE_ACTION_NOT_SUPPORTED => GetString("NODE_ACTION_NOT_SUPPORTED", resourceCulture); + + /// <summary> + /// Looks up a localized string similar to The parameter must be greater than or equal to zero.. + /// </summary> + public static string? NUMBER_CANNOT_BE_NEGATIVE => GetString("NUMBER_CANNOT_BE_NEGATIVE", resourceCulture); + + /// <summary> + /// Looks up a localized string similar to Number class not supported by NumericRangeQueryNode: {0}. + /// </summary> + public static string? NUMBER_CLASS_NOT_SUPPORTED_BY_NUMERIC_RANGE_QUERY => GetString("NUMBER_CLASS_NOT_SUPPORTED_BY_NUMERIC_RANGE_QUERY", resourceCulture); + + /// <summary> + /// Looks up a localized string similar to Field "{0}" is numeric and cannot have an empty value.. + /// </summary> + public static string? NUMERIC_CANNOT_BE_EMPTY => GetString("NUMERIC_CANNOT_BE_EMPTY", resourceCulture); + + /// <summary> + /// Looks up a localized string similar to Parameter {1} with value {0} not supported.. + /// </summary> + public static string? PARAMETER_VALUE_NOT_SUPPORTED => GetString("PARAMETER_VALUE_NOT_SUPPORTED", resourceCulture); + + /// <summary> + /// Looks up a localized string similar to Too many boolean clauses, the maximum supported is {0}: {1}. + /// </summary> + public static string? TOO_MANY_BOOLEAN_CLAUSES => GetString("TOO_MANY_BOOLEAN_CLAUSES", resourceCulture); + + /// <summary> + /// Looks up a localized string similar to Unsupported NumericField.DataType: {0}. + /// </summary> + public static string? UNSUPPORTED_NUMERIC_DATA_TYPE => GetString("UNSUPPORTED_NUMERIC_DATA_TYPE", resourceCulture); + + /// <summary> + /// Looks up a localized string similar to Wildcard is not supported for query: {0}. + /// </summary> + public static string? WILDCARD_NOT_SUPPORTED => GetString("WILDCARD_NOT_SUPPORTED", resourceCulture); + } +} diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Messages/QueryParserResourceProvider.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Messages/QueryParserResourceProvider.cs new file mode 100644 index 0000000..0a9633f --- /dev/null +++ b/src/Lucene.Net.QueryParser/Flexible/Core/Messages/QueryParserResourceProvider.cs @@ -0,0 +1,191 @@ +using Lucene.Net.Support; +using Lucene.Net.Util; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Globalization; +using System.IO; +using System.Resources; +using System.Threading; +#nullable enable + +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. + */ + + /// <summary> + /// The default <see cref="IResourceProvider"/> implementation for the <see cref="QueryParserMessages"/> class. + /// This class can be set in the <see cref="QueryParserMessages.SetResourceProvider(IResourceProvider)"/> method + /// and supplied with one or more <see cref="ResourceManager"/> instances that can override the default query parser + /// messages (generally, they are exception messages). + /// <para/> + /// Alternatively, this class may be overridden to provide either a custom <see cref="FallbackResourceManager"/> or + /// to alter the fallback logic in either <see cref="GetString(string, CultureInfo?)"/> or <see cref="GetObject(string, CultureInfo?)"/>. + /// The performance of this class may be improved significantly by specifying the <see cref="ResourceManager"/> that a specific resource + /// can be found in rather than attempting all of them. + /// </summary> + public class QueryParserResourceProvider : IResourceProvider + { + private ResourceManager? fallbackResourceManager; + private readonly IList<ResourceManager> resourceManagers; + + /// <summary> + /// Initializes a new instance of the <see cref="QueryParserResourceProvider"/> class with default values. + /// </summary> + public QueryParserResourceProvider() + : this((IList<ResourceManager>)Arrays.Empty<ResourceManager>()) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="QueryParserResourceProvider"/> class with the specified + /// <paramref name="resourceManagers"/>. The <paramref name="resourceManagers"/> may override resources + /// in the <see cref="FallbackResourceManager"/>, provided they have the same names. + /// <para/> + /// Note that not all of the resources are required to be provided and if the name doesn't exist it will + /// fall back to the next <see cref="ResourceManager"/> that is provided and ultimately will try the + /// <see cref="FallbackResourceManager"/> if the resource is not found. + /// </summary> + /// <param name="resourceManagers">One or more <see cref="ResourceManager"/> instances that provide + /// localized resources. The <paramref name="resourceManagers"/> are used in the order they are specified, and the first one + /// that provides a non-<c>null</c> value for a given resource name wins.</param> + /// <exception cref="ArgumentNullException">If <paramref name="resourceManagers"/> is <c>null</c>.</exception> + public QueryParserResourceProvider(params ResourceManager[] resourceManagers) + : this((IList<ResourceManager>)resourceManagers) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="QueryParserResourceProvider"/> class with the specified + /// <paramref name="resourceManagers"/>. The <paramref name="resourceManagers"/> may override resources + /// in the <see cref="FallbackResourceManager"/>, provided they have the same names. + /// <para/> + /// Note that not all of the resources are required to be provided and if the name doesn't exist it will + /// fall back to the next <see cref="ResourceManager"/> that is provided and ultimately will try the + /// <see cref="FallbackResourceManager"/> if the resource is not found. + /// </summary> + /// <param name="resourceManagers">One or more <see cref="ResourceManager"/> instances that provide + /// localized resources. The <paramref name="resourceManagers"/> are used in the order they are specified, and the first one + /// that provides a non-<c>null</c> value for a given resource name wins.</param> + /// <exception cref="ArgumentNullException">If <paramref name="resourceManagers"/> is <c>null</c>.</exception> + public QueryParserResourceProvider(IList<ResourceManager> resourceManagers) + { + this.resourceManagers = resourceManagers ?? throw new ArgumentNullException(nameof(resourceManagers)); + } + + /// <summary> + /// Gets the cached <see cref="ResourceManager"/> instance used as the fallback by this class. + /// </summary> + [EditorBrowsable(EditorBrowsableState.Advanced)] + public virtual ResourceManager FallbackResourceManager + { + get + { + return LazyInitializer.EnsureInitialized(ref fallbackResourceManager, + () => new ResourceManager("Lucene.Net.QueryParsers.Flexible.Core.Messages.QueryParserMessages", typeof(QueryParserMessages).Assembly))!; + } + } + + /// <summary>Returns the value of the string resource localized for the specified <paramref name="culture"/>. + /// <para/> + /// The resource is searched for + /// first in the <see cref="ResourceManager"/> instances passed in the <see cref="QueryParserResourceProvider(IList{ResourceManager})"/> + /// or <see cref="QueryParserResourceProvider(ResourceManager[])"/> constructor, in the order they are specified. If not found, the + /// <see cref="FallbackResourceManager"/> is used. This method may return <c>null</c> if the resource with the given name is not found.</summary> + /// <inheritdoc/> + public virtual string? GetString(string name, CultureInfo? culture) + { + if (resourceManagers.Count > 0) + { + foreach (var resourceManager in resourceManagers) + { + // LUCENENET NOTE: MissingManifestResourceException or MissingSatelliteAssemblyException + // can be thrown here, but these indicate that there is a misconfigured setup (missing resource file, + // missing assembly, etc.) We intentionally let these errors propagate to ensure the developer who + // is creating resources is aware of these problems before the app is deployed (provided they test it). + // However, if the resource simply doesn't have an entry, we get a null return value instead and handle + // the fallback accordingly. + var result = resourceManager.GetString(name, culture); + if (result is null) + continue; + return result; + } + } + + return FallbackResourceManager.GetString(name, culture); + } + + /// <summary>Gets the value of the specified non-string resource localized for the specified <paramref name="culture"/>. + /// <para/> + /// The resource is searched for + /// first in the <see cref="ResourceManager"/> instances passed in the <see cref="QueryParserResourceProvider(IList{ResourceManager})"/> + /// or <see cref="QueryParserResourceProvider(ResourceManager[])"/> constructor, in the order they are specified. If not found, the + /// <see cref="FallbackResourceManager"/> is used. This method may return <c>null</c> if the resource with the given name is not found.</summary> + /// <inheritdoc/> + public virtual object? GetObject(string name, CultureInfo? culture) + { + if (resourceManagers.Count > 0) + { + foreach (var resourceManager in resourceManagers) + { + // LUCENENET NOTE: MissingManifestResourceException or MissingSatelliteAssemblyException + // can be thrown here, but these indicate that there is a misconfigured setup (missing resource file, + // missing assembly, etc.) We intentionally let these errors propagate to ensure the developer who + // is creating resources is aware of these problems before the app is deployed (provided they test it). + // However, if the resource simply doesn't have an entry, we get a null return value instead and handle + // the fallback accordingly. + var result = resourceManager.GetObject(name, culture); + if (result is null) + continue; + return result; + } + } + + return FallbackResourceManager.GetObject(name, culture); + } + + /// <summary>Returns an unmanaged memory stream object from the specified resource, using the specified <paramref name="culture"/>. + /// <para/> + /// The resource is searched for + /// first in the <see cref="ResourceManager"/> instances passed in the <see cref="QueryParserResourceProvider(IList{ResourceManager})"/> + /// or <see cref="QueryParserResourceProvider(ResourceManager[])"/> constructor, in the order they are specified. If not found, the + /// <see cref="FallbackResourceManager"/> is used. This method may return <c>null</c> if the resource with the given name is not found.</summary> + /// <inheritdoc/> + public Stream? GetStream(string name, CultureInfo? culture) + { + if (resourceManagers.Count > 0) + { + foreach (var resourceManager in resourceManagers) + { + // LUCENENET NOTE: MissingManifestResourceException or MissingSatelliteAssemblyException + // can be thrown here, but these indicate that there is a misconfigured setup (missing resource file, + // missing assembly, etc.) We intentionally let these errors propagate to ensure the developer who + // is creating resources is aware of these problems before the app is deployed (provided they test it). + // However, if the resource simply doesn't have an entry, we get a null return value instead and handle + // the fallback accordingly. + var result = resourceManager.GetStream(name, culture); + if (result is null) + continue; + return result; + } + } + + return FallbackResourceManager.GetStream(name, culture); + } + } +} diff --git a/src/Lucene.Net.QueryParser/Lucene.Net.QueryParser.csproj b/src/Lucene.Net.QueryParser/Lucene.Net.QueryParser.csproj index 20f51fe..4d287a7 100644 --- a/src/Lucene.Net.QueryParser/Lucene.Net.QueryParser.csproj +++ b/src/Lucene.Net.QueryParser/Lucene.Net.QueryParser.csproj @@ -53,17 +53,8 @@ </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 Update="Flexible\Core\Messages\QueryParserMessages.resx" > + <Generator Label="No generator used - we update manually."></Generator> </EmbeddedResource> </ItemGroup> diff --git a/src/Lucene.Net.Tests.QueryParser/Lucene.Net.Tests.QueryParser.csproj b/src/Lucene.Net.Tests.QueryParser/Lucene.Net.Tests.QueryParser.csproj index 603bbf2..52d4966 100644 --- a/src/Lucene.Net.Tests.QueryParser/Lucene.Net.Tests.QueryParser.csproj +++ b/src/Lucene.Net.Tests.QueryParser/Lucene.Net.Tests.QueryParser.csproj @@ -25,9 +25,17 @@ <PropertyGroup> <AssemblyTitle>Lucene.Net.Tests.QueryParser</AssemblyTitle> + + <RootNamespace>Lucene.Net.QueryParsers</RootNamespace> </PropertyGroup> <ItemGroup> + <None Remove="Support\Flexible\Core\Messages\lucene-net-icon-32x32.png" /> + </ItemGroup> + + <ItemGroup> + <!-- For testing whether we can get an image from a localized resource --> + <EmbeddedResource Include="Support\Flexible\Core\Messages\lucene-net-icon-32x32.png" /> <EmbeddedResource Include="Xml\albumBooleanQuery.xsl;Xml\albumFilteredQuery.xsl;Xml\albumLuceneClassicQuery.xsl;Xml\BooleanFilter.xml;Xml\BooleanQuery.xml;Xml\BoostingQuery.xml;Xml\BoostingTermQuery.xml;Xml\CachedFilter.xml;Xml\ConstantScoreQuery.xml;Xml\DisjunctionMaxQuery.xml;Xml\DuplicateFilterQuery.xml;Xml\FuzzyLikeThisQuery.xml;Xml\LikeThisQuery.xml;Xml\MatchAllDocsQuery.xml;Xml\NestedBooleanQuery.xml;Xml\NumericRangeFilterQuery.xml;Xml\NumericRangeQueryQuery.xml;Xml\RangeFilter [...] </ItemGroup> @@ -40,7 +48,26 @@ <Import Project="$(SolutionDir)build/TestReferences.Common.targets" /> <ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.1' "> - <PackageReference Include="System.Net.Primitives" Version="$(SystemNetPrimitivesPackageVersion)"/> + <PackageReference Include="System.Net.Primitives" Version="$(SystemNetPrimitivesPackageVersion)" /> + </ItemGroup> + + <ItemGroup> + <Compile Update="Support\Flexible\Core\Messages\MessagesTest.Designer.cs"> + <DesignTime>True</DesignTime> + <AutoGen>True</AutoGen> + <DependentUpon>MessagesTest.resx</DependentUpon> + </Compile> + </ItemGroup> + + <ItemGroup> + <EmbeddedResource Update="Support\Flexible\Core\Messages\MessagesTest.resx"> + <Generator>ResXFileCodeGenerator</Generator> + <LastGenOutput>MessagesTest.Designer.cs</LastGenOutput> + </EmbeddedResource> + </ItemGroup> + + <ItemGroup> + <Folder Include="Resources\" /> </ItemGroup> </Project> diff --git a/src/Lucene.Net.Tests.QueryParser/Resources/LUCENE_NET_ICON_32x32.png b/src/Lucene.Net.Tests.QueryParser/Resources/LUCENE_NET_ICON_32x32.png new file mode 100644 index 0000000..3e9d6ed Binary files /dev/null and b/src/Lucene.Net.Tests.QueryParser/Resources/LUCENE_NET_ICON_32x32.png differ diff --git a/src/Lucene.Net.Tests.QueryParser/Support/Flexible/Core/Messages/MessagesTest.Designer.cs b/src/Lucene.Net.Tests.QueryParser/Support/Flexible/Core/Messages/MessagesTest.Designer.cs new file mode 100644 index 0000000..67dc83d --- /dev/null +++ b/src/Lucene.Net.Tests.QueryParser/Support/Flexible/Core/Messages/MessagesTest.Designer.cs @@ -0,0 +1,100 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace Lucene.Net.QueryParsers.Support.Flexible.Core.Messages { + using System; + + + /// <summary> + /// A strongly-typed resource class, for looking up localized strings, etc. + /// </summary> + // This class was auto-generated by the StronglyTypedResourceBuilder + // 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", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class MessagesTest { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal MessagesTest() { + } + + /// <summary> + /// Returns the cached ResourceManager instance used by this class. + /// </summary> + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + 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.Support.Flexible.Core.Messages.MessagesTest", typeof(MessagesTest).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// <summary> + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// </summary> + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// <summary> + /// Looks up a localized string similar to Syntax Error: {0} (TEST). + /// </summary> + internal static string INVALID_SYNTAX { + get { + return ResourceManager.GetString("INVALID_SYNTAX", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Non-hex character in Unicode escape sequence: {0} (TEST). + /// </summary> + internal static string INVALID_SYNTAX_ESCAPE_NONE_HEX_UNICODE { + get { + return ResourceManager.GetString("INVALID_SYNTAX_ESCAPE_NONE_HEX_UNICODE", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Truncated unicode escape sequence. (TEST) . + /// </summary> + internal static string INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION { + get { + return ResourceManager.GetString("INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized resource of type System.Byte[]. + /// </summary> + internal static byte[] LUCENE_NET_ICON_32x32 { + get { + object obj = ResourceManager.GetObject("LUCENE_NET_ICON_32x32", resourceCulture); + return ((byte[])(obj)); + } + } + } +} diff --git a/src/Lucene.Net.Tests.QueryParser/Support/Flexible/Core/Messages/MessagesTest.ja.resx b/src/Lucene.Net.Tests.QueryParser/Support/Flexible/Core/Messages/MessagesTest.ja.resx new file mode 100644 index 0000000..230b8a6 --- /dev/null +++ b/src/Lucene.Net.Tests.QueryParser/Support/Flexible/Core/Messages/MessagesTest.ja.resx @@ -0,0 +1,126 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <!-- + Microsoft ResX Schema + + Version 2.0 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">2.0</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + <value>[base64 mime encoded serialized .NET Framework object]</value> + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> + <comment>This is a comment</comment> + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> + <xsd:element name="root" msdata:IsDataSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="metadata"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="name" use="required" type="xsd:string" /> + <xsd:attribute name="type" type="xsd:string" /> + <xsd:attribute name="mimetype" type="xsd:string" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="assembly"> + <xsd:complexType> + <xsd:attribute name="alias" type="xsd:string" /> + <xsd:attribute name="name" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="data"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="resheader"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + </xsd:element> + </xsd:choice> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>2.0</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <data name="INVALID_SYNTAX" xml:space="preserve"> + <value>構文エラー: {0}</value> + </data> + <data name="INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION" xml:space="preserve"> + <value>切り捨てられたユニコード・エスケープ・シーケンス。</value> + </data> +</root> \ No newline at end of file diff --git a/src/Lucene.Net.Tests.QueryParser/Support/Flexible/Core/Messages/MessagesTest.resx b/src/Lucene.Net.Tests.QueryParser/Support/Flexible/Core/Messages/MessagesTest.resx new file mode 100644 index 0000000..549d008 --- /dev/null +++ b/src/Lucene.Net.Tests.QueryParser/Support/Flexible/Core/Messages/MessagesTest.resx @@ -0,0 +1,133 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <!-- + Microsoft ResX Schema + + Version 2.0 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">2.0</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + <value>[base64 mime encoded serialized .NET Framework object]</value> + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> + <comment>This is a comment</comment> + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> + <xsd:element name="root" msdata:IsDataSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="metadata"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="name" use="required" type="xsd:string" /> + <xsd:attribute name="type" type="xsd:string" /> + <xsd:attribute name="mimetype" type="xsd:string" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="assembly"> + <xsd:complexType> + <xsd:attribute name="alias" type="xsd:string" /> + <xsd:attribute name="name" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="data"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="resheader"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + </xsd:element> + </xsd:choice> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>2.0</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <data name="INVALID_SYNTAX" xml:space="preserve"> + <value>Syntax Error: {0} (TEST)</value> + </data> + <data name="INVALID_SYNTAX_ESCAPE_NONE_HEX_UNICODE" xml:space="preserve"> + <value>Non-hex character in Unicode escape sequence: {0} (TEST)</value> + </data> + <data name="INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION" xml:space="preserve"> + <value>Truncated unicode escape sequence. (TEST) </value> + </data> + <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> + <data name="LUCENE_NET_ICON_32x32" type="System.Resources.ResXFileRef, System.Windows.Forms"> + <value>lucene-net-icon-32x32.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> +</root> \ No newline at end of file diff --git a/src/Lucene.Net.Tests.QueryParser/Support/Flexible/Core/Messages/TestQueryParserMessagesDefault.cs b/src/Lucene.Net.Tests.QueryParser/Support/Flexible/Core/Messages/TestQueryParserMessagesDefault.cs new file mode 100644 index 0000000..361ae08 --- /dev/null +++ b/src/Lucene.Net.Tests.QueryParser/Support/Flexible/Core/Messages/TestQueryParserMessagesDefault.cs @@ -0,0 +1,105 @@ +using Lucene.Net.QueryParsers.Flexible.Core.Messages; +using NUnit.Framework; +using System.Globalization; +using Assert = Lucene.Net.TestFramework.Assert; + +namespace Lucene.Net.QueryParsers.Support.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. + */ + + public class TestQueryParserMessagesDefault + { + [Test] + public void TestOverrideResourceStrings() + { + QueryParserMessages.Culture = null; + + var actual = QueryParserMessages.INVALID_SYNTAX; + + Assert.AreEqual("Syntax Error: {0}", actual); + + actual = QueryParserMessages.INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION; + + Assert.AreEqual("Truncated unicode escape sequence.", actual); + + actual = QueryParserMessages.INVALID_SYNTAX_ESCAPE_NONE_HEX_UNICODE; + + Assert.AreEqual("Non-hex character in Unicode escape sequence: {0}", actual); + + actual = QueryParserMessages.INVALID_SYNTAX_FUZZY_LIMITS; + + Assert.AreEqual("The similarity value for a fuzzy search must be between 0.0 and 1.0.", actual); + } + + [Test] + public void TestOverrideResourceStrings_ja() + { + QueryParserMessages.Culture = new CultureInfo("ja"); + try + { + var actual = QueryParserMessages.INVALID_SYNTAX; + + Assert.AreEqual("Syntax Error: {0}", actual); + + actual = QueryParserMessages.INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION; + + Assert.AreEqual("Truncated unicode escape sequence.", actual); + + actual = QueryParserMessages.INVALID_SYNTAX_ESCAPE_NONE_HEX_UNICODE; + + Assert.AreEqual("Non-hex character in Unicode escape sequence: {0}", actual); + + actual = QueryParserMessages.INVALID_SYNTAX_FUZZY_LIMITS; + + Assert.AreEqual("The similarity value for a fuzzy search must be between 0.0 and 1.0.", actual); + } + finally + { + QueryParserMessages.Culture = null; + } + } + + [Test] + public void TestOverrideResourceStrings_ja_JP() + { + QueryParserMessages.Culture = new CultureInfo("ja-JP"); + try + { + var actual = QueryParserMessages.INVALID_SYNTAX; + + Assert.AreEqual("Syntax Error: {0}", actual); + + actual = QueryParserMessages.INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION; + + Assert.AreEqual("Truncated unicode escape sequence.", actual); + + actual = QueryParserMessages.INVALID_SYNTAX_ESCAPE_NONE_HEX_UNICODE; + + Assert.AreEqual("Non-hex character in Unicode escape sequence: {0}", actual); + + actual = QueryParserMessages.INVALID_SYNTAX_FUZZY_LIMITS; + + Assert.AreEqual("The similarity value for a fuzzy search must be between 0.0 and 1.0.", actual); + } + finally + { + QueryParserMessages.Culture = null; + } + } + } +} diff --git a/src/Lucene.Net.Tests.QueryParser/Support/Flexible/Core/Messages/TestQueryParserMessagesOverridden.cs b/src/Lucene.Net.Tests.QueryParser/Support/Flexible/Core/Messages/TestQueryParserMessagesOverridden.cs new file mode 100644 index 0000000..f80a8e8 --- /dev/null +++ b/src/Lucene.Net.Tests.QueryParser/Support/Flexible/Core/Messages/TestQueryParserMessagesOverridden.cs @@ -0,0 +1,123 @@ +using Lucene.Net.QueryParsers.Flexible.Core.Messages; +using Lucene.Net.Util; +using NUnit.Framework; +using System.Globalization; +using Assert = Lucene.Net.TestFramework.Assert; + +namespace Lucene.Net.QueryParsers.Support.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. + */ + + public class TestQueryParserMessagesOverridden : LuceneTestCase + { + public override void BeforeClass() + { + base.BeforeClass(); + + var provider = new QueryParserResourceProvider(MessagesTest.ResourceManager); + QueryParserMessages.SetResourceProvider(provider); + } + + public override void AfterClass() + { + // Return to the default + var provider = new QueryParserResourceProvider(); + QueryParserMessages.SetResourceProvider(provider); + + base.AfterClass(); + } + + [Test] + public void TestOverrideResourceStrings() + { + QueryParserMessages.Culture = null; + + var actual = QueryParserMessages.INVALID_SYNTAX; + + Assert.IsTrue(actual.Contains("(TEST)")); + + actual = QueryParserMessages.INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION; + + Assert.IsTrue(actual.Contains("(TEST)")); + + actual = QueryParserMessages.INVALID_SYNTAX_ESCAPE_NONE_HEX_UNICODE; + + Assert.IsTrue(actual.Contains("(TEST)")); + + actual = QueryParserMessages.INVALID_SYNTAX_FUZZY_LIMITS; + + Assert.IsFalse(actual.Contains("(TEST)")); // Fallback to default ResourceManager + } + + [Test] + public void TestOverrideResourceStrings_ja() + { + QueryParserMessages.Culture = new CultureInfo("ja"); + try + { + var actual = QueryParserMessages.INVALID_SYNTAX; + + Assert.AreEqual("構文エラー: {0}", actual); + + actual = QueryParserMessages.INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION; + + Assert.AreEqual("切り捨てられたユニコード・エスケープ・シーケンス。", actual); + + actual = QueryParserMessages.INVALID_SYNTAX_ESCAPE_NONE_HEX_UNICODE; + + Assert.AreEqual("Non-hex character in Unicode escape sequence: {0} (TEST)", actual); // Fallback to non-localized test + + actual = QueryParserMessages.INVALID_SYNTAX_FUZZY_LIMITS; + + Assert.AreEqual("The similarity value for a fuzzy search must be between 0.0 and 1.0.", actual); // Fallback to default ResourceManager + } + finally + { + QueryParserMessages.Culture = null; + } + } + + [Test] + public void TestOverrideResourceStrings_ja_JP() + { + QueryParserMessages.Culture = new CultureInfo("ja-JP"); + try + { + var actual = QueryParserMessages.INVALID_SYNTAX; + + Assert.AreEqual("構文エラー: {0}", actual); + + actual = QueryParserMessages.INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION; + + Assert.AreEqual("切り捨てられたユニコード・エスケープ・シーケンス。", actual); + + actual = QueryParserMessages.INVALID_SYNTAX_ESCAPE_NONE_HEX_UNICODE; + + Assert.AreEqual("Non-hex character in Unicode escape sequence: {0} (TEST)", actual); // Fallback to non-localized test + + actual = QueryParserMessages.INVALID_SYNTAX_FUZZY_LIMITS; + + Assert.AreEqual("The similarity value for a fuzzy search must be between 0.0 and 1.0.", actual); // Fallback to default ResourceManager + } + finally + { + QueryParserMessages.Culture = null; + } + } + } +} diff --git a/src/Lucene.Net.Tests.QueryParser/Support/Flexible/Core/Messages/TestQueryParserResourceProvider.cs b/src/Lucene.Net.Tests.QueryParser/Support/Flexible/Core/Messages/TestQueryParserResourceProvider.cs new file mode 100644 index 0000000..6979df4 --- /dev/null +++ b/src/Lucene.Net.Tests.QueryParser/Support/Flexible/Core/Messages/TestQueryParserResourceProvider.cs @@ -0,0 +1,113 @@ +using Lucene.Net.QueryParsers.Flexible.Core.Messages; +using Lucene.Net.Util; +using NUnit.Framework; +using System.Globalization; +using Assert = Lucene.Net.TestFramework.Assert; + +namespace Lucene.Net.QueryParsers.Support.Flexible.Core.Messages // LUCENENET: There is no control over the namespace for code generation other than the folder, so we must use this namespace +{ + /* + * 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. + */ + + public class TestQueryParserResourceProvider : LuceneTestCase + { + [Test] + public void TestOverrideResourceStrings() + { + var provider = new QueryParserResourceProvider(MessagesTest.ResourceManager); + + var actual = provider.GetString("INVALID_SYNTAX", null); + + Assert.IsTrue(actual.Contains("(TEST)")); + + actual = provider.GetString("INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION", null); + + Assert.IsTrue(actual.Contains("(TEST)")); + + actual = provider.GetString("INVALID_SYNTAX_ESCAPE_NONE_HEX_UNICODE", null); + + Assert.IsTrue(actual.Contains("(TEST)")); + + actual = provider.GetString("INVALID_SYNTAX_FUZZY_LIMITS", null); + + Assert.AreEqual("The similarity value for a fuzzy search must be between 0.0 and 1.0.", actual); // Fallback to default ResourceManager + } + + [Test] + public void TestOverrideResourceStrings_ja() + { + var provider = new QueryParserResourceProvider(MessagesTest.ResourceManager); + + var actual = provider.GetString("INVALID_SYNTAX", new CultureInfo("ja")); + + Assert.AreEqual("構文エラー: {0}", actual); + + actual = provider.GetString("INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION", new CultureInfo("ja")); + + Assert.AreEqual("切り捨てられたユニコード・エスケープ・シーケンス。", actual); + + actual = provider.GetString("INVALID_SYNTAX_ESCAPE_NONE_HEX_UNICODE", new CultureInfo("ja")); + + Assert.AreEqual("Non-hex character in Unicode escape sequence: {0} (TEST)", actual); // Fallback to non-localized test + + actual = provider.GetString("INVALID_SYNTAX_FUZZY_LIMITS", new CultureInfo("ja")); + + Assert.AreEqual("The similarity value for a fuzzy search must be between 0.0 and 1.0.", actual); // Fallback to default ResourceManager + } + + [Test] + public void TestOverrideResourceStrings_ja_JP() + { + var provider = new QueryParserResourceProvider(MessagesTest.ResourceManager); + + var actual = provider.GetString("INVALID_SYNTAX", new CultureInfo("ja-JP")); + + Assert.AreEqual("構文エラー: {0}", actual); + + actual = provider.GetString("INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION", new CultureInfo("ja-JP")); + + Assert.AreEqual("切り捨てられたユニコード・エスケープ・シーケンス。", actual); + + actual = provider.GetString("INVALID_SYNTAX_ESCAPE_NONE_HEX_UNICODE", new CultureInfo("ja-JP")); + + Assert.AreEqual("Non-hex character in Unicode escape sequence: {0} (TEST)", actual); // Fallback to non-localized test + + actual = provider.GetString("INVALID_SYNTAX_FUZZY_LIMITS", new CultureInfo("ja-JP")); + + Assert.AreEqual("The similarity value for a fuzzy search must be between 0.0 and 1.0.", actual); // Fallback to default ResourceManager + } + + [Test] + public void TestGetImageAsObject() + { + // Get the expected bytes + using var expectedStream = GetType().Assembly.GetManifestResourceStream("Lucene.Net.QueryParsers.Support.Flexible.Core.Messages.lucene-net-icon-32x32.png"); + byte[] expectedBytes = new byte[expectedStream.Length]; + expectedStream.Read(expectedBytes, 0, (int)expectedStream.Length); + + // Check the wrapper to ensure we can read the bytes + Assert.AreEqual(expectedBytes, MessagesTest.LUCENE_NET_ICON_32x32); + + + var provider = new QueryParserResourceProvider(MessagesTest.ResourceManager); + + byte[] actualBytes = (byte[])provider.GetObject("LUCENE_NET_ICON_32x32", null); + + Assert.AreEqual(expectedBytes, actualBytes); + } + } +} diff --git a/src/Lucene.Net.Tests.QueryParser/Support/Flexible/Core/Messages/lucene-net-icon-32x32.png b/src/Lucene.Net.Tests.QueryParser/Support/Flexible/Core/Messages/lucene-net-icon-32x32.png new file mode 100644 index 0000000..227b7ce Binary files /dev/null and b/src/Lucene.Net.Tests.QueryParser/Support/Flexible/Core/Messages/lucene-net-icon-32x32.png differ diff --git a/src/Lucene.Net/Support/Util/IResourceProvider.cs b/src/Lucene.Net/Support/Util/IResourceProvider.cs new file mode 100644 index 0000000..034da27 --- /dev/null +++ b/src/Lucene.Net/Support/Util/IResourceProvider.cs @@ -0,0 +1,94 @@ +using System; +using System.IO; +using System.Globalization; +using System.Resources; +#nullable enable + +namespace Lucene.Net.Util +{ + /* + * 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. + */ + + /// <summary> + /// Contract for a set of localized resources. Generally, this is an abstraction over one or + /// more <see cref="ResourceManager"/> instances. + /// </summary> + public interface IResourceProvider + { + /// <summary> + /// Returns the value of the string resource localized for the specified <paramref name="culture"/>. + /// </summary> + /// <param name="name">The name of the resource to retrieve.</param> + /// <param name="culture">An object that represents the culture for which the resource is localized.</param> + /// <returns>The value of the resource localized for the specified <paramref name="culture"/>, or <c>null</c> + /// if <paramref name="name"/> cannot be found in a resource set.</returns> + /// <exception cref="ArgumentNullException">The <paramref name="name"/> parameter is <c>null</c>.</exception> + /// <exception cref="InvalidOperationException">The value of the specified resource is not a string.</exception> + /// <exception cref="MissingManifestResourceException">No usable set of resources has been found, and there are + /// no resources for a default culture. For information about how to handle this exception, see the + /// "Handling MissingManifestResourceException and MissingSatelliteAssemblyException Exceptions" section + /// in the <see cref="ResourceManager"/> class topic.</exception> + /// <exception cref="MissingSatelliteAssemblyException">The default culture's resources reside in a satellite + /// assembly that could not be found. For information about how to handle this exception, see the + /// "Handling MissingManifestResourceException and MissingSatelliteAssemblyException Exceptions" section + /// in the <see cref="ResourceManager"/> class topic.</exception> + string? GetString(string name, CultureInfo? culture); + + /// <summary> + /// Gets the value of the specified non-string resource localized for the specified <paramref name="culture"/>. + /// </summary> + /// <param name="name">The name of the resource to get.</param> + /// <param name="culture">The culture for which the resource is localized. If the resource is not + /// localized for this culture, the resource manager uses fallback rules to locate an appropriate resource. + /// <para/> + /// If this value is <c>null</c>, the <see cref="CultureInfo"/> object is obtained by using the + /// <see cref="CultureInfo.CurrentUICulture"/> property. + /// </param> + /// <returns>The value of the resource, localized for the specified culture. If an appropriate resource + /// set exists but <paramref name="name"/> cannot be found, the method returns <c>null</c>.</returns> + /// <exception cref="ArgumentNullException">The <paramref name="name"/> parameter is <c>null</c>.</exception> + /// <exception cref="MissingManifestResourceException">No usable set of resources has been found, and there are + /// no resources for a default culture. For information about how to handle this exception, see the + /// "Handling MissingManifestResourceException and MissingSatelliteAssemblyException Exceptions" section + /// in the <see cref="ResourceManager"/> class topic.</exception> + /// <exception cref="MissingSatelliteAssemblyException">The default culture's resources reside in a satellite + /// assembly that could not be found. For information about how to handle this exception, see the + /// "Handling MissingManifestResourceException and MissingSatelliteAssemblyException Exceptions" section + /// in the <see cref="ResourceManager"/> class topic.</exception> + object? GetObject(string name, CultureInfo? culture); + + + /// <summary> + /// Returns an unmanaged memory stream object from the specified resource, using the specified <paramref name="culture"/>. + /// </summary> + /// <param name="name">The name of a resource.</param> + /// <param name="culture">An object that specifies the culture to use for the resource lookup. If <paramref name="culture"/> + /// is <c>null</c>, the culture for the current thread is used.</param> + /// <returns>An unmanaged memory stream object that represents a resource.</returns> + /// <exception cref="ArgumentNullException">The <paramref name="name"/> parameter is <c>null</c>.</exception> + /// <exception cref="InvalidOperationException">The value of the specified resource is not a <see cref="MemoryStream"/> object.</exception> + /// <exception cref="MissingManifestResourceException">No usable set of resources has been found, and there are + /// no resources for a default culture. For information about how to handle this exception, see the + /// "Handling MissingManifestResourceException and MissingSatelliteAssemblyException Exceptions" section + /// in the <see cref="ResourceManager"/> class topic.</exception> + /// <exception cref="MissingSatelliteAssemblyException">The default culture's resources reside in a satellite + /// assembly that could not be found. For information about how to handle this exception, see the + /// "Handling MissingManifestResourceException and MissingSatelliteAssemblyException Exceptions" section + /// in the <see cref="ResourceManager"/> class topic.</exception> + Stream? GetStream(string name, CultureInfo? culture); + } +}
