partial work on KeyPathConverter replacement
This commit is contained in:
parent
4b34fe357f
commit
9d5be9caa0
@ -13,6 +13,7 @@ import java.util.regex.Pattern;
|
||||
* If nesting is enabled the delimiter within a section is escaped otherwise the delimiter between the key sections.
|
||||
* @author marhali
|
||||
*/
|
||||
@Deprecated // Replacement moved to utils
|
||||
public class KeyPathConverter {
|
||||
|
||||
private final boolean nestKeys;
|
||||
|
145
src/main/java/de/marhali/easyi18n/util/KeyPathConverter.java
Normal file
145
src/main/java/de/marhali/easyi18n/util/KeyPathConverter.java
Normal file
@ -0,0 +1,145 @@
|
||||
package de.marhali.easyi18n.util;
|
||||
|
||||
import de.marhali.easyi18n.model.translation.KeyPath;
|
||||
import de.marhali.easyi18n.settings.ProjectSettings;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Stateful utility to transform absolute translation keys into their character literal representation and backwards.
|
||||
* @author marhali
|
||||
*/
|
||||
public class KeyPathConverter {
|
||||
|
||||
private final ProjectSettings settings;
|
||||
|
||||
/**
|
||||
* Constructs a new converter instance
|
||||
* @param settings Delimiter configuration
|
||||
*/
|
||||
public KeyPathConverter(ProjectSettings settings) {
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform to character literal representation
|
||||
* @param path Absolute key path
|
||||
* @return Character literal
|
||||
*/
|
||||
public @NotNull String toString(@NotNull KeyPath path) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
for(int i = 0; i < path.size(); i++) {
|
||||
if(i > 0) { // Delimiters
|
||||
if(i == 1 && settings.getFolderStrategy().isNamespaceMode() && settings.getNamespaceDelimiter() != null) {
|
||||
builder.append(quoteDelimiter(settings.getNamespaceDelimiter()));
|
||||
} else {
|
||||
builder.append(quoteDelimiter(settings.getSectionDelimiter()));
|
||||
}
|
||||
}
|
||||
|
||||
// Section content
|
||||
builder.append(quoteSection(path.get(i)));
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits provided character literal into key path sections.
|
||||
* If namespace mode is activated and none was provided, the default namespace will be added.
|
||||
* @return Layered key path sections
|
||||
*/
|
||||
public @NotNull KeyPath fromString(@NotNull String literalPath) {
|
||||
KeyPath path = new KeyPath();
|
||||
|
||||
int i = 0;
|
||||
for(String section : literalPath.split(getSplitRegex())) {
|
||||
|
||||
// Missing namespace
|
||||
if(i == 0 && settings.getFolderStrategy().isNamespaceMode() && hasDefaultNamespace()) {
|
||||
if(section.length() == literalPath.length() || !String.valueOf(literalPath.charAt(section.length())).equals(settings.getNamespaceDelimiter())) {
|
||||
path.add(settings.getDefaultNamespace());
|
||||
}
|
||||
}
|
||||
|
||||
path.add(unquoteSection(section));
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "KeyPathConverter{" +
|
||||
"settings=" + settings +
|
||||
'}';
|
||||
}
|
||||
|
||||
/*
|
||||
* INTERNAL METHODS
|
||||
*/
|
||||
|
||||
private boolean hasDefaultNamespace() {
|
||||
return settings.getDefaultNamespace() != null && !settings.getDefaultNamespace().isEmpty();
|
||||
}
|
||||
|
||||
private String getSplitRegex() {
|
||||
return settings.isNestedKeys()
|
||||
? ("(?<!" + Pattern.quote("\\") + ")" + getSplitCharsRegex())
|
||||
: Pattern.quote("\\") + getSplitCharsRegex();
|
||||
}
|
||||
|
||||
private String getSplitCharsRegex() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
builder.append("(");
|
||||
builder.append(Pattern.quote(settings.getSectionDelimiter()));
|
||||
|
||||
// Add optional namespace delimiter if present
|
||||
if(hasDefaultNamespace()) {
|
||||
builder.append("|");
|
||||
builder.append(Pattern.quote(Objects.requireNonNull(settings.getNamespaceDelimiter())));
|
||||
}
|
||||
|
||||
builder.append(")");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Securely escape found delimiters inside provided section according to the configured policy.
|
||||
*/
|
||||
private String quoteSection(String section) {
|
||||
if(!settings.isNestedKeys()) {
|
||||
return section;
|
||||
}
|
||||
|
||||
if(hasDefaultNamespace()) {
|
||||
section = section.replace(settings.getNamespaceDelimiter(), "\\" + settings.getNamespaceDelimiter());
|
||||
}
|
||||
|
||||
section = section.replace(settings.getSectionDelimiter(), "\\" + settings.getSectionDelimiter());
|
||||
return section;
|
||||
}
|
||||
|
||||
private String unquoteSection(String section) {
|
||||
if(hasDefaultNamespace()) {
|
||||
section = section.replace("\\" + settings.getNamespaceDelimiter(), settings.getNamespaceDelimiter());
|
||||
}
|
||||
|
||||
section = section.replace("\\" + settings.getSectionDelimiter(), settings.getSectionDelimiter());
|
||||
return section;
|
||||
}
|
||||
|
||||
/**
|
||||
* Securely escape provided delimiter according to the configured policy.
|
||||
*/
|
||||
private String quoteDelimiter(String delimiter) {
|
||||
return settings.isNestedKeys() ? delimiter : delimiter.replace(delimiter, "\\" + delimiter);
|
||||
}
|
||||
}
|
@ -1,53 +1,146 @@
|
||||
package de.marhali.easyi18n;
|
||||
|
||||
import de.marhali.easyi18n.model.KeyPath;
|
||||
import de.marhali.easyi18n.model.KeyPathConverter;
|
||||
import de.marhali.easyi18n.io.parser.ParserStrategyType;
|
||||
import de.marhali.easyi18n.model.FolderStrategyType;
|
||||
import de.marhali.easyi18n.model.translation.KeyPath;
|
||||
import de.marhali.easyi18n.settings.ProjectSettings;
|
||||
import de.marhali.easyi18n.util.KeyPathConverter;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
/**
|
||||
* Unit tests for {@link KeyPathConverter}.
|
||||
* @author marhali
|
||||
*/
|
||||
public class KeyPathConverterTest {
|
||||
|
||||
private final KeyPathConverter deepMapper = new KeyPathConverter(true);
|
||||
private final KeyPathConverter flatMapper = new KeyPathConverter(false);
|
||||
|
||||
@Test
|
||||
public void testNestedConcat() {
|
||||
Assert.assertEquals("first\\\\.section.second.third",
|
||||
deepMapper.concat(KeyPath.of("first.section", "second", "third")));
|
||||
public void nonNestedSingle() {
|
||||
KeyPathConverter converter = getConverter(FolderStrategyType.SINGLE, null, ".", null, false);
|
||||
|
||||
Assert.assertEquals("first.second.third",
|
||||
deepMapper.concat(KeyPath.of("first", "second", "third")));
|
||||
Assert.assertEquals("username", converter.toString(new KeyPath("username")));
|
||||
Assert.assertEquals("username\\.nested.section", converter.toString(new KeyPath("username", "nested.section")));
|
||||
Assert.assertEquals("username.normal.nested", converter.toString(new KeyPath("username.normal.nested")));
|
||||
|
||||
Assert.assertEquals(new KeyPath("username"), converter.fromString("username"));
|
||||
Assert.assertEquals(new KeyPath("username", "nested.section"), converter.fromString("username\\.nested.section"));
|
||||
Assert.assertEquals(new KeyPath("username.normal.nested"), converter.fromString("username.normal.nested"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNestedSplit() {
|
||||
Assert.assertEquals(KeyPath.of("first.section", "second", "third"),
|
||||
deepMapper.split("first\\\\.section.second.third"));
|
||||
public void nonNestedNamespace() {
|
||||
KeyPathConverter converter = getConverter(FolderStrategyType.MODULARIZED_NAMESPACE, ":", ".", "common", false);
|
||||
|
||||
Assert.assertEquals(KeyPath.of("first", "second", "third"),
|
||||
deepMapper.split("first.second.third"));
|
||||
Assert.assertEquals("username", converter.toString(new KeyPath("username")));
|
||||
Assert.assertEquals("username.title\\:concat.leaf\\.node", converter.toString(new KeyPath("username.title", "concat.leaf", "node")));
|
||||
|
||||
Assert.assertEquals(new KeyPath("common", "username"), converter.fromString("username"));
|
||||
// TODO: problem here
|
||||
Assert.assertEquals(new KeyPath("username.title", "concat.leaf", "node"), converter.fromString("username.title\\:concat\\.leaf.node"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonNestedConcat() {
|
||||
Assert.assertEquals("flat.map\\\\.deeper",
|
||||
flatMapper.concat(KeyPath.of("flat.map", "deeper")));
|
||||
public void single() {
|
||||
KeyPathConverter converter = getConverter(FolderStrategyType.SINGLE,null, ".", null, true);
|
||||
|
||||
Assert.assertEquals("flat.map.keys",
|
||||
flatMapper.concat(KeyPath.of("flat.map.keys")));
|
||||
Assert.assertEquals("username", converter.toString(new KeyPath("username")));
|
||||
Assert.assertEquals("username.title", converter.toString(new KeyPath("username", "title")));
|
||||
Assert.assertEquals("username.nested\\.section", converter.toString(new KeyPath("username", "nested.section")));
|
||||
Assert.assertEquals("username.deep.nested", converter.toString(new KeyPath("username", "deep", "nested")));
|
||||
|
||||
Assert.assertEquals(new KeyPath("username"), converter.fromString("username"));
|
||||
Assert.assertEquals(new KeyPath("username", "title"), converter.fromString("username.title"));
|
||||
Assert.assertEquals(new KeyPath("username", "nested.section"), converter.fromString("username.nested\\.section"));
|
||||
Assert.assertEquals(new KeyPath("username", "deep", "nested"), converter.fromString("username.deep.nested"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonNestedSplit() {
|
||||
Assert.assertEquals(KeyPath.of("flat.keys.with", "deep.section"),
|
||||
flatMapper.split("flat.keys.with\\\\.deep.section"));
|
||||
public void namespace() {
|
||||
KeyPathConverter converter = getConverter(FolderStrategyType.MODULARIZED_NAMESPACE, ":", ".", "common", true);
|
||||
|
||||
Assert.assertEquals(KeyPath.of("flat.keys.only"),
|
||||
flatMapper.split("flat.keys.only"));
|
||||
Assert.assertEquals("common", converter.toString(new KeyPath("common")));
|
||||
Assert.assertEquals("common:username", converter.toString(new KeyPath("common", "username")));
|
||||
Assert.assertEquals("nested\\:common:username", converter.toString(new KeyPath("nested:common", "username")));
|
||||
Assert.assertEquals("common:username.nested\\.section", converter.toString(new KeyPath("common", "username", "nested.section")));
|
||||
Assert.assertEquals("common:username.deep.nested", converter.toString(new KeyPath("common", "username", "deep", "nested")));
|
||||
|
||||
Assert.assertEquals(new KeyPath("common", "key"), converter.fromString("key"));
|
||||
Assert.assertEquals(new KeyPath("common", "common:username", "title"), converter.fromString("common\\:username.title"));
|
||||
Assert.assertEquals(new KeyPath("user", "title"), converter.fromString("user:title"));
|
||||
Assert.assertEquals(new KeyPath("user:complex", "deep.nested", "value"), converter.fromString("user\\:complex:deep\\.nested.value"));
|
||||
}
|
||||
}
|
||||
|
||||
private KeyPathConverter getConverter(FolderStrategyType strategy, String namespaceDelim,
|
||||
String sectionDelim, String defaultNs, boolean nestKeys) {
|
||||
return new KeyPathConverter(new ProjectSettings() {
|
||||
@Override
|
||||
public @Nullable String getLocalesDirectory() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull FolderStrategyType getFolderStrategy() {
|
||||
return strategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ParserStrategyType getParserStrategy() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getFilePattern() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSorting() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getNamespaceDelimiter() {
|
||||
return namespaceDelim;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getSectionDelimiter() {
|
||||
return sectionDelim;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getContextDelimiter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getPluralDelimiter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getDefaultNamespace() {
|
||||
return defaultNs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getPreviewLocale() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNestedKeys() {
|
||||
return nestKeys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAssistance() {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user