Skip to content

Commit

Permalink
Merge branch 'jdk8'
Browse files Browse the repository at this point in the history
  • Loading branch information
bjorndarri committed Jan 29, 2024
2 parents 5ba2eaf + 500502a commit cc637ef
Show file tree
Hide file tree
Showing 16 changed files with 1,070 additions and 31 deletions.
157 changes: 157 additions & 0 deletions buildSrc/src/main/groovy/I18n.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.Set;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.IntStream;

import static java.util.Collections.unmodifiableList;
import static java.util.stream.Collectors.*;

public final class I18n {

private static final String DEFAULT = "default";

private final Pattern localeProperties = Pattern.compile(".*_[a-z]{2}_[A-Z]{2}.properties");
private final Map<String, Set<Resource>> moduleResources = new LinkedHashMap<>();

public I18n(Map<String, List<String>> modulePropertiesFiles) {
modulePropertiesFiles.forEach((module, resourceFiles) -> {
Set<Resource> resources = resourceFiles.stream()
.map(this::cleanFileString)
.map(file -> toResource(file, resourceFiles))
.collect(toCollection(LinkedHashSet::new));
moduleResources.put(module, resources);
});
}

public String toAsciidoc() {
StringBuilder builder = new StringBuilder();
builder.append("= Internationalization (i18n)\n\n");
builder.append("Overview of the available i18n properties files and their keys and values.\n\n");
moduleResources.forEach((module, resources) -> {
builder.append("== ").append(module).append("\n\n");
resources.forEach(resource -> {
builder.append("=== ").append(resource.owner).append(".java\n\n");
builder.append("[source]\n");
builder.append("----\n");
resource.localeFiles.values().forEach(localeFile -> builder.append(removePrefix(localeFile)).append("\n"));
builder.append("----\n");
builder.append("[cols=\"");
builder.append(IntStream.rangeClosed(0, resource.locales.size())
.mapToObj(i -> "1")
.collect(joining(",")));
builder.append("\"]\n");
builder.append("|===\n");
builder.append("|key");
resource.locales.forEach(locale -> builder.append("|" + locale));
builder.append("\n\n");
Properties defaultProperties = resource.localeProperties.get(I18n.DEFAULT);
List<String> propertyNames = Collections.list(defaultProperties.propertyNames())
.stream()
.map(Objects::toString)
.sorted(Comparator.naturalOrder())
.collect(toList());
for (String propertyName : propertyNames) {
builder.append("|" + propertyName);
resource.locales.forEach(locale -> {
Properties localeProperties = resource.localeProperties.get(locale);
String value = (String) localeProperties.get(propertyName);
builder.append("|").append(value.replaceAll("\\|", "\\\\|"));
});
builder.append("\n");
}
builder.append("|===\n\n");
});
});

return builder.toString().trim();
}

private String cleanFileString(String file) {
file = removePrefix(file);
if (localeProperties.matcher(file).matches()) {
return file.substring(0, file.length() - 17);
}

return file.substring(0, file.length() - 11);
}

private static Resource toResource(String resourceOwner, List<String> propertiesFiles) {
return new Resource(resourceOwner, propertiesFiles.stream()
.filter(file -> isPropertiesFileFor(removePrefix(file), resourceOwner))
.collect(toMap(I18n::parseLocale, Function.identity(), (s, s2) -> s, LinkedHashMap::new)));
}

private static boolean isPropertiesFileFor(String file, String resourceOwner) {
return file.endsWith(resourceOwner + ".properties") || file.matches(Pattern.quote(resourceOwner) + "_[a-z]{2}_[A-Z]{2}.properties");
}

private static String parseLocale(String file) {
int localeUnderscore = file.indexOf("_", file.lastIndexOf("/"));
if (localeUnderscore != -1) {
return file.substring(localeUnderscore + 1, file.lastIndexOf("."));
}

return DEFAULT;
}

private static String removePrefix(String file) {
return file.substring(file.indexOf("src/main/resources/") + 19);
}

private static final class Resource {

private final String owner;
private final List<String> locales;
private final Map<String, String> localeFiles;
private final Map<String, Properties> localeProperties = new LinkedHashMap<>();

private Resource(String owner, Map<String, String> localeFiles) {
this.owner = owner;
this.localeFiles = localeFiles;
this.locales = unmodifiableList(new ArrayList<>(localeFiles.keySet()));
this.locales.forEach(locale -> localeProperties.put(locale, createProperties(locale)));
}

@Override
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (!(object instanceof Resource)) {
return false;
}
Resource resource = (Resource) object;

return Objects.equals(owner, resource.owner);
}

@Override
public int hashCode() {
return Objects.hash(owner);
}

private Properties createProperties(String locale) {
try (InputStream stream = Files.newInputStream(Paths.get(localeFiles.get(locale)))) {
Properties properties = new Properties();
properties.load(stream);

return properties;
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
3 changes: 2 additions & 1 deletion changelog.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Codion Change Log
==================

## 0.17.26-SNAPSHOT
## 0.17.26
### is.codion.common.core
- EventObserver now accepts data listeners for value type superclasses.
### is.codion.common.rmi
Expand All @@ -18,6 +18,7 @@ Codion Change Log
- EntityPanel.setDisposeEditDialogOnEscape() replaced with State based disposeEditDialogOnEscape().
- EntityPanel.INCLUDE_DETAIL_PANEL_CONTROLS removed, replaced by TabbedPanelLayout.INCLUDE_DETAIL_CONTROLS.
- EntityDialogs.EditEntityComponentFactory.componentValue(), now sets the columns for text input panels, preventing multi-screen spanning dialogs in case of very long strings.
- EntityApplicationPanel.createRefreshAllControl() removed.

## 0.17.25
### is.codion.common.db
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ clear_tip=Clear all fields
advanced=Advanced
refresh=Refresh
refresh_mnemonic=R
refresh_tip=Refresh Data
refresh_tip=Refresh data
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ clear_tip=Hreinsa alla reiti
advanced=N\u00E1kv\u00E6m
refresh=Endurhla\u00F0a
refresh_mnemonic=E
refresh_tip=Endurhla\u00F0a G\u00F6gnum
refresh_tip=Endurhla\u00F0a g\u00F6gnum
23 changes: 22 additions & 1 deletion documentation/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ def documentationVersion = project.version.replace("-SNAPSHOT", "")
def documentationDir = "${documentationVersion}"

tasks.register("copyModuleDependencyGraphs") {
group "documentation"
doLast {
frameworkModules.each {
def moduleDir = it.projectDir
Expand All @@ -22,8 +23,28 @@ tasks.register("copyModuleDependencyGraphs") {
}
}

tasks.register("populateI18nPage") {
group "documentation"
doLast {
def file = file("src/docs/asciidoc/technical/i18n.adoc")
def moduleFiles = new LinkedHashMap<>()
frameworkModules.each {
def files = new ArrayList<>()
it.sourceSets.main.resources.matching {
include "**/*.properties"
}.each {
files.add(it.toString())
}
if (!files.empty) {
moduleFiles.put(it.name, files.sort())
}
}
file.text = new I18n(moduleFiles).toAsciidoc()
}
}

asciidoctor {
dependsOn copyModuleDependencyGraphs
dependsOn copyModuleDependencyGraphs, populateI18nPage
// since the sources included in the docs may have changed, there"s definitely
// a more gradle like way to do this, but it escapes me
inputs.dir(new File("../demos/chinook/src"))
Expand Down
Loading

0 comments on commit cc637ef

Please sign in to comment.