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

adamsaghy pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git


The following commit(s) were added to refs/heads/develop by this push:
     new 52be53778d FINERACT-2326: Locale Validator shall accept all valid 
language codes
52be53778d is described below

commit 52be53778db4a3b65acd1f76dce52fb28987aa72
Author: Adam Saghy <[email protected]>
AuthorDate: Mon Jul 28 17:24:14 2025 +0200

    FINERACT-2326: Locale Validator shall accept all valid language codes
---
 .../validation/BusinessDateValidationTest.java     |  2 +-
 .../validation/constraints/LocaleValidator.java    | 18 ++++++++++-
 .../constraints/LocaleValidationTest.java          | 35 +++++++++++++---------
 3 files changed, 39 insertions(+), 16 deletions(-)

diff --git 
a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/businessdate/validation/BusinessDateValidationTest.java
 
b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/businessdate/validation/BusinessDateValidationTest.java
index c165f41009..761911c03a 100644
--- 
a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/businessdate/validation/BusinessDateValidationTest.java
+++ 
b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/businessdate/validation/BusinessDateValidationTest.java
@@ -55,7 +55,7 @@ class BusinessDateValidationTest {
     @Test
     void invalidLocale() {
         var request = 
BusinessDateUpdateRequest.builder().dateFormat("dd-MM-yyyy").type(BusinessDateType.BUSINESS_DATE).date("12-05-2025")
-                .locale("EN").build();
+                .locale("INVALID").build();
 
         var errors = validator.validateObject(request);
 
diff --git 
a/fineract-validation/src/main/java/org/apache/fineract/validation/constraints/LocaleValidator.java
 
b/fineract-validation/src/main/java/org/apache/fineract/validation/constraints/LocaleValidator.java
index fb410aec4c..664559524a 100644
--- 
a/fineract-validation/src/main/java/org/apache/fineract/validation/constraints/LocaleValidator.java
+++ 
b/fineract-validation/src/main/java/org/apache/fineract/validation/constraints/LocaleValidator.java
@@ -27,6 +27,22 @@ class LocaleValidator implements ConstraintValidator<Locale, 
String> {
 
     @Override
     public boolean isValid(String value, ConstraintValidatorContext context) {
-        return StringUtils.isNotBlank(value) && 
Arrays.asList(java.util.Locale.getISOLanguages()).contains(value);
+        if (StringUtils.isBlank(value)) {
+            return false; // empty string is invalid
+        }
+
+        // Normalize input to use BCP 47 format (e.g., "en-US")
+        String languageTag = value.replace('_', '-');
+
+        java.util.Locale inputLocale = 
java.util.Locale.forLanguageTag(languageTag);
+
+        // If language is empty, it's not a valid locale
+        if (inputLocale.getLanguage().isEmpty()) {
+            return false;
+        }
+
+        // Check if it matches any available locale
+        return Arrays.stream(java.util.Locale.getAvailableLocales())
+                .anyMatch(available -> 
available.toLanguageTag().equalsIgnoreCase(inputLocale.toLanguageTag()));
     }
 }
diff --git 
a/fineract-validation/src/test/java/org/apache/fineract/validation/constraints/LocaleValidationTest.java
 
b/fineract-validation/src/test/java/org/apache/fineract/validation/constraints/LocaleValidationTest.java
index 0de66519f9..192f599450 100644
--- 
a/fineract-validation/src/test/java/org/apache/fineract/validation/constraints/LocaleValidationTest.java
+++ 
b/fineract-validation/src/test/java/org/apache/fineract/validation/constraints/LocaleValidationTest.java
@@ -27,6 +27,8 @@ import lombok.NoArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.fineract.validation.config.ValidationConfig;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.context.ContextConfiguration;
@@ -51,24 +53,29 @@ class LocaleValidationTest {
         assertThat(errors.getFieldErrors()).anyMatch(e -> 
e.getField().equals("locale"));
     }
 
-    @Test
-    void invalidFormat() {
-        var request = LocaleModel.builder().locale("EN").build();
-
+    @ParameterizedTest
+    @ValueSource(strings = { "invalid-locale", // invalid format
+            "xx-YY", // non-existent locale
+            "random text", // random text
+            "123", // numbers
+            "en-US-extra" // extra segment
+    })
+    void invalidFormats(String locale) {
+        var request = LocaleModel.builder().locale(locale).build();
         var errors = validator.validateObject(request);
-
-        assertThat(errors.getFieldErrorCount()).isEqualTo(1);
-
-        assertThat(errors.getFieldErrors()).anyMatch(e -> 
e.getField().equals("locale"));
+        assertThat(errors.getFieldErrorCount()).as("Expected locale '%s' to be 
invalid but it was valid", locale).isGreaterThan(0);
     }
 
-    @Test
-    void valid() {
-        var request = LocaleModel.builder().locale("en").build();
-
+    @ParameterizedTest
+    @ValueSource(strings = { "en", // language only
+            "EN", // uppercase language only
+            "en-US", // language with country (hyphen)
+            "en_US", // language with country (underscore)
+    })
+    void validLocales(String locale) {
+        var request = LocaleModel.builder().locale(locale).build();
         var errors = validator.validateObject(request);
-
-        assertThat(errors.getFieldErrorCount()).isEqualTo(0);
+        assertThat(errors.getFieldErrorCount()).as("Expected locale '%s' to be 
valid but it was invalid", locale).isZero();
     }
 
     @Builder

Reply via email to