Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

Commit

Permalink
v1.0.2 Refactor CLDR methods, Dockerfile, add unit tests for Cldr Pro…
Browse files Browse the repository at this point in the history
…cessors and improve user suggestions

* Add Unit tests for CldrProcessors

* Update Docker config, method access scopes and refactor

* Improve standard patterns sugguestions messages

* Update versioning

* Update README
  • Loading branch information
kirilraykov authored Nov 21, 2022
1 parent 385fdae commit 0606c0f
Show file tree
Hide file tree
Showing 19 changed files with 183 additions and 56 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/maven-publish.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Maven Package and Deploy
name: Package and Deploy Jars + Docker image

on:
push:
Expand Down Expand Up @@ -62,7 +62,7 @@ jobs:
- uses: actions/download-artifact@v2
with:
name: jar-artifact
path: target/
path: rest-api-service/target/
- name: Docker build
run: |
docker build . -t vmware/date-time-pattern-rest-api-service
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Define base docker image
FROM openjdk:17
LABEL maintainer="[email protected]"
COPY ./target/*.jar date-time-pattern-detection-service.jar
COPY ./rest-api-service/target/*.jar date-time-pattern-detection-service.jar
ENTRYPOINT ["java","-jar","date-time-pattern-detection-service.jar"]
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ validate the localized date/time components. It provides suggestions based on th
## Build and Run as local REST-API service using Docker

1. Pull Docker image from GitHub Container Registry: `docker pull ghcr.io/vmware-labs/date-and-time-pattern-detection:main`
If you get authentication error, you may need to login to chcr.io/vware-labs using Github username and access token.
2. Run on specified port. Example: `docker run -p 8083:8083 ghcr.io/vmware-labs/date-and-time-pattern-detection:main`
3. Open browser at http://localhost:8083/i18n/swagger-ui/index.html#/ (Port may be different, depending on above step).
4. Access the REST-API documentation and test-out the endpoints.
Expand Down Expand Up @@ -55,7 +56,7 @@ You can directly use the library part of the project by injecting the dependency
<dependency>
<groupId>com.vmware.g11n</groupId>
<artifactId>date-time-pattern-detection-library</artifactId>
<version>0.0.6</version>
<version>1.0.2</version>
</dependency>
```
2. Specify GitHub Package Registry as Maven Repository in your local settings.xml:
Expand Down
4 changes: 2 additions & 2 deletions library/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<parent>
<groupId>com.vmware.g11n</groupId>
<artifactId>date-time-pattern-detection-parent</artifactId>
<version>1.0.1</version>
<version>1.0.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand All @@ -22,7 +22,7 @@

<artifactId>date-time-pattern-detection-library</artifactId>
<name>date-time-pattern-detection-library</name>
<version>1.0.1</version>
<version>1.0.2</version>
<packaging>jar</packaging>

<dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

public class Builders {

public static ValidationResult buildValidationResultResponse(String input, String language, boolean isLocalizedContent, ValidatedPattern detectedPattern) {
public static ValidationResult buildValidationResult(String input, String language, boolean isLocalizedContent, ValidatedPattern detectedPattern) {
return ValidationResult.builder()
.input(input)
.language(language)
Expand All @@ -20,10 +20,10 @@ public static ValidationResult buildValidationResultResponse(String input, Strin
.build();
}

public static ConversionResult buildConversionResponse(ValidationResult sourceValidation,
ValidationResult targetValidation,
Map<ErrorsType, String> errors,
Map<SuggestionsType, String> suggestions) {
public static ConversionResult buildConversionResult(ValidationResult sourceValidation,
ValidationResult targetValidation,
Map<ErrorsType, String> errors,
Map<SuggestionsType, String> suggestions) {
return ConversionResult.builder()
.isSourceContentLocalized(sourceValidation.isLocalizedContent)
.isTargetContentLocalized(targetValidation.isLocalizedContent)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import static com.vmware.g11n.pattern.detection.library.data.DateFieldSymbols.*;
import static com.vmware.g11n.pattern.detection.library.data.PatternDetectionConstants.*;
import static com.vmware.g11n.pattern.detection.library.patterns.PatternBuilders.*;
import static com.vmware.g11n.pattern.detection.library.utils.Matchers.*;

public class CldrMappers {
Expand Down Expand Up @@ -71,13 +72,13 @@ public static Map<String, String> mapAllDateFieldsData(DateFields fields) {
* Skipping check for 24h standalone hours as the pattern is part of the standard CLDR formats.
*/
public static String getPatternFromDateField(String dateField, String input) {
if (dateField.equals(YEAR_FIELD_KEY) && !PatternBuilders.buildYearPattern(input).isEmpty()) {
if (dateField.equals(YEAR_FIELD_KEY) && !buildYearPattern(input).isEmpty()) {
return YEAR_1_DIGIT;
}
if (dateField.equals(MONTH_FIELD_KEY) && !PatternBuilders.buildMonthPattern(input).isEmpty()) {
if (dateField.equals(MONTH_FIELD_KEY) && !buildMonthPattern(input).isEmpty()) {
return MONTH_1_DIGIT;
}
if (dateField.equals(DAY_FIELD_KEY) && !PatternBuilders.buildDayOfMonthPattern(input).isEmpty()) {
if (dateField.equals(DAY_FIELD_KEY) && !buildDayOfMonthPattern(input).isEmpty()) {
return DAY_OF_MONTH_1_DIGIT;
}
if (dateField.equals(HOUR_FIELD_KEY) && detectHoursShortStandaloneFormat(input)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ public final class PatternDetectionConstants {

// Suggestions
public static String INCORRECT_CASING_SUGGESTION = "Incorrect casing. Please follow recommended CLDR casing for localized content for the provided locale.";
public static String NON_STANDARD_DATE_SUGGESTION = "Provided date does not match the standard CLDR date patterns.";
public static String NON_STANDARD_TIME_SUGGESTION = "Provided time does not match the standard CLDR time patterns.";
public static String NON_STANDARD_DATE_TIME_SUGGESTION = "Provided dateTime does not match the standard CLDR dateTime patterns: ";
public static String NON_STANDARD_DATE_SUGGESTION = "Provided Date does not match the standard CLDR date patterns: ";
public static String NON_STANDARD_TIME_SUGGESTION = "Provided Time does not match the standard CLDR time patterns: ";
public static String NON_STANDARD_DATE_TIME_SUGGESTION = "Provided Date-Time does not match the standard CLDR dateTime patterns: ";
public static String RELATIVE_TIME_DETECTED_SUGGESTION = "The input is containing relative time components. If left as part of the pattern, they can introduce issues when input is formatted to another language. Relative components detected: ";
public static String ASIAN_TO_NON_ASIAN_INPUTS_CONVERSION_SUGGESTION = "It is not recommended to convert asian and non-asian localized inputs which do not follow CLDR Standard formats. Some components may not be parsable using the same patterns.";
public static String NON_CONVERTABLE_COMPONENTS_SUGGESTION = "Non-convertable (hardcoded) components detected in source input. The following elements are not localized to the target locale: ";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public ValidatedPattern generatePatternFromComponents(LinkedList<String> userInp

// If component cannot be detected manually, try to detect it using Standard cldr data
if (patternForElement.isBlank()) {
patternForElement = detectPatternFromCldrFormats(cldrData, trimmedInput, locale).pattern + " ";
patternForElement = getValidatedPatternFromCldrFormats(cldrData, trimmedInput, locale).pattern + " ";
}

// Check component against ISO standard data
Expand Down Expand Up @@ -93,7 +93,7 @@ private String processComponentAndGetPattern(CldrData cldrData, String component
}

// Check if the current element is valid time format
String detectedTimeFromCldr = detectCldrTimePattern(cldrData, component, locale);
String detectedTimeFromCldr = detectAnyCldrTimePattern(cldrData, component, locale);
if (!detectedTimeFromCldr.isBlank()) {
return detectedTimeFromCldr;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public static boolean isValidPattern(String pattern, String value, Locale locale

public static ValidatedPattern verifyAndBuildPattern(String pattern, String input, Locale locale, CldrData cldrData) {
if (isValidPattern(pattern, input, locale, DATE_TIME)) {
ValidatorService.suggestions.put(NON_STANDARD_DATE_TIME, NON_STANDARD_DATE_TIME_SUGGESTION + cldrData.gregorianCalendar.getStandardDateTimeMap().values());
ValidatorService.suggestions.put(NON_STANDARD_DATE_TIME, NON_STANDARD_DATE_TIME_SUGGESTION + cldrData.gregorianCalendar.getStandardDateTimeMapToString());
return ValidatedPattern.builder().pattern(pattern).patternInfoMessage(VALID_NON_STANDARD_DATE_TIME_MESSAGE).localizedType(DATE_TIME).isValidDate(true).build();
} else if (isValidPattern(pattern, input, locale, DATE)) {
ValidatorService.suggestions.put(NON_STANDARD_DATE, NON_STANDARD_DATE_SUGGESTION + cldrData.gregorianCalendar.dateFormats.toString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ private ConversionResult buildConversionResponse(ValidationResult sourceValidati
Map<ErrorsType, String> errors = new HashMap<>(targetValidation.errors);
Map<SuggestionsType, String> suggestions = generateSuggestions(sourceValidation, sourceLocale, targetLocale);

return Builders.buildConversionResponse(sourceValidation, targetValidation, errors, suggestions);
return Builders.buildConversionResult(sourceValidation, targetValidation, errors, suggestions);

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@

import java.util.*;

import static com.vmware.g11n.pattern.detection.library.data.Builders.buildValidationResultResponse;
import static com.vmware.g11n.pattern.detection.library.utils.CldrProcessors.detectPatternFromCldrFormats;
import static com.vmware.g11n.pattern.detection.library.data.Builders.buildValidationResult;
import static com.vmware.g11n.pattern.detection.library.utils.CldrProcessors.getValidatedPatternFromCldrFormats;
import static com.vmware.g11n.pattern.detection.library.utils.IsoProcessors.detectPatternFromPredefinedIsoFormats;
import static com.vmware.g11n.pattern.detection.library.utils.ResourceLoaders.loadCldrData;
import static com.vmware.g11n.pattern.detection.library.utils.UserInputProcessors.*;
Expand Down Expand Up @@ -40,16 +40,16 @@ public ValidationResult validateInput(String input, String locale) {
CldrData cldrData = loadCldrData(providedLocale);

// Try to match the input as a whole to a CLDR pattern
ValidatedPattern detectedPattern = detectPatternFromCldrFormats(cldrData, input, providedLocale);
ValidatedPattern detectedPattern = getValidatedPatternFromCldrFormats(cldrData, input, providedLocale);
if (!detectedPattern.pattern.isEmpty()) {
return buildValidationResultResponse(input, providedLocale.getDisplayName(), true, detectedPattern)
return buildValidationResult(input, providedLocale.getDisplayName(), true, detectedPattern)
.toBuilder().suggestions(generateSuggestions()).errors(getErrors()).build();
}

// Try to match the input as a whole to ISO locale-independent patterns
detectedPattern = detectPatternFromPredefinedIsoFormats(input);
if (!detectedPattern.pattern.isEmpty()) {
return buildValidationResultResponse(input, providedLocale.getDisplayName(), true, detectedPattern)
return buildValidationResult(input, providedLocale.getDisplayName(), true, detectedPattern)
.toBuilder().suggestions(generateSuggestions()).errors(getErrors()).build();
}

Expand All @@ -58,7 +58,7 @@ public ValidationResult validateInput(String input, String locale) {

// Generate pattern by traversing each component and mapping it to a skeleton pattern
ValidatedPattern generatedPattern = patternBuilders.generatePatternFromComponents(listOfDateElements, providedLocale, cldrData);
return buildValidationResultResponse(input, providedLocale.getDisplayName(), generatedPattern != null, generatedPattern)
return buildValidationResult(input, providedLocale.getDisplayName(), generatedPattern != null, generatedPattern)
.toBuilder().suggestions(generateSuggestions()).errors(getErrors()).build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,41 +27,41 @@
public class CldrProcessors {

// Try to match the input from any CLDR full pattern
public static ValidatedPattern detectPatternFromCldrFormats(CldrData cldrData, String input, Locale locale) {
ValidatedPattern validatedPattern = detectStandardDateCldrFormat(cldrData, input, locale);
public static ValidatedPattern getValidatedPatternFromCldrFormats(CldrData cldrData, String input, Locale locale) {
ValidatedPattern validatedPattern = detectStandardDateCldrPattern(cldrData, input, locale);
if (nonNull(validatedPattern)) {
return validatedPattern;
}

validatedPattern = detectStandardTimeCldrFormat(cldrData, input, locale);
validatedPattern = detectStandardTimeCldrPattern(cldrData, input, locale);
if (nonNull(validatedPattern)) {
return validatedPattern;
}

validatedPattern = detectStandardDateTimeCldrFormats(cldrData, input, locale);
validatedPattern = detectStandardDateTimeCldrPattern(cldrData, input, locale);
if (nonNull(validatedPattern)) {
return validatedPattern;
}

validatedPattern = detectNonStandardDateCldrFormat(cldrData, input, locale);
validatedPattern = detectNonStandardDateCldrPattern(cldrData, input, locale);
if (nonNull(validatedPattern)) {
return validatedPattern;
}

validatedPattern = detectNonStandardTimeCldrFormat(cldrData, input, locale);
validatedPattern = detectNonStandardTimeCldrPattern(cldrData, input, locale);
if (nonNull(validatedPattern)) {
return validatedPattern;
}

validatedPattern = detectAnyTemporalCldrFormat(cldrData, input, locale);
validatedPattern = detectAnyTemporalCldrPattern(cldrData, input, locale);
if (nonNull(validatedPattern)) {
return validatedPattern;
}

return ValidatedPattern.builder().pattern(EMPTY).build();
}

private static ValidatedPattern detectStandardDateCldrFormat(CldrData cldrData, String input, Locale locale) {
private static ValidatedPattern detectStandardDateCldrPattern(CldrData cldrData, String input, Locale locale) {
Map<String, String> standardDateFormats = new LinkedHashMap<>(cldrData.gregorianCalendar.dateFormats.getAllDateFormatsAsMap());

for (Map.Entry<String, String> entry : standardDateFormats.entrySet()) {
Expand All @@ -73,7 +73,7 @@ private static ValidatedPattern detectStandardDateCldrFormat(CldrData cldrData,
return null;
}

private static ValidatedPattern detectNonStandardDateCldrFormat(CldrData cldrData, String input, Locale locale) {
private static ValidatedPattern detectNonStandardDateCldrPattern(CldrData cldrData, String input, Locale locale) {
Map<String, String> availableFormats = new LinkedHashMap<>(cldrData.gregorianCalendar.dateTimeFormats.availableFormats);
for (Map.Entry<String, String> entry : availableFormats.entrySet()) {
if (PatternValidators.isValidPattern(entry.getValue(), input, locale, LocalizedType.DATE)) {
Expand All @@ -86,7 +86,7 @@ private static ValidatedPattern detectNonStandardDateCldrFormat(CldrData cldrDat
return null;
}

public static ValidatedPattern detectAnyTemporalCldrFormat(CldrData cldrData, String input, Locale locale) {
private static ValidatedPattern detectAnyTemporalCldrPattern(CldrData cldrData, String input, Locale locale) {
for (Map.Entry<String, String> entry : cldrData.gregorianCalendar.dateTimeFormats.availableFormats.entrySet()) {
if (PatternValidators.isValidPattern(entry.getValue(), input, locale, LocalizedType.TEMPORAL)) {
return ValidatedPattern.builder().pattern(entry.getValue()).localizedType(LocalizedType.TEMPORAL).cldrDataKeyName(entry.getKey())
Expand All @@ -96,7 +96,7 @@ public static ValidatedPattern detectAnyTemporalCldrFormat(CldrData cldrData, St
return null;
}

private static ValidatedPattern detectStandardDateTimeCldrFormats(CldrData cldrData, String input, Locale locale) {
private static ValidatedPattern detectStandardDateTimeCldrPattern(CldrData cldrData, String input, Locale locale) {
Map<String, String> standardDateTimeFormats = new LinkedHashMap<>(cldrData.gregorianCalendar.getStandardDateTimeMap());

for (Map.Entry<String, String> entry : standardDateTimeFormats.entrySet()) {
Expand All @@ -108,7 +108,7 @@ private static ValidatedPattern detectStandardDateTimeCldrFormats(CldrData cldrD
return null;
}

public static ValidatedPattern detectStandardTimeCldrFormat(CldrData cldrData, String input, Locale locale) {
private static ValidatedPattern detectStandardTimeCldrPattern(CldrData cldrData, String input, Locale locale) {
Map<String, String> standardTimeFormats = new LinkedHashMap<>(cldrData.gregorianCalendar.timeFormats.getAllTimeFormatsAsMap());

for (Map.Entry<String, String> entry : standardTimeFormats.entrySet()) {
Expand All @@ -120,7 +120,7 @@ public static ValidatedPattern detectStandardTimeCldrFormat(CldrData cldrData, S
return null;
}

public static ValidatedPattern detectNonStandardTimeCldrFormat(CldrData cldrData, String input, Locale locale) {
private static ValidatedPattern detectNonStandardTimeCldrPattern(CldrData cldrData, String input, Locale locale) {
Map<String, String> availableFormats = new LinkedHashMap<>(cldrData.gregorianCalendar.dateTimeFormats.availableFormats);
for (Map.Entry<String, String> entry : availableFormats.entrySet()) {
if (PatternValidators.isValidPattern(entry.getValue(), input, locale, LocalizedType.TIME)) {
Expand All @@ -134,9 +134,9 @@ public static ValidatedPattern detectNonStandardTimeCldrFormat(CldrData cldrData
}

//TODO: Revisit
public static String detectCldrTimePattern(CldrData cldrData, String el, Locale locale) {
ValidatedPattern patternForDetectedStandardTime = detectStandardTimeCldrFormat(cldrData, el, locale);
ValidatedPattern patternForDetectedNonStandardTime = detectStandardTimeCldrFormat(cldrData, el, locale);
public static String detectAnyCldrTimePattern(CldrData cldrData, String el, Locale locale) {
ValidatedPattern patternForDetectedStandardTime = detectStandardTimeCldrPattern(cldrData, el, locale);
ValidatedPattern patternForDetectedNonStandardTime = detectStandardTimeCldrPattern(cldrData, el, locale);

String detectedStandardTime = nonNull(patternForDetectedStandardTime) ? patternForDetectedStandardTime.pattern : EMPTY;
String detectedNonStandardTime = nonNull(patternForDetectedNonStandardTime) ? patternForDetectedNonStandardTime.pattern : EMPTY;
Expand Down Expand Up @@ -224,7 +224,7 @@ public static String detectExtendedHmsPattern(String input) {
public static String detectTimezonesWithSpacings(String input, CldrData cldrData) {
List<String> timeZonesWithSpacing = new ArrayList<>();

List<String> examplarCities = cldrData.timezoneNames.getZones().values().stream()
List<String> exemplarCities = cldrData.timezoneNames.getZones().values().stream()
.flatMap(zone -> zone.values().stream())
.map(SubZone::getExemplarCity).toList();

Expand All @@ -238,7 +238,7 @@ public static String detectTimezonesWithSpacings(String input, CldrData cldrData
.flatMap(metaZone -> Stream.of(metaZone.getLongMetaZone().getDaylight(), metaZone.getLongMetaZone().getStandard()))
.toList();

timeZonesWithSpacing.addAll(examplarCities);
timeZonesWithSpacing.addAll(exemplarCities);
timeZonesWithSpacing.addAll(longGenericNonLocations);
timeZonesWithSpacing.addAll(longSpecificNonLocations);

Expand Down
Loading

0 comments on commit 0606c0f

Please sign in to comment.