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

desruisseaux pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/sis.git

commit fed83f0af11c1ff84e0e1c63821b34364b51abc9
Merge: ae65a8be08 64feb29631
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Fri Jan 24 18:14:34 2025 +0100

    Merge branch 'geoapi-3.1'

 .../apache/sis/buildtools/gradle/Assembler.java    |   2 +-
 .../org/apache/sis/coverage/SampleRangeFormat.java |   6 +-
 .../sis/coverage/grid/BufferedGridCoverage.java    |   4 +-
 .../apache/sis/coverage/grid/DomainLinearizer.java |   4 +-
 .../apache/sis/coverage/grid/GridCoverage2D.java   |  23 +-
 .../apache/sis/coverage/grid/GridDerivation.java   | 257 ++++++++----
 .../org/apache/sis/coverage/grid/GridExtent.java   | 235 +++++++----
 .../org/apache/sis/coverage/grid/GridGeometry.java | 237 +++++++++--
 .../apache/sis/coverage/grid/PixelTranslation.java |  28 +-
 .../sis/coverage/grid/ResampledGridCoverage.java   |  10 +-
 .../apache/sis/coverage/grid/SliceGeometry.java    |   2 +-
 .../sis/coverage/privy/CommonDomainFinder.java     |  18 +-
 .../main/org/apache/sis/feature/FeatureFormat.java |   9 +-
 .../main/org/apache/sis/image/ComputedImage.java   |   2 +-
 .../main/org/apache/sis/image/ComputedTiles.java   |  12 +-
 .../main/org/apache/sis/image/ImageOverlay.java    |  59 ++-
 .../main/org/apache/sis/image/ImageProcessor.java  |   9 +-
 .../main/org/apache/sis/image/PlanarImage.java     |   9 +-
 .../main/org/apache/sis/image/TileCache.java       |   5 +-
 .../apache/sis/image/privy/AssertionMessages.java  |  87 ++++
 .../grid => image/privy}/ReshapedImage.java        |  51 ++-
 .../apache/sis/image/privy/TilePlaceholder.java    |   5 +-
 .../sis/coverage/grid/GridDerivationTest.java      | 138 ++++---
 .../apache/sis/coverage/grid/GridExtentTest.java   |  60 ++-
 .../apache/sis/coverage/grid/GridGeometryTest.java |  87 +++-
 .../coverage/grid/ResampledGridCoverageTest.java   |   1 +
 .../grid => image/privy}/ReshapedImageTest.java    |  12 +-
 .../org/apache/sis/metadata/privy/Identifiers.java |   2 +-
 .../main/org/apache/sis/metadata/sql/Citations.sql |   2 +-
 .../apache/sis/xml/bind/lan/LocaleAndCharset.java  |  10 +-
 .../org/apache/sis/xml/bind/lan/PT_FreeText.java   |  10 +-
 .../apache/sis/xml/bind/gco/StringAdapterTest.java |   2 +-
 .../sis/xml/bind/lan/FreeTextMarshallingTest.java  |   2 +-
 .../coverage/MultiResolutionCoverageLoader.java    |   2 +-
 .../org/apache/sis/map/coverage/RenderingData.java |  30 +-
 .../sis/referencing/gazetteer/LocationFormat.java  |   7 +-
 .../org/apache/sis/geometry/EnvelopeReducer.java   |   7 +-
 .../main/org/apache/sis/geometry/Envelopes.java    |  30 +-
 .../org/apache/sis/parameter/ParameterFormat.java  |  41 +-
 .../main/org/apache/sis/referencing/CRS.java       |   6 +-
 .../apache/sis/referencing/GeodeticCalculator.java |   6 +-
 .../sis/referencing/ImmutableIdentifier.java       | 131 +++---
 .../apache/sis/referencing/NamedIdentifier.java    |  24 +-
 .../sis/referencing/StandardDefinitions.java       |  14 +-
 .../org/apache/sis/referencing/cs/AxisName.java    |   2 +-
 .../main/org/apache/sis/referencing/cs/Codes.java  |   6 +-
 .../sis/referencing/cs/CoordinateSystems.java      |  33 +-
 .../cs/DefaultCoordinateSystemAxis.java            |   4 +-
 .../sis/referencing/cs/DirectionAlongMeridian.java |   4 +-
 .../org/apache/sis/referencing/cs/Normalizer.java  |  12 +-
 .../operation/builder/LinearTransformBuilder.java  |  28 +-
 .../referencing/operation/builder/Linearizer.java  |  11 +-
 .../operation/builder/ProjectedTransformTry.java   |   6 +-
 .../sis/referencing/operation/gridded/Tile.java    |   6 +-
 .../operation/provider/MapProjection.java          |  19 +-
 .../operation/provider/PseudoMercator.java         |  10 +
 .../operation/provider/PseudoSinusoidal.java       |  10 +
 .../sis/referencing/privy/AxisDirections.java      |   2 +-
 .../sis/referencing/NamedIdentifierTest.java       |   2 +-
 .../sis/referencing/cs/CoordinateSystemsTest.java  |  22 +-
 .../operation/builder/LinearizerTest.java          |   3 +-
 .../projection/MercatorMethodComparison.java       |  10 +-
 .../operation/transform/MathTransformTestCase.java |   2 +-
 .../sis/test/integration/ConsistencyTest.java      |  12 +-
 .../org/apache/sis/storage/geotiff/DataCube.java   |   6 +-
 .../org/apache/sis/storage/geotiff/DataSubset.java |   2 +-
 .../apache/sis/storage/geotiff/GeoTiffStore.java   |  14 +
 .../sis/storage/geotiff/ImageFileDirectory.java    |   2 +-
 .../sis/storage/geotiff/MultiResolutionImage.java  |   2 +-
 .../sis/storage/geotiff/reader/CRSBuilder.java     |   4 +-
 .../sis/storage/geotiff/writer/GeoEncoder.java     | 158 +++++---
 .../apache/sis/storage/netcdf/MetadataReader.java  |  16 +-
 .../apache/sis/storage/netcdf/base/Dimension.java  |   2 +-
 .../sis/storage/netcdf/base/RasterResource.java    |  14 +-
 .../sis/storage/netcdf/MetadataReaderTest.java     |   2 -
 .../main/org/apache/sis/storage/gpx/Metadata.java  |  10 +-
 .../org/apache/sis/io/stream/ByteRangeChannel.java |   4 +-
 .../org/apache/sis/io/stream/ChannelDataInput.java | 135 ++++++-
 .../apache/sis/io/stream/FileCacheByteChannel.java |   2 +-
 .../apache/sis/io/stream/HyperRectangleWriter.java |  34 +-
 .../main/org/apache/sis/io/stream/Region.java      |   2 +-
 .../apache/sis/storage/GridCoverageResource.java   |   4 +-
 .../main/org/apache/sis/storage/URLDataSource.java |  25 +-
 .../sis/storage/aggregate/AggregatedResource.java  | 182 ++++++++-
 .../aggregate/BandAggregateGridResource.java       |  78 ++--
 .../aggregate/ConcatenatedGridCoverage.java        | 391 ++++++++----------
 .../aggregate/ConcatenatedGridResource.java        | 442 +++++++++++----------
 .../sis/storage/aggregate/CoverageAggregator.java  |  77 ++--
 .../sis/storage/aggregate/DimensionSelector.java   |  99 +++--
 .../apache/sis/storage/aggregate/GridSlice.java    | 233 +++++++----
 .../sis/storage/aggregate/GridSliceLocator.java    | 210 ++++------
 .../org/apache/sis/storage/aggregate/Group.java    |  79 +++-
 .../sis/storage/aggregate/GroupAggregate.java      | 175 ++------
 .../apache/sis/storage/aggregate/GroupByCRS.java   |  50 +--
 .../sis/storage/aggregate/GroupBySample.java       |  57 ++-
 .../sis/storage/aggregate/GroupByTransform.java    | 121 ++++--
 .../sis/storage/aggregate/MergeStrategy.java       | 222 ++++++++---
 .../sis/storage/base/GridResourceWrapper.java      |   1 +
 .../org/apache/sis/storage/base/LegalSymbols.java  | 107 ++++-
 .../sis/storage/base/MemoryGridResource.java       |  44 +-
 .../apache/sis/storage/base/MetadataBuilder.java   |   8 +-
 .../apache/sis/storage/base/TiledGridCoverage.java | 201 +++++++---
 .../apache/sis/storage/base/TiledGridResource.java |  16 +-
 .../org/apache/sis/storage/esri/WritableStore.java |   1 +
 .../apache/sis/storage/image/WritableStore.java    |   8 +-
 .../org/apache/sis/storage/internal/Resources.java |  11 +-
 .../sis/storage/internal/Resources.properties      |   5 +-
 .../sis/storage/internal/Resources_fr.properties   |   5 +-
 .../apache/sis/io/stream/ChannelDataInputTest.java | 111 +++++-
 .../sis/io/stream/HyperRectangleWriterTest.java    |  44 ++
 .../aggregate/BandAggregateGridResourceTest.java   |   4 +-
 .../storage/aggregate/CoverageAggregatorTest.java  | 107 ++++-
 .../sis/storage/aggregate/CoverageMosaicTest.java  | 379 ++++++++++++++++++
 .../sis/storage/aggregate/OpaqueGridResource.java  |  11 +-
 .../sis/storage/base/MetadataBuilderTest.java      |  59 +--
 .../main/org/apache/sis/io/TableAppender.java      |   7 +-
 .../main/org/apache/sis/io/TabularFormat.java      |  10 +-
 .../main/org/apache/sis/math/StatisticsFormat.java |   9 +-
 .../main/org/apache/sis/util/CharSequences.java    |  16 +-
 .../sis/util/DefaultInternationalString.java       |  39 +-
 .../sis/util/collection/DefaultTreeTable.java      |  25 +-
 .../org/apache/sis/util/collection/TreeTable.java  |  21 +-
 .../sis/util/collection/TreeTableFormat.java       |  12 +-
 .../org/apache/sis/util/privy/AbstractMap.java     |   8 +-
 .../main/org/apache/sis/util/privy/Strings.java    |  61 ++-
 .../org/apache/sis/test/LogRecordCollector.java    |   2 +-
 .../sis/util/DefaultInternationalStringTest.java   |   8 +-
 .../sis/util/SimpleInternationalStringTest.java    |   8 +-
 .../sis/util/collection/TreeTableFormatTest.java   |   2 +-
 .../sis/storage/shapefile/shp/ShapeRecord.java     |   6 +-
 netbeans-project/ivy.xml                           |   2 +-
 optional/src/org.apache.sis.gui/bundle/bin/sisfx   |  12 +
 .../apache/sis/gui/coverage/CoverageCanvas.java    |   4 +-
 .../apache/sis/gui/internal/io/FileAccessItem.java |   2 +-
 .../main/org/apache/sis/gui/map/MapCanvas.java     |   2 +-
 .../main/org/apache/sis/gui/map/StatusBar.java     |   6 +-
 .../main/org/apache/sis/storage/gdal/Band.java     |  17 +-
 .../org/apache/sis/storage/gdal/TiledCoverage.java |  34 +-
 .../org/apache/sis/storage/gdal/TiledResource.java |  17 +-
 settings.gradle.kts                                |   2 +-
 140 files changed, 4190 insertions(+), 2020 deletions(-)

diff --cc 
endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridExtent.java
index 2737c6a1d3,7d17cc4192..dc50188b69
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridExtent.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridExtent.java
@@@ -62,14 -64,14 +64,12 @@@ import org.apache.sis.referencing.opera
  import org.apache.sis.referencing.operation.transform.TransformSeparator;
  import org.apache.sis.math.MathFunctions;
  import org.apache.sis.io.TableAppender;
- import org.apache.sis.util.iso.Types;
- import org.apache.sis.util.logging.Logging;
  import org.apache.sis.system.Modules;
  
 -// Specific to the geoapi-3.1 and geoapi-4.0 branches:
 -import org.opengis.coordinate.MismatchedDimensionException;
 -import org.opengis.coverage.CannotEvaluateException;
 -import org.opengis.coverage.PointOutsideCoverageException;
 -import org.opengis.coverage.grid.GridEnvelope;
 -import org.opengis.coverage.grid.GridCoordinates;
 +// Specific to the main branch:
 +import org.opengis.geometry.MismatchedDimensionException;
 +import org.apache.sis.coverage.CannotEvaluateException;
 +import org.apache.sis.coverage.PointOutsideCoverageException;
  
  
  /**
@@@ -1765,10 -1817,10 +1775,10 @@@ public class GridExtent implements Seri
                  if (c >= low && c <= high) {
                      slice.coordinates[i + m] = slice.coordinates[i] = c;
                  } else {
-                     final StringBuilder b = new StringBuilder();
+                     final var b = new StringBuilder();
                      for (int j=0; j<n; j++) {
                          if (j != 0) b.append(", ");
 -                        p = slicePoint.getCoordinate(j);
 +                        p = slicePoint.getOrdinate(j);
                          if (Double.isNaN(p)) b.append("NaN");
                          else b.append(Math.round(p));
                      }
diff --cc 
endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/FeatureFormat.java
index 2f0a746d06,ed04aaab9d..8401b35036
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/FeatureFormat.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/FeatureFormat.java
@@@ -384,10 -395,10 +383,10 @@@ public class FeatureFormat extends Tabu
           * a row has no value, it will be skipped if and only if that row is 
optional (minimum occurrence
           * of zero).
           */
-         final StringBuffer  buffer  = new StringBuffer();
-         final FieldPosition dummyFP = new FieldPosition(-1);
-         final List<String>  remarks = new ArrayList<>();
+         final var buffer  = new StringBuffer();
+         final var dummyFP = new FieldPosition(-1);
+         final var remarks = new ArrayList<String>();
 -        for (final PropertyType propertyType : 
featureType.getProperties(true)) {
 +        for (final AbstractIdentifiedType propertyType : 
featureType.getProperties(true)) {
              Object value = null;
              int cardinality = -1;
              if (feature != null) {
diff --cc 
endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/ImmutableIdentifier.java
index ea3a7d67ca,c5283d5f3a..a7441b1833
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/ImmutableIdentifier.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/ImmutableIdentifier.java
@@@ -236,28 -222,23 +235,23 @@@ public class ImmutableIdentifier extend
       *     <td>{@value org.opengis.metadata.Identifier#CODE_KEY}</td>
       *     <td>{@link String}</td>
       *     <td>{@link #getCode()}</td>
-      *   </tr>
-      *   <tr>
+      *   </tr><tr>
 -     *     <td>{@value org.opengis.metadata.Identifier#CODESPACE_KEY}</td>
 +     *     <td>{@value 
org.opengis.referencing.ReferenceIdentifier#CODESPACE_KEY}</td>
       *     <td>{@link String}</td>
       *     <td>{@link #getCodeSpace()}</td>
-      *   </tr>
-      *   <tr>
+      *   </tr><tr>
 -     *     <td>{@value org.opengis.metadata.Identifier#AUTHORITY_KEY}</td>
 +     *     <td>{@value 
org.opengis.referencing.ReferenceIdentifier#AUTHORITY_KEY}</td>
       *     <td>{@link String} or {@link Citation}</td>
       *     <td>{@link #getAuthority()}</td>
-      *   </tr>
-      *   <tr>
+      *   </tr><tr>
 -     *     <td>{@value org.opengis.metadata.Identifier#VERSION_KEY}</td>
 +     *     <td>{@value 
org.opengis.referencing.ReferenceIdentifier#VERSION_KEY}</td>
       *     <td>{@link String}</td>
       *     <td>{@link #getVersion()}</td>
-      *   </tr>
-      *   <tr>
+      *   </tr><tr>
 -     *     <td>{@value org.opengis.metadata.Identifier#DESCRIPTION_KEY}</td>
 +     *     <td>{@value #DESCRIPTION_KEY}</td>
       *     <td>{@link String} or {@link InternationalString}</td>
       *     <td>{@link #getDescription()}</td>
-      *   </tr>
-      *   <tr>
+      *   </tr><tr>
       *     <td>{@value 
org.apache.sis.referencing.AbstractIdentifiedObject#LOCALE_KEY}</td>
       *     <td>{@link Locale}</td>
       *     <td>(none)</td>
diff --cc 
endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/NamedIdentifier.java
index 9eca9f6206,a0f501aec6..331401a3b5
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/NamedIdentifier.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/NamedIdentifier.java
@@@ -171,28 -168,23 +168,23 @@@ public class NamedIdentifier extends Im
       *     <td>{@value org.opengis.metadata.Identifier#CODE_KEY}</td>
       *     <td>{@link String}</td>
       *     <td>{@link #getCode()}</td>
-      *   </tr>
-      *   <tr>
+      *   </tr><tr>
 -     *     <td>{@value org.opengis.metadata.Identifier#CODESPACE_KEY}</td>
 +     *     <td>"codespace"</td>
       *     <td>{@link String}</td>
       *     <td>{@link #getCodeSpace()}</td>
-      *   </tr>
-      *   <tr>
+      *   </tr><tr>
       *     <td>{@value org.opengis.metadata.Identifier#AUTHORITY_KEY}</td>
       *     <td>{@link String} or {@link Citation}</td>
       *     <td>{@link #getAuthority()}</td>
-      *   </tr>
-      *   <tr>
+      *   </tr><tr>
 -     *     <td>{@value org.opengis.metadata.Identifier#VERSION_KEY}</td>
 +     *     <td>"version"</td>
       *     <td>{@link String}</td>
       *     <td>{@link #getVersion()}</td>
-      *   </tr>
-      *   <tr>
+      *   </tr><tr>
 -     *     <td>{@value org.opengis.metadata.Identifier#DESCRIPTION_KEY}</td>
 +     *     <td>"description"</td>
       *     <td>{@link String} or {@link InternationalString}</td>
       *     <td>{@link #getDescription()}</td>
-      *   </tr>
-      *   <tr>
+      *   </tr><tr>
       *     <td>{@value 
org.apache.sis.referencing.AbstractIdentifiedObject#LOCALE_KEY}</td>
       *     <td>{@link Locale}</td>
       *     <td>(none)</td>
diff --cc 
endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/ConcatenatedGridCoverage.java
index 53c7bcc145,cb557479bd..bab29f55ad
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/ConcatenatedGridCoverage.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/ConcatenatedGridCoverage.java
@@@ -26,16 -28,16 +28,16 @@@ import org.apache.sis.coverage.grid.Gri
  import org.apache.sis.coverage.grid.GridGeometry;
  import org.apache.sis.coverage.grid.GridCoverage;
  import org.apache.sis.coverage.grid.DisjointExtentException;
- import org.apache.sis.storage.GridCoverageResource;
  import org.apache.sis.storage.DataStoreException;
  import org.apache.sis.storage.internal.Resources;
- import org.apache.sis.util.privy.Numerics;
+ import org.apache.sis.storage.base.MemoryGridResource;
  import org.apache.sis.util.collection.Cache;
  import org.apache.sis.util.logging.Logging;
+ import org.apache.sis.util.privy.Numerics;
  import static org.apache.sis.image.privy.ImageUtilities.LOGGER;
  
 -// Specific to the geoapi-3.1 and geoapi-4.0 branches:
 -import org.opengis.coverage.CannotEvaluateException;
 +// Specific to the main branch:
 +import org.apache.sis.coverage.CannotEvaluateException;
  
  
  /**
diff --cc 
endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/LegalSymbols.java
index 93dbbdb81b,4399710240..ccc5360c93
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/LegalSymbols.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/LegalSymbols.java
@@@ -205,19 -213,92 +213,92 @@@ parse:  for (int i = 0; i < length;) 
              if (!isSpaceOrPunctuation(c)) break;
              i -= Character.charCount(c);
          }
-         final var c = new DefaultCitation(notice);
+         DefaultCitation citation = null;
+         if (locale != null) {
+             for (Citation c : constraints.getReferences()) {
+                 if (c instanceof DefaultCitation) {
+                     if (update(c.getTitle(), locale, notice)) {
+                         citation = (DefaultCitation) c;             // Set 
only on success.
+                         break;
+                     }
+                 }
+             }
+         }
+         if (citation == null) {
+             citation = new DefaultCitation(i18n(locale, notice));
+             constraints.getReferences().add(citation);
+         }
          if (year != 0) {
-             final Date date = new Date(LocalDate.of(year, 1, 1).toEpochDay() 
* MILLISECONDS_PER_DAY);
-             c.setDates(Collections.singleton(new DefaultCitationDate(date, 
DateType.valueOf("IN_FORCE"))));
 -            final var date = new DefaultCitationDate(Year.of(year), 
DateType.IN_FORCE);
++            final var date = new DefaultCitationDate(Year.of(year), 
DateType.valueOf("IN_FORCE"));
+             final var dates = citation.getDates();
+             if (!dates.contains(date)) {
+                 dates.add(date);
+             }
          }
+         /*
+          * At this point, the citation has been created and added to the 
contraints.
+          * If a party already exists, try to update the owner's name. This is 
based
+          * on the assumption that `LegalSymbols` is the only code putting 
'i18n' in
+          * the constraints.
+          */
          if (i != 0) {
              buffer.setLength(i);
+             final String owner = buffer.toString();
+             if (locale != null) {
+                 for (final var cited : citation.getCitedResponsibleParties()) 
{
 -                    if (cited.getRole() == Role.OWNER) {
 -                        for (final var party : cited.getParties()) {
++                    if (cited.getRole() == Role.OWNER && cited instanceof 
DefaultResponsibleParty) {
++                        for (final var party : ((DefaultResponsibleParty) 
cited).getParties()) {
+                             final var i18n = party.getName();
+                             if (CharSequences.startsWith(owner, 
i18n.toString(Locale.ENGLISH), true)) {
+                                 /*
+                                  * Use case: name is followed by unwanted 
text because the
+                                  * `VALUES` special cases are provided in 
English only.
+                                  * Example: "John Smith, Tous droits 
réservés."
+                                  */
+                                 return;
+                             }
+                             if (update(i18n, locale, owner)) {
+                                 return;
+                             }
+                         }
+                     }
+                 }
+             }
              // Same limitation as MetadataBuilder.party().
-             final var party = new AbstractParty(buffer, null);
-             final var r = new DefaultResponsibleParty(Role.OWNER);
-             r.setParties(Collections.singleton(party));
-             c.setCitedResponsibleParties(Collections.singleton(r));
+             var party = new AbstractParty(i18n(locale, owner), null);
+             var cited = new DefaultResponsibleParty(Role.OWNER);
+             cited.getParties().add(party);
+             citation.getCitedResponsibleParties().add(cited);
          }
-         constraints.getReferences().add(c);
+     }
+ 
+     /**
+      * If the given international string is an instance of {@link 
DefaultInternationalString},
+      * add the language to it and returns {@code true}. Otherwise, returns 
{@code false} for
+      * notifying the caller that it needs to update the metadata itself.
+      *
+      * @param  i18n    the international string to update if possible.
+      * @param  locale  locale of the text.
+      * @param  text    the localized text.
+      */
+     private static boolean update(final InternationalString i18n, final 
Locale locale, final String text) {
+         if (i18n instanceof DefaultInternationalString) try {
+             ((DefaultInternationalString) i18n).add(locale, text);
+             return true;
+         } catch (IllegalArgumentException e) {
+             Logging.ignorableException(StoreUtilities.LOGGER, 
MetadataBuilder.class, "parseLegalNotice", e);
+         }
+         return (i18n != null) && text.equalsIgnoreCase(i18n.toString());
+     }
+ 
+     /**
+      * Creates a potentially international string for the given text.
+      *
+      * @param  locale  locale of the text, or {@code null} if unspecified.
+      * @param  text    the text to internationalize.
+      * @return the potentially international text.
+      */
+     private static CharSequence i18n(final Locale locale, final String text) {
+         return (locale != null) ? new DefaultInternationalString(locale, 
text) : text;
      }
  }
diff --cc 
endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/esri/WritableStore.java
index 79bf6f5156,66ca6828ea..f47e705546
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/esri/WritableStore.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/esri/WritableStore.java
@@@ -211,6 -211,6 +211,7 @@@ final class WritableStore extends Ascii
               * "NaN" because the default is -9999, and we need to overwrite 
that default if it cannot be used.
               */
              final ChannelDataOutput out = (output != null) ? output : 
h.channel(input().input);
++            @SuppressWarnings("LocalVariableHidesMemberVariable")
              final Number nodataValue = setCoverage(coverage, data, band);
              header.put(NODATA_VALUE, nodataValue);
              writeHeader(header, out);
diff --cc 
endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/image/WritableStore.java
index cf94e852c2,3a5372a8d7..aa97853d4f
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/image/WritableStore.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/image/WritableStore.java
@@@ -33,7 -33,7 +33,6 @@@ import javax.imageio.stream.ImageInputS
  import javax.imageio.stream.ImageOutputStream;
  import org.apache.sis.coverage.grid.GridCoverage;
  import org.apache.sis.coverage.grid.GridGeometry;
--import org.apache.sis.coverage.grid.GridExtent;
  import org.apache.sis.storage.Resource;
  import org.apache.sis.storage.GridCoverageResource;
  import org.apache.sis.storage.WritableAggregate;
@@@ -211,12 -211,8 +210,7 @@@ class WritableStore extends WorldFileSt
           * Make sure that the grid geometry starts at (0,0).
           * Must be done before to compare with existing grid.
           */
--        final GridExtent extent = gg.getExtent();
-         final long[] translation = new long[extent.getDimension()];
-         for (int i=0; i<translation.length; i++) {
-             translation[i] = Math.negateExact(extent.getLow(i));
-         }
-         gg = gg.shiftGrid(translation);
 -        gg = gg.shiftGrid(extent.getLow().getCoordinateValues(), true);
++        gg = gg.shiftGridToZeros();
          /*
           * If the data store already contains a coverage, then the given grid 
geometry
           * must be identical to the existing one, in which case there is 
nothing to do.
diff --cc 
endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/base/MetadataBuilderTest.java
index 6ef1ccf9b5,ec9e903f8a..b353796add
--- 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/base/MetadataBuilderTest.java
+++ 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/base/MetadataBuilderTest.java
@@@ -30,14 -32,13 +32,13 @@@ import static org.junit.jupiter.api.Ass
  import org.apache.sis.test.TestCase;
  import static org.apache.sis.metadata.Assertions.assertTitleEquals;
  import static org.apache.sis.metadata.Assertions.assertPartyNameEquals;
- import static org.apache.sis.test.TestUtilities.date;
  import static org.apache.sis.test.TestUtilities.getSingleton;
  
 -// Specific to the geoapi-3.1 and geoapi-4.0 branches:
 -import org.opengis.metadata.content.FeatureCatalogueDescription;
 -import org.opengis.metadata.content.FeatureTypeInfo;
 -import org.opengis.metadata.constraint.LegalConstraints;
 -import org.opengis.feature.FeatureType;
 +// Specific to the main branch:
- import org.apache.sis.metadata.iso.citation.DefaultCitation;
++import org.apache.sis.metadata.iso.citation.DefaultCitationDate;
 +import org.apache.sis.metadata.iso.constraint.DefaultLegalConstraints;
 +import org.apache.sis.metadata.iso.content.DefaultFeatureCatalogueDescription;
 +import org.apache.sis.metadata.iso.content.DefaultFeatureTypeInfo;
  
  
  /**
@@@ -87,51 -88,50 +88,54 @@@ public final class MetadataBuilderTest 
       */
      private static void verifyCopyrightParsing(final String notice) {
          final var builder = new MetadataBuilder();
-         builder.parseLegalNotice(notice);
+         builder.parseLegalNotice(null, notice);
 -        final Citation ref = copyright(builder);
 +        final var constraints = 
assertInstanceOf(DefaultLegalConstraints.class, getSingleton(getSingleton(
 +                
builder.build().getIdentificationInfo()).getResourceConstraints()));
 +
 +        assertEquals(Restriction.COPYRIGHT, 
getSingleton(constraints.getUseConstraints()));
 +        final Citation ref = getSingleton(constraints.getReferences());
          assertTitleEquals(notice, ref, "reference.title");
          assertPartyNameEquals("John Smith", ref, 
"reference.citedResponsibleParty");
-         assertEquals(date("1992-01-01 00:00:00"), 
getSingleton(ref.getDates()).getDate());
 -        assertEquals(Year.of(1992), 
getSingleton(ref.getDates()).getReferenceDate());
++        assertEquals(Year.of(1992), ((DefaultCitationDate) 
getSingleton(ref.getDates())).getReferenceDate());
      }
  
      /**
-      * Tests {@link MetadataBuilder#addFeatureType(DefaultFeatureType, long)}.
-      *
-      * @todo Combine the 4 tests in a single one for leveraging the same 
{@link DefaultFeatureType} instance?
-      *       It would be consistent with {@link #testParseLegalNotice()}, and 
the error message in those tests
-      *       are already quite clear.
-      */
-     @Test
-     public void negative_feature_count_are_ignored() {
-         verifyFeatureInstanceCount("Feature count should not be written if it 
is negative", null, -1);
-     }
- 
-     /**
-      * Tests {@link MetadataBuilder#addFeatureType(DefaultFeatureType, long)}.
+      * Returns the citation of the legal constraints built by the given 
builder.
+      * This method verifies that the constraint is a copyright.
       */
-     @Test
-     public void no_overflow_on_feature_count() {
-         verifyFeatureInstanceCount("Feature count should be limited to 
maximum 32bit integer value", Integer.MAX_VALUE, 7_000_000_000L);
+     private static Citation copyright(final MetadataBuilder builder) {
+         final var id = getSingleton(builder.build().getIdentificationInfo());
 -        final var constraints = assertInstanceOf(LegalConstraints.class, 
getSingleton(id.getResourceConstraints()));
++        final var constraints = 
assertInstanceOf(DefaultLegalConstraints.class, 
getSingleton(id.getResourceConstraints()));
+         assertEquals(Restriction.COPYRIGHT, 
getSingleton(constraints.getUseConstraints()));
+         return getSingleton(constraints.getReferences());
      }
  
      /**
-      * Tests {@link MetadataBuilder#addFeatureType(DefaultFeatureType, long)}.
+      * Tests {@link MetadataBuilder#parseLegalNotice(String)} with different 
languages.
       */
      @Test
-     public void verify_feature_count_is_written() {
-         verifyFeatureInstanceCount("Feature count should be written as is", 
42, 42);
+     public void testParseLegalNoticeLocalized() {
+         final var builder = new MetadataBuilder();
+         builder.parseLegalNotice(Locale.ENGLISH, "Copyright (C), John Smith, 
1997. All rights reserved.");
+         builder.parseLegalNotice(Locale.FRENCH,  "Copyright (C), John Smith, 
1997. Tous droits réservés.");
+         final Citation ref = copyright(builder);
 -        assertEquals(Year.of(1997), 
getSingleton(ref.getDates()).getReferenceDate());
++        assertEquals(Year.of(1997), ((DefaultCitationDate) 
getSingleton(ref.getDates())).getReferenceDate());
+         assertPartyNameEquals("John Smith", ref, 
"reference.citedResponsibleParty");
+         final var title = ref.getTitle();
+         assertEquals("Copyright (C), John Smith, 1997. All rights reserved.", 
 title.toString(Locale.ENGLISH));
+         assertEquals("Copyright (C), John Smith, 1997. Tous droits 
réservés.", title.toString(Locale.FRENCH));
      }
  
      /**
 -     * Tests {@link MetadataBuilder#addFeatureType(FeatureType, long)}.
 +     * Tests {@link MetadataBuilder#addFeatureType(DefaultFeatureType, long)}.
       */
      @Test
-     public void feature_should_be_ignored_when_count_is_zero() {
-         verifyFeatureInstanceCount("Feature should not be written if count is 
0", null, 0);
+     public void testAddFeatureType() {
+         final var dataType = new 
DefaultFeatureType(Map.of(DefaultFeatureType.NAME_KEY, "Test type"), false, 
null);
+         verifyFeatureInstanceCount(dataType, "Feature count should not be 
written if it is negative", null, -1);
+         verifyFeatureInstanceCount(dataType, "Feature count should be limited 
to maximum 32bit integer value", Integer.MAX_VALUE, 7_000_000_000L);
+         verifyFeatureInstanceCount(dataType, "Feature count should be written 
as is", 42, 42);
+         verifyFeatureInstanceCount(dataType, "Feature should not be written 
if count is 0", null, 0);
      }
  
      /**

Reply via email to