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

asf-gitbox-commits pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit 120b6be14dd92777ed95a438497a9ab628ab4f1b
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Fri Oct 16 15:46:38 2026 +0200

    Removed the deprecated `LocalizedException` interface.
---
 .../org/apache/sis/feature/EnvelopeOperation.java  |  8 +-
 .../sis/feature/FeatureOperationException.java     | 46 +++++-------
 .../sis/feature/InvalidFeatureException.java       | 38 +++++-----
 .../main/org/apache/sis/feature/package-info.java  |  2 +-
 .../sis/metadata/MetadataVisitorException.java     | 52 +++++++++----
 .../main/org/apache/sis/openoffice/CalcAddins.java | 20 +----
 .../sis/io/wkt/UnparsableObjectException.java      | 49 +++++++++----
 .../main/org/apache/sis/io/wkt/package-info.java   |  2 +-
 .../org/apache/sis/storage/DataStoreException.java | 55 +++++++++-----
 .../src/org.apache.sis.util/main/module-info.java  |  3 +-
 .../main/org/apache/sis/util/Exceptions.java       | 44 ++++-------
 .../org/apache/sis/util/LocalizedException.java    | 85 ----------------------
 .../internal/shared/LocalizedParseException.java   | 38 +++++++---
 .../main/org/apache/sis/util/logging/Logging.java  |  4 +-
 .../main/org/apache/sis/util/package-info.java     |  2 +-
 .../sis/util/resources/IndexedResourceBundle.java  |  8 +-
 .../shared/LocalizedParseExceptionTest.java        | 12 +--
 .../org/apache/sis/gui/referencing/WKTPane.java    |  7 +-
 18 files changed, 223 insertions(+), 252 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/EnvelopeOperation.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/EnvelopeOperation.java
index 5c2806c8ec..b3e00c8932 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/EnvelopeOperation.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/EnvelopeOperation.java
@@ -417,7 +417,7 @@ final class EnvelopeOperation extends AbstractOperation {
                         final Object geomCRS;
                         if (at != null && (geomCRS = at.getValue()) != null) {
                             if (!(geomCRS instanceof 
CoordinateReferenceSystem)) {
-                                throw new 
FeatureOperationException(Resources.formatInternational(
+                                throw new 
FeatureOperationException(Resources.format(
                                         
Resources.Keys.IllegalCharacteristicsType_3,
                                         AttributeConvention.CRS_CHARACTERISTIC,
                                         CoordinateReferenceSystem.class,
@@ -443,7 +443,7 @@ final class EnvelopeOperation extends AbstractOperation {
                         genv = Envelopes.transform(op, genv);
                     }
                 } catch (FactoryException | TransformException e) {
-                    throw new 
FeatureOperationException(Errors.formatInternational(Errors.Keys.CanNotTransformEnvelope),
 e);
+                    throw new 
FeatureOperationException(Errors.format(Errors.Keys.CanNotTransformEnvelope), 
e);
                 }
                 /*
                  * If there is only one geometry, we will return that geometry 
as-is even if its CRS is unknown.
@@ -454,7 +454,7 @@ final class EnvelopeOperation extends AbstractOperation {
                 if (envelope == null) {
                     envelope = genv;
                 } else if (hasUnknownCRS) {
-                    throw new 
FeatureOperationException(Errors.formatInternational(Errors.Keys.UnspecifiedCRS));
+                    throw new 
FeatureOperationException(Errors.format(Errors.Keys.UnspecifiedCRS));
                 } else if (targetCRS != null) {
                     envelope.add(genv);
                 } else {
@@ -470,7 +470,7 @@ final class EnvelopeOperation extends AbstractOperation {
             } else try {
                 return Envelopes.union(deferred);
             } catch (TransformException e) {
-                throw new 
FeatureOperationException(Errors.formatInternational(Errors.Keys.CanNotTransformEnvelope),
 e);
+                throw new 
FeatureOperationException(Errors.format(Errors.Keys.CanNotTransformEnvelope), 
e);
             }
         }
     }
diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/FeatureOperationException.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/FeatureOperationException.java
index dabb75dd2d..b37deb01d7 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/FeatureOperationException.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/FeatureOperationException.java
@@ -16,58 +16,48 @@
  */
 package org.apache.sis.feature;
 
-import org.opengis.util.InternationalString;
-import org.apache.sis.util.LocalizedException;
-
 
 /**
  * Thrown when a property value cannot be computed.
  * This exception may occur during a call to {@link 
AbstractAttribute#getValue()} on an attribute
  * instance which computes its value dynamically instead of returning a stored 
value.
- * It may be for example the attributes produced by {@link FeatureOperations}.
+ * It may be, for example, the attributes produced by {@link 
FeatureOperations}.
  *
  * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.8
+ * @since   1.8
  */
-final class FeatureOperationException extends IllegalStateException implements 
LocalizedException {
+public class FeatureOperationException extends IllegalStateException {
     /**
      * For cross-version compatibility.
      */
-    private static final long serialVersionUID = -7281160433831489357L;
-
-    /**
-     * A description of the computation error.
-     */
-    @SuppressWarnings("serial")                     // Most SIS 
implementations are serializable.
-    private final InternationalString message;
+    private static final long serialVersionUID = 6381299496396235246L;
 
     /**
-     * Creates a new exception with the given explanation message.
+     * Creates an exception with the specified details message.
      *
-     * @param message  a description of the computation error.
+     * @param message  the detail message in the default locale.
      */
-    FeatureOperationException(final InternationalString message) {
-        super(message.toString());
-        this.message = message;
+    public FeatureOperationException(String message) {
+        super(message);
     }
 
     /**
-     * Creates a new exception with the given explanation message and cause.
+     * Creates an exception with the specified cause and no details message.
      *
-     * @param message  a description of the computation error.
-     * @param cause    the cause of the error.
+     * @param cause  the cause for this exception.
      */
-    FeatureOperationException(final InternationalString message, final 
Exception cause) {
-        super(message.toString(), cause);
-        this.message = message;
+    public FeatureOperationException(Throwable cause) {
+        super(cause);
     }
 
     /**
-     * Returns the message in various locales.
+     * Creates an exception with the specified details message and cause.
      *
-     * @return the exception message.
+     * @param message  the detail message in the default locale.
+     * @param cause    the cause for this exception.
      */
-    @Override
-    public InternationalString getInternationalMessage() {
-        return message;
+    public FeatureOperationException(String message, Throwable cause) {
+        super(message, cause);
     }
 }
diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/InvalidFeatureException.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/InvalidFeatureException.java
index 6aeff94a2a..4910141115 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/InvalidFeatureException.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/InvalidFeatureException.java
@@ -17,7 +17,6 @@
 package org.apache.sis.feature;
 
 import org.opengis.util.InternationalString;
-import org.apache.sis.util.LocalizedException;
 
 // Specific to the geoapi-3.1 and geoapi-4.0 branches:
 import org.opengis.feature.Feature;
@@ -27,25 +26,20 @@ import org.opengis.feature.InvalidPropertyValueException;
 /**
  * Thrown when a feature fails at least one conformance test.
  *
- * <h2>API design note</h2>
- * This exception extends {@link InvalidPropertyValueException} because an 
Apache SIS feature
- * can be invalid only if a property is invalid.
+ * <p><b>API design note:</b> this exception extends {@link 
InvalidPropertyValueException}
+ * because an Apache <abbr>SIS</abbr> feature can be invalid only if a 
property is invalid.</p>
  *
  * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.8
+ * @since   1.8
  *
  * @see Features#validate(Feature)
  */
-final class InvalidFeatureException extends InvalidPropertyValueException 
implements LocalizedException {
+public class InvalidFeatureException extends InvalidPropertyValueException {
     /**
      * For cross-version compatibility.
      */
-    private static final long serialVersionUID = 7288810679876346027L;
-
-    /**
-     * A description of the illegal feature.
-     */
-    @SuppressWarnings("serial")                     // Most SIS 
implementations are serializable.
-    private final InternationalString message;
+    private static final long serialVersionUID = -8089121424988848183L;
 
     /**
      * Creates a new exception with the given explanation message.
@@ -54,16 +48,24 @@ final class InvalidFeatureException extends 
InvalidPropertyValueException implem
      */
     InvalidFeatureException(final InternationalString message) {
         super(message.toString());
-        this.message = message;
     }
 
     /**
-     * Returns the message in various locales.
+     * Creates an exception with the specified details message.
+     *
+     * @param message  the detail message in the default locale.
+     */
+    public InvalidFeatureException(String message) {
+        super(message);
+    }
+
+    /**
+     * Creates an exception with the specified details message and cause.
      *
-     * @return the exception message.
+     * @param message  the detail message in the default locale.
+     * @param cause    the cause for this exception.
      */
-    @Override
-    public InternationalString getInternationalMessage() {
-        return message;
+    public InvalidFeatureException(String message, Throwable cause) {
+        super(message, cause);
     }
 }
diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/package-info.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/package-info.java
index f10a0bf841..e8e9a140cf 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/package-info.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/package-info.java
@@ -93,7 +93,7 @@
  * @author  Travis L. Pinney
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.7
+ * @version 1.8
  * @since   0.5
  */
 package org.apache.sis.feature;
diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/MetadataVisitorException.java
 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/MetadataVisitorException.java
index 09ead057f7..085409e7a3 100644
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/MetadataVisitorException.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/MetadataVisitorException.java
@@ -16,8 +16,8 @@
  */
 package org.apache.sis.metadata;
 
-import org.opengis.util.InternationalString;
-import org.apache.sis.util.LocalizedException;
+import java.util.Locale;
+import org.apache.sis.util.Localized;
 import org.apache.sis.util.collection.BackingStoreException;
 import org.apache.sis.util.collection.Containers;
 import org.apache.sis.util.resources.Errors;
@@ -25,10 +25,12 @@ import org.apache.sis.util.resources.Errors;
 
 /**
  * Thrown when a {@link MetadataVisitor#visit(Class, Object)} method failed.
+ * The details message is created only when requested.
+ * The context-sensitive locale is inherited from the cause.
  *
  * @author  Martin Desruisseaux (Geomatys)
  */
-final class MetadataVisitorException extends BackingStoreException implements 
LocalizedException {
+final class MetadataVisitorException extends BackingStoreException implements 
Localized {
     /**
      * For cross-version compatibility.
      */
@@ -53,17 +55,31 @@ final class MetadataVisitorException extends 
BackingStoreException implements Lo
 
     /**
      * Returns an error message giving the location of the failure together 
with the cause.
+     *
+     * @return the detail message in the default locale.
      */
     @Override
     public String getMessage() {
-        return getInternationalMessage().toString();
+        return getMessage(false);
     }
 
     /**
-     * Returns an error message giving the location of the failure together 
with the cause.
+     * Returns an error message in a context-dependent locale if available.
+     *
+     * @return the detail message in the context-dependent locale.
      */
     @Override
-    public InternationalString getInternationalMessage() {
+    public String getLocalizedMessage() {
+        return getMessage(true);
+    }
+
+    /**
+     * Returns an error message giving the location of the failure together 
with the cause.
+     *
+     * @param  localized  whether to use context-dependent locale.
+     * @return the detail message in the given locale.
+     */
+    private String getMessage(final boolean localized) {
         short key = Errors.Keys.CanNotProcessProperty_2;
         int count = 2;
         String location = super.getMessage();
@@ -76,15 +92,9 @@ final class MetadataVisitorException extends 
BackingStoreException implements Lo
             }
         }
         final Throwable cause = getCause();
-        Object message = null;
-        if (cause instanceof LocalizedException) {
-            message = ((LocalizedException) cause).getInternationalMessage();
-        }
+        Object message = localized ? cause.getLocalizedMessage() : 
cause.getMessage();
         if (message == null) {
-            message = cause.getLocalizedMessage();
-            if (message == null) {
-                message = cause.getClass();
-            }
+            message = cause.getClass();
         }
         final var arguments = new Object[count];
         arguments[--count] = message;
@@ -92,6 +102,18 @@ final class MetadataVisitorException extends 
BackingStoreException implements Lo
         if (count != 0) {
             arguments[0] = String.join(".", 
Containers.viewAsUnmodifiableList(propertyPath, 0, pathLength));
         }
-        return Errors.formatInternational(key, arguments);
+        return Errors.forLocale(getLocale()).getString(key, arguments);
+    }
+
+    /**
+     * Returns the locale of the localized exception message, or {@code null} 
if unspecified.
+     * If non-null, this is the effective language of the string returned by 
{@link #getLocalizedMessage()}.
+     *
+     * @return the locale of the localized message, or {@code null} if not 
explicitly defined.
+     */
+    @Override
+    public Locale getLocale() {
+        final Throwable cause = getCause();
+        return (cause instanceof Localized) ? ((Localized) cause).getLocale() 
: null;
     }
 }
diff --git 
a/endorsed/src/org.apache.sis.openoffice/main/org/apache/sis/openoffice/CalcAddins.java
 
b/endorsed/src/org.apache.sis.openoffice/main/org/apache/sis/openoffice/CalcAddins.java
index d597cf0335..345eed443b 100644
--- 
a/endorsed/src/org.apache.sis.openoffice/main/org/apache/sis/openoffice/CalcAddins.java
+++ 
b/endorsed/src/org.apache.sis.openoffice/main/org/apache/sis/openoffice/CalcAddins.java
@@ -25,6 +25,7 @@ import com.sun.star.lang.XServiceInfo;
 import com.sun.star.lang.XServiceName;
 import com.sun.star.uno.XComponentContext;
 import com.sun.star.lib.uno.helper.WeakBase;
+import org.apache.sis.pending.jdk.JDK19;
 import org.apache.sis.util.Classes;
 import org.apache.sis.util.Exceptions;
 import org.apache.sis.util.resources.Vocabulary;
@@ -133,7 +134,7 @@ public abstract class CalcAddins extends WeakBase 
implements XServiceName, XServ
                 String language = locale.Language; if (language == null) 
language = "";
                 String country  = locale.Country;  if (country  == null) 
country  = "";
                 String variant  = locale.Variant;  if (variant  == null) 
variant  = "";
-                javaLocale = new java.util.Locale(language, country, variant);
+                javaLocale = JDK19.localeOf(language, country, variant);
             } else {
                 javaLocale = java.util.Locale.getDefault();
             }
@@ -150,20 +151,6 @@ public abstract class CalcAddins extends WeakBase 
implements XServiceName, XServ
         return 
Vocabulary.forLocale(getJavaLocale()).getString(Vocabulary.Keys.NotKnown);
     }
 
-    /**
-     * Returns the minimal length of the specified arrays. In the special case 
where one array
-     * has a length of 1, we assume that this single element will be repeated 
for all elements
-     * in the other array.
-     */
-    static int getMinimalLength(final Object[] array1, final Object[] array2) {
-        if (array1 == null || array2 == null) {
-            return 0;
-        }
-        if (array1.length == 1) return array2.length;
-        if (array2.length == 1) return array1.length;
-        return Math.min(array1.length, array2.length);
-    }
-
     /**
      * Returns the localized message from the specified exception. If no 
message is available,
      * returns a default string. This method never return a null value.
@@ -187,8 +174,9 @@ public abstract class CalcAddins extends WeakBase 
implements XServiceName, XServ
      * @param exception  the exception.
      */
     final void reportException(final String method, final Exception exception) 
{
+        @SuppressWarnings("LocalVariableHidesMemberVariable")
         final Logger logger = getLogger();
-        final LogRecord record = new LogRecord(Level.WARNING, 
getLocalizedMessage(exception));
+        final var record = new LogRecord(Level.WARNING, 
getLocalizedMessage(exception));
         record.setLoggerName(logger.getName());
         record.setSourceClassName(getClass().getCanonicalName());
         record.setSourceMethodName(method);
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/UnparsableObjectException.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/UnparsableObjectException.java
index bf90aeae0c..971e019691 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/UnparsableObjectException.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/UnparsableObjectException.java
@@ -18,15 +18,13 @@ package org.apache.sis.io.wkt;
 
 import java.util.Locale;
 import java.text.ParseException;
-import org.opengis.util.InternationalString;
-import org.apache.sis.util.LocalizedException;
+import org.apache.sis.util.Localized;
+import org.apache.sis.util.Workaround;
 import org.apache.sis.util.resources.Errors;
 
 
 /**
- * Thrown when a <i>Well Known Text</i> (WKT) cannot be parsed.
- *
- * <h2>Localization</h2>
+ * Thrown when a <i>Well Known Text</i> (<abbr>WKT</abbr>) cannot be parsed.
  * This exception may contain the error message in two languages:
  *
  * <ul>
@@ -38,15 +36,25 @@ import org.apache.sis.util.resources.Errors;
  * </ul>
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.8
  * @since   0.8
  */
-public class UnparsableObjectException extends ParseException implements 
LocalizedException {
+public class UnparsableObjectException extends ParseException implements 
Localized {
     /**
      * For cross-version compatibility.
      */
     private static final long serialVersionUID = 5949195205739826024L;
 
+    /**
+     * The effective locale of the localized message, or {@code null} if 
unspecified.
+     * This is the locale of the message returned by {@link 
#getLocalizedMessage()}.
+     * It is specified at construction time, then eventually replaced by the 
locale
+     * of the resource used for building the message.
+     *
+     * @see #getLocale()
+     */
+    private Locale locale;
+
     /**
      * The resources key as one of the {@link Errors.Keys} constant, or 0 if 
none.
      *
@@ -80,9 +88,18 @@ public class UnparsableObjectException extends 
ParseException implements Localiz
      * @param  errorOffset  the position where the error is found while 
parsing.
      */
     UnparsableObjectException(final Locale locale, final short key, final 
Object[] parameters, final int errorOffset) {
-        super(Errors.forLocale(locale).getString(key, parameters), 
errorOffset);
-        this.parameters = parameters;
+        this(Errors.forLocale(locale), key, parameters, errorOffset);
+    }
+
+    /**
+     * Workaround while waiting for JEP 513: Flexible Constructor Bodies.
+     */
+    @Workaround(library="JDK", version="11", fixed="25")
+    private UnparsableObjectException(final Errors resources, final short key, 
final Object[] parameters, final int errorOffset) {
+        super(resources.getString(key, parameters), errorOffset);
+        this.locale     = resources.getLocale();
         this.key        = key;
+        this.parameters = parameters;
     }
 
     /**
@@ -110,14 +127,18 @@ public class UnparsableObjectException extends 
ParseException implements Localiz
     }
 
     /**
-     * If this exception is capable to return the message in various locales, 
returns that message.
-     * Otherwise returns {@code null}.
+     * Returns the locale of the localized exception message, or {@code null} 
if unspecified.
+     * If non-null, this is the effective language of the string returned by 
{@link #getLocalizedMessage()}.
+     * This locale depends on the {@linkplain WKTFormat#getLocale() locale 
configured on the WKT parser} and
+     * the resources available in Apache <abbr>SIS</abbr>.
+     *
+     * @return the locale of the localized message, or {@code null} if not 
explicitly defined.
      *
-     * @return the exception message, or {@code null} if this exception cannot 
produce international message.
+     * @since 1.8
      */
     @Override
-    public InternationalString getInternationalMessage() {
-        return (key != 0) ? Errors.formatInternational(key, parameters) : null;
+    public Locale getLocale() {
+        return locale;
     }
 
     /**
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/package-info.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/package-info.java
index e53edbfd09..f6dcb9bb84 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/package-info.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/package-info.java
@@ -82,7 +82,7 @@
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @author  Rémi Eve (IRD)
  * @author  Rueben Schulz (UBC)
- * @version 1.7
+ * @version 1.8
  * @since   0.4
  */
 package org.apache.sis.io.wkt;
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/DataStoreException.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/DataStoreException.java
index ad301679ed..d4f5686c7d 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/DataStoreException.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/DataStoreException.java
@@ -17,8 +17,7 @@
 package org.apache.sis.storage;
 
 import java.util.Locale;
-import org.opengis.util.InternationalString;
-import org.apache.sis.util.LocalizedException;
+import org.apache.sis.util.Localized;
 import org.apache.sis.util.Workaround;
 import org.apache.sis.storage.internal.Resources;
 import org.apache.sis.io.stream.IOUtilities;
@@ -27,26 +26,35 @@ import org.apache.sis.io.stream.IOUtilities;
 /**
  * Thrown when a {@link DataStore} cannot complete a read or write operation.
  *
- * <h2>Localization</h2>
- * The {@link #getMessage()} and {@link #getLocalizedMessage()} methods return 
the same message,
- * but sometimes in different languages. The general policy is that {@link 
#getMessage()} returns
- * the message in the JVM {@linkplain Locale#getDefault() default locale} 
while {@link #getLocalizedMessage()}
- * returns the message in the locale specified by the last call to {@link 
DataStore#setLocale(Locale)}.
+ * <p><b>Localization:</b>
+ * The exception {@linkplain #getMessage() message} is usually in a language
+ * determined by the <abbr>JVM</abbr>-wide {@linkplain Locale#getDefault() 
default locale}.
+ * In addition, a {@linkplain #getLocalizedMessage() localized message} may 
also be available in a
+ * language determined by the {@linkplain DataStore#getLocale() locale 
configured on the data store}.
  * In a client-server architecture, the former is typically the locale of the 
system administrator
- * while the latter is presumably the locale of the client connected to the 
server.
- * However, this policy is applied on a <em>best-effort</em> basis only.
+ * while the latter should be the locale of the client connected to the 
server.</p>
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.8
  * @since   0.3
  */
-public class DataStoreException extends Exception implements 
LocalizedException {
+public class DataStoreException extends Exception implements Localized {
     /**
      * For cross-version compatibility.
      */
     private static final long serialVersionUID = -1778987176103191950L;
 
+    /**
+     * The effective locale of the localized message, or {@code null} if 
unspecified.
+     * This is the locale of the message returned by {@link 
#getLocalizedMessage()}.
+     * It is specified at construction time, then eventually replaced by the 
locale
+     * of the resource used for building the message.
+     *
+     * @see #getLocale()
+     */
+    private Locale locale;
+
     /**
      * The resources key as one of the {@link Resources.Keys} constant, or 0 
if none.
      *
@@ -137,7 +145,16 @@ public class DataStoreException extends Exception 
implements LocalizedException
      * @param parameters  parameters to use for formatting the messages.
      */
     DataStoreException(final Locale locale, final short key, final Object... 
parameters) {
-        super(Resources.forLocale(locale).getString(key, parameters));
+        this(Resources.forLocale(locale), key, parameters);
+    }
+
+    /**
+     * Workaround while waiting for JEP 513: Flexible Constructor Bodies.
+     */
+    @Workaround(library="JDK", version="11", fixed="25")
+    private DataStoreException(final Resources resources, final short key, 
final Object[] parameters) {
+        super(resources.getString(key, parameters));
+        this.locale     = resources.getLocale();
         this.key        = key;
         this.parameters = parameters;
     }
@@ -179,16 +196,18 @@ public class DataStoreException extends Exception 
implements LocalizedException
     }
 
     /**
-     * If this exception is capable to return the message in various locales, 
returns that message.
-     * Otherwise returns {@code null}.
+     * Returns the locale of the localized exception message, or {@code null} 
if unspecified.
+     * If non-null, this is the effective language of the string returned by 
{@link #getLocalizedMessage()}.
+     * This locale depends on the {@linkplain DataStore#getLocale() locale 
configured on the data store} and
+     * the resources available in Apache <abbr>SIS</abbr>.
      *
-     * @return the exception message, or {@code null} if this exception cannot 
produce international message.
+     * @return the locale of the localized message, or {@code null} if not 
explicitly defined.
      *
-     * @since 0.8
+     * @since 1.8
      */
     @Override
-    public InternationalString getInternationalMessage() {
-        return (key != 0) ? Resources.formatInternational(key, parameters) : 
null;
+    public Locale getLocale() {
+        return locale;
     }
 
     /**
diff --git a/endorsed/src/org.apache.sis.util/main/module-info.java 
b/endorsed/src/org.apache.sis.util/main/module-info.java
index aee6c12b11..f69aa636f4 100644
--- a/endorsed/src/org.apache.sis.util/main/module-info.java
+++ b/endorsed/src/org.apache.sis.util/main/module-info.java
@@ -22,7 +22,7 @@
  *
  * @author  Martin Desruisseaux (MPO, IRD, Geomatys)
  * @author  Alexis Manin (Geomatys)
- * @version 1.7
+ * @version 1.8
  * @since   0.3
  */
 module org.apache.sis.util {
@@ -178,6 +178,7 @@ module org.apache.sis.util {
             org.apache.sis.storage.netcdf,
             org.apache.sis.storage.geoheif,
             org.apache.sis.storage.geotiff,
+            org.apache.sis.openoffice,
             org.apache.sis.console,
             org.apache.sis.portrayal,
             org.apache.sis.gui;                         // In the "optional" 
sub-project.
diff --git 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/Exceptions.java 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/Exceptions.java
index e0826556a6..d792d9fd04 100644
--- a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/Exceptions.java
+++ b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/Exceptions.java
@@ -25,7 +25,6 @@ import java.io.UncheckedIOException;
 import java.nio.file.DirectoryIteratorException;
 import java.lang.reflect.InvocationTargetException;
 import java.util.concurrent.ExecutionException;
-import org.opengis.util.InternationalString;
 import org.apache.sis.util.resources.Vocabulary;
 import org.apache.sis.util.collection.BackingStoreException;
 
@@ -51,7 +50,7 @@ import org.apache.sis.util.collection.BackingStoreException;
  * This allows system administrator to analyze the issue without the need to 
understand client's language.</p>
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 1.7
+ * @version 1.8
  * @since   0.3
  */
 public final class Exceptions {
@@ -62,47 +61,36 @@ public final class Exceptions {
     }
 
     /**
-     * Returns the message of the given exception, localized in the given 
locale if possible.
-     * Some exceptions created by SIS can format a message in different 
locales. This method
-     * returns such localized message if possible, or fallback on the standard 
JDK methods otherwise.
-     * More specifically:
+     * Returns the message of the given exception with a preference for the 
given locale.
+     * The heuristic rules applied by this method may change between different 
versions of
+     * Apache <abbr>SIS</abbr>. The current rules are:
      *
      * <ul>
-     *   <li>If the given {@code exception} is null, then this method returns 
{@code null}.</li>
-     *   <li>Otherwise if the given {@code locale} is null, then this method 
returns {@link Exception#getMessage()}.
-     *       This is consistent with the {@link Localized} policy saying that 
null locale stands for "unlocalized"
-     *       message (usually in English) or message in the JVM {@linkplain 
Locale#getDefault() default locale}.</li>
-     *   <li>Otherwise if the given {@code exception} is an instance of {@link 
LocalizedException} providing
-     *       a non-null {@linkplain 
LocalizedException#getInternationalMessage() international message},
-     *       then this method returns the result of {@link 
InternationalString#toString(Locale)}.</li>
-     *   <li>Otherwise this method returns {@link 
Exception#getLocalizedMessage()}.</li>
+     *   <li>If the given {@code exception} is null, returns {@code null}.</li>
+     *   <li>If the given {@code locale} is null, returns {@link 
Exception#getMessage()}.</li>
+     *   <li>If the given {@code exception} does <em>not</em> implement {@link 
Localized},
+     *       returns {@link Exception#getLocalizedMessage()}.</li>
+     *   <li>Otherwise, this method compares {@link Localized#getLocale()} 
with the given locale
+     *       for choosing between {@code getMessage()} and {@code 
getLocalizedMessage()}.</li>
      * </ul>
      *
      * @param  exception  the exception from which to get the localize 
message, or {@code null}.
-     * @param  locale     the preferred locale for the message, or {@code 
null} for the JVM default locale.
+     * @param  locale     the preferred locale for the message, or {@code 
null} if unspecified.
      *                    This locale is honored on a <em>best effort</em> 
basis only.
      * @return the message in the given locale if possible, or {@code null} if 
the {@code exception}
      *         argument was {@code null} or if the exception does not contain 
a message.
-     *
-     * @see LocalizedException#getLocalizedMessage()
-     *
-     * @deprecated Depends on {@link LocalizedException}, which has been 
deprecated.
      */
-    @Deprecated(since = "1.7", forRemoval = true)
     public static String getLocalizedMessage(final Throwable exception, final 
Locale locale) {
         if (exception == null) {
             return null;
         }
         if (locale == null) {
-            return exception.getMessage();      // See the policy documented 
in LocalizedException.getMessage()
+            return exception.getMessage();
         }
-        if (exception instanceof LocalizedException) {
-            final InternationalString i18n = ((LocalizedException) 
exception).getInternationalMessage();
-            if (i18n != null) {
-                final String message = i18n.toString(locale);
-                if (message != null) {
-                    return message;
-                }
+        if (exception instanceof Localized) {
+            final Locale actual = ((Localized) exception).getLocale();
+            if (actual != null && 
!locale.getLanguage().equalsIgnoreCase(actual.getLanguage())) {
+                return exception.getMessage();
             }
         }
         return exception.getLocalizedMessage();
diff --git 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/LocalizedException.java
 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/LocalizedException.java
deleted file mode 100644
index 1f5c1a35cb..0000000000
--- 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/LocalizedException.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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.
- */
-package org.apache.sis.util;
-
-import java.util.Locale;
-import org.opengis.util.InternationalString;
-
-
-/**
- * An exception which can produce an error message in the client locale.
- * Exceptions implementing this interface apply the following policy:
- *
- * <ul>
- *   <li>{@link #getMessage()} returns the message in the {@linkplain 
Locale#getDefault() default locale}.
- *       In a client-server architecture, this is often the locale on the 
server side.</li>
- *   <li>{@link #getLocalizedMessage()} returns the message in a locale that 
depends on the context
- *       in which the exception has been thrown. This is often the locale used 
by a {@link java.text.Format}
- *       or {@link org.apache.sis.storage.DataStore} instance,
- *       and can be presumed to be the locale on the client side.</li>
- *   <li>{@link #getInternationalMessage()} may return the message in 
arbitrary locale (optional operation).
- *       This method is specific to Apache SIS.</li>
- * </ul>
- *
- * <h2>Example</h2>
- * If an error occurred while a Japanese client connected to an European 
server, the localized message may be sent
- * to the client in Japanese language while the same error may be logged on 
the server side in the French language.
- * This allows system administrator to analyze the issue without the need to 
understand client's language.
- *
- * The above policy is applied on a <em>best-effort</em> basis only. For 
example, exceptions that
- * do not implement {@code LocalizedException} may use any locale (not 
necessarily the default one),
- * and {@code LocalizedException} used as {@linkplain 
Exception#Exception(Throwable) wrappers} around
- * other exception usually lost their localization capability.
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @version 1.7
- *
- * @see Exceptions#getLocalizedMessage(Throwable, Locale)
- * @see org.apache.sis.storage.DataStore#setLocale(Locale)
- *
- * @since 0.8
- *
- * @deprecated Rarely used in practice and support is unequal.
- */
-@Deprecated(since = "1.7", forRemoval = true)
-public interface LocalizedException {
-    /**
-     * Returns the message in the {@linkplain Locale#getDefault() default 
locale}.
-     * In a client-server architecture, this is usually the locale on the 
server side.
-     * This is the recommended language for logging messages to be read by 
system administrators.
-     *
-     * @return the exception message in the JVM {@linkplain 
Locale#getDefault() default locale}.
-     */
-    String getMessage();
-
-    /**
-     * Returns the message in the locale that depends on the context in which 
this exception has been thrown.
-     * For example, it may be the local of a client application connected to a 
distant server.
-     * This is the recommended language to show in widgets.
-     *
-     * @return the exception message in the locale of a service configured for 
a particular client.
-     */
-    String getLocalizedMessage();
-
-    /**
-     * If this exception is capable to return the message in various locales, 
returns that message.
-     * Otherwise returns {@code null}.
-     *
-     * @return the exception message, or {@code null} if this exception cannot 
produce international message.
-     */
-    InternationalString getInternationalMessage();
-}
diff --git 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/LocalizedParseException.java
 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/LocalizedParseException.java
index 7f7cc74cc0..9eea5a2057 100644
--- 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/LocalizedParseException.java
+++ 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/LocalizedParseException.java
@@ -19,10 +19,9 @@ package org.apache.sis.util.internal.shared;
 import java.util.Locale;
 import java.text.ParsePosition;
 import java.text.ParseException;
-import org.opengis.util.InternationalString;
 import org.apache.sis.util.Workaround;
 import org.apache.sis.util.CharSequences;
-import org.apache.sis.util.LocalizedException;
+import org.apache.sis.util.Localized;
 import org.apache.sis.util.resources.Errors;
 
 
@@ -41,12 +40,22 @@ import org.apache.sis.util.resources.Errors;
  *
  * @author  Martin Desruisseaux (Geomatys)
  */
-public final class LocalizedParseException extends ParseException implements 
LocalizedException {
+public final class LocalizedParseException extends ParseException implements 
Localized {
     /**
      * For cross-version compatibility.
      */
     private static final long serialVersionUID = -1467571540435486742L;
 
+    /**
+     * The effective locale of the localized message, or {@code null} if 
unspecified.
+     * This is the locale of the message returned by {@link 
#getLocalizedMessage()}.
+     * It is specified at construction time, then eventually replaced by the 
locale
+     * of the resource used for building the message.
+     *
+     * @see #getLocale()
+     */
+    private final Locale locale;
+
     /**
      * The resources key as one of the {@link Errors.Keys} constant, or 0 if 
none.
      *
@@ -71,7 +80,16 @@ public final class LocalizedParseException extends 
ParseException implements Loc
      * @param  errorOffset  the position where the error is found while 
parsing.
      */
     public LocalizedParseException(final Locale locale, final short key, final 
Object[] parameters, final int errorOffset) {
-        super(Errors.forLocale(locale).getString(key, parameters), 
errorOffset);
+        this(Errors.forLocale(locale), key, parameters, errorOffset);
+    }
+
+    /**
+     * Workaround while waiting for JEP 513: Flexible Constructor Bodies.
+     */
+    @Workaround(library="JDK", version="11", fixed="25")
+    private LocalizedParseException(final Errors resources, final short key, 
final Object[] parameters, final int errorOffset) {
+        super(resources.getString(key, parameters), errorOffset);
+        this.locale     = resources.getLocale();
         this.parameters = parameters;
         this.key        = key;
     }
@@ -168,14 +186,16 @@ public final class LocalizedParseException extends 
ParseException implements Loc
     }
 
     /**
-     * If this exception is capable to return the message in various locales, 
returns that message.
-     * Otherwise returns {@code null}.
+     * Returns the locale of the localized exception message, or {@code null} 
if unspecified.
+     * If non-null, this is the effective language of the string returned by 
{@link #getLocalizedMessage()}.
+     *
+     * @return the locale of the localized message, or {@code null} if not 
explicitly defined.
      *
-     * @return the exception message, or {@code null} if this exception cannot 
produce international message.
+     * @since 1.8
      */
     @Override
-    public InternationalString getInternationalMessage() {
-        return (key != 0) ? Errors.formatInternational(key, parameters) : null;
+    public Locale getLocale() {
+        return locale;
     }
 
     /**
diff --git 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/logging/Logging.java
 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/logging/Logging.java
index f9e9d5f6f1..9ef85b274d 100644
--- 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/logging/Logging.java
+++ 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/logging/Logging.java
@@ -269,9 +269,9 @@ public final class Logging {
         /*
          * The message is fetched using Exception.getMessage() instead of 
getLocalizedMessage()
          * because in a client-server architecture, we want the locale on the 
server-side instead
-         * than the locale on the client side. See LocalizedException policy.
+         * than the locale on the client side. See the policy documented in 
the `Exceptions` class.
          */
-        final StringBuilder buffer = new 
StringBuilder(256).append(Classes.getShortClassName(error));
+        final var buffer = new 
StringBuilder(256).append(Classes.getShortClassName(error));
         String message = error.getMessage();        // Targeted to system 
administrators (see above).
         if (message != null) {
             buffer.append(": ").append(message);
diff --git 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/package-info.java 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/package-info.java
index 28291f7284..a0e0b8af13 100644
--- 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/package-info.java
+++ 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/package-info.java
@@ -39,7 +39,7 @@
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Alexis Manin (Geomatys)
- * @version 1.7
+ * @version 1.8
  * @since   0.3
  */
 package org.apache.sis.util;
diff --git 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/IndexedResourceBundle.java
 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/IndexedResourceBundle.java
index 998e711792..106a6cfa8e 100644
--- 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/IndexedResourceBundle.java
+++ 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/IndexedResourceBundle.java
@@ -294,7 +294,7 @@ public abstract class IndexedResourceBundle extends 
ResourceBundle implements Lo
                     /*
                      * Loads resources from the UTF file.
                      */
-                    try (DataInputStream input = new DataInputStream(new 
BufferedInputStream(resources))) {
+                    try (var input = new DataInputStream(new 
BufferedInputStream(resources))) {
                         values = new String[input.readInt()];
                         for (int i=0; i<values.length; i++) {
                             values[i] = input.readUTF();
@@ -307,9 +307,11 @@ public abstract class IndexedResourceBundle extends 
ResourceBundle implements Lo
                         record.setMessage(exception.getMessage());             
 // For administrator, use system locale.
                         record.setThrown (exception);
                         Logging.completeAndLog(LOGGER, 
IndexedResourceBundle.class, methodName, record);
-                        throw (MissingResourceException) new 
MissingResourceException(
+                        var e = new MissingResourceException(
                                 Exceptions.getLocalizedMessage(exception, 
locale),   // For users, use requested locale.
-                                baseName, key).initCause(exception);
+                                baseName, key);
+                        e.initCause(exception);
+                        throw e;
                     }
                     /*
                      * Now, logs the message. This message is provided only in 
English.
diff --git 
a/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/internal/shared/LocalizedParseExceptionTest.java
 
b/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/internal/shared/LocalizedParseExceptionTest.java
index 32ae104b0a..3ba1de9a6d 100644
--- 
a/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/internal/shared/LocalizedParseExceptionTest.java
+++ 
b/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/internal/shared/LocalizedParseExceptionTest.java
@@ -50,16 +50,18 @@ public final class LocalizedParseExceptionTest extends 
TestCase {
         final var pos = new ParsePosition(0);
         pos.setErrorIndex(5);
         final var e = new LocalizedParseException(Locale.CANADA, Angle.class, 
"Some text to parse", pos);
-        String message = e.getLocalizedMessage();
+        final String message = e.getLocalizedMessage();
         assertTrue(message.contains("Some text to parse"), message);
         assertTrue(message.contains("cannot be parsed"), message);
         assertTrue(message.contains("Angle"), message);
 
         assertEquals(message, Exceptions.getLocalizedMessage(e, 
Locale.CANADA));
-        message = Exceptions.getLocalizedMessage(e, Locale.FRANCE);
-        assertTrue(message.contains("Some text to parse"), message);
-        assertTrue(message.contains("n’est pas reconnu"), message);
-        assertTrue(message.contains("Angle"), message);
+        final String localized = Exceptions.getLocalizedMessage(e, 
Locale.FRANCE);
+        if (!localized.equals(message)) {    // Locale-dependent test.
+            assertTrue(localized.contains("Some text to parse"), localized);
+            assertTrue(localized.contains("n’est pas reconnu"), localized);
+            assertTrue(localized.contains("Angle"), localized);
+        }
     }
 
     /**
diff --git 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/referencing/WKTPane.java
 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/referencing/WKTPane.java
index 98cd70a217..49d650150a 100644
--- 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/referencing/WKTPane.java
+++ 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/referencing/WKTPane.java
@@ -72,6 +72,7 @@ final class WKTPane extends StringConverter<Convention> 
implements ChangeListene
     /**
      * Creates a new pane for showing CRS Well Known Text.
      */
+    @SuppressWarnings("LeakingThisInConstructor")
     WKTPane(final Locale locale) {
         final Convention[] sc = {           // Selected conventions in the 
order we want them to appear.
             Convention.WKT2_SIMPLIFIED,
@@ -110,11 +111,11 @@ final class WKTPane extends StringConverter<Convention> 
implements ChangeListene
             case WKT1_COMMON_UNITS: version = "GDAL 1-2"; break;
             default: return c.name();
         }
-        String text = vocabulary.getString(Vocabulary.Keys.Version_2, "WKT 
(Well Known Text)", version);
+        String label = vocabulary.getString(Vocabulary.Keys.Version_2, "WKT 
(Well Known Text)", version);
         if (simplified) {
-            text += " — " + vocabulary.getString(Vocabulary.Keys.Simplified);
+            label += " — " + vocabulary.getString(Vocabulary.Keys.Simplified);
         }
-        return text;
+        return label;
     }
 
     /**

Reply via email to