diff --git a/CHANGELOG.md b/CHANGELOG.md index a861de7..7cf58c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,12 +5,14 @@ ## [Unreleased] ### BREAKING CHANGES - Translation file pattern matcher needs to be updated to \*.* or equivalent wildcard rule +- I18n key nesting will now escape every delimiter within a section layer (can be inverted via option) ### Added - Full keyboard shortcut support inside tool-window - Support for dots within key nodes in YAML files ### Changed +- Key completion inside editor suggests all keys without any logic - Translation file pattern uses wildcard matcher instead of regex - Improve exception handling on IO operations - Update Qodana to latest version diff --git a/src/main/java/de/marhali/easyi18n/DataBus.java b/src/main/java/de/marhali/easyi18n/DataBus.java index 101a8fd..5bd517b 100644 --- a/src/main/java/de/marhali/easyi18n/DataBus.java +++ b/src/main/java/de/marhali/easyi18n/DataBus.java @@ -1,5 +1,6 @@ package de.marhali.easyi18n; +import de.marhali.easyi18n.model.KeyPath; import de.marhali.easyi18n.model.bus.BusListener; import de.marhali.easyi18n.model.TranslationData; @@ -42,7 +43,7 @@ public class DataBus { } @Override - public void onFocusKey(@Nullable String key) { + public void onFocusKey(@Nullable KeyPath key) { listener.forEach(li -> li.onFocusKey(key)); } diff --git a/src/main/java/de/marhali/easyi18n/DataStore.java b/src/main/java/de/marhali/easyi18n/DataStore.java index e41ecdc..a255b47 100644 --- a/src/main/java/de/marhali/easyi18n/DataStore.java +++ b/src/main/java/de/marhali/easyi18n/DataStore.java @@ -42,7 +42,7 @@ public class DataStore { protected DataStore(@NotNull Project project) { this.project = project; - this.data = new TranslationData(true, true); // Initialize with hard-coded configuration + this.data = new TranslationData(true); // Initialize with hard-coded configuration this.changeListener = new FileChangeListener(project); VirtualFileManager.getInstance().addAsyncFileListener( @@ -63,7 +63,7 @@ public class DataStore { String localesPath = state.getLocalesPath(); if(localesPath == null || localesPath.isEmpty()) { // Populate empty instance - this.data = new TranslationData(state.isSortKeys(), state.isNestedKeys()); + this.data = new TranslationData(state.isSortKeys()); return; } @@ -73,7 +73,7 @@ public class DataStore { strategy.read(this.project, localesPath, state, (data) -> { this.data = data == null - ? new TranslationData(state.isSortKeys(), state.isNestedKeys()) + ? new TranslationData(state.isSortKeys()) : data; successResult.accept(data != null); diff --git a/src/main/java/de/marhali/easyi18n/action/AddAction.java b/src/main/java/de/marhali/easyi18n/action/AddAction.java index f2c2455..b356b9a 100644 --- a/src/main/java/de/marhali/easyi18n/action/AddAction.java +++ b/src/main/java/de/marhali/easyi18n/action/AddAction.java @@ -3,15 +3,20 @@ package de.marhali.easyi18n.action; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.project.Project; +import com.intellij.ui.content.Content; +import de.marhali.easyi18n.model.KeyPath; +import de.marhali.easyi18n.model.KeyPathConverter; import de.marhali.easyi18n.service.WindowManager; import de.marhali.easyi18n.dialog.AddDialog; -import de.marhali.easyi18n.util.PathUtil; import de.marhali.easyi18n.util.TreeUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.tree.TreePath; +import java.util.Objects; import java.util.ResourceBundle; /** @@ -27,32 +32,33 @@ public class AddAction extends AnAction { @Override public void actionPerformed(@NotNull AnActionEvent e) { - new AddDialog(e.getProject(), detectPreKey()).showAndHandle(); + new AddDialog(Objects.requireNonNull(e.getProject()), detectPreKey(e.getProject())).showAndHandle(); } - private String detectPreKey() { - WindowManager manager = WindowManager.getInstance(); + private @Nullable KeyPath detectPreKey(@NotNull Project project) { + KeyPathConverter converter = new KeyPathConverter(project); + WindowManager window = WindowManager.getInstance(); + Content manager = window.getToolWindow().getContentManager().getSelectedContent(); if(manager == null) { return null; } - if(manager.getToolWindow().getContentManager().getSelectedContent() - .getDisplayName().equals(ResourceBundle.getBundle("messages").getString("view.tree.title"))) { + if(manager.getDisplayName().equals( + ResourceBundle.getBundle("messages").getString("view.tree.title"))) { // Tree View - TreePath path = manager.getTreeView().getTree().getSelectionPath(); + TreePath path = window.getTreeView().getTree().getSelectionPath(); if(path != null) { - return TreeUtil.getFullPath(path) + PathUtil.DELIMITER; + return TreeUtil.getFullPath(path); } } else { // Table View - - int row = manager.getTableView().getTable().getSelectedRow(); + int row = window.getTableView().getTable().getSelectedRow(); if(row >= 0) { - String fullPath = String.valueOf(manager.getTableView().getTable().getValueAt(row, 0)); - return fullPath + "."; + String path = String.valueOf(window.getTableView().getTable().getValueAt(row, 0)); + return converter.split(path); } } diff --git a/src/main/java/de/marhali/easyi18n/dialog/AddDialog.java b/src/main/java/de/marhali/easyi18n/dialog/AddDialog.java index 7702fba..dd886b0 100644 --- a/src/main/java/de/marhali/easyi18n/dialog/AddDialog.java +++ b/src/main/java/de/marhali/easyi18n/dialog/AddDialog.java @@ -8,9 +8,10 @@ import com.intellij.ui.components.JBScrollPane; import com.intellij.ui.components.JBTextField; import de.marhali.easyi18n.InstanceManager; -import de.marhali.easyi18n.model.KeyedTranslation; -import de.marhali.easyi18n.model.Translation; -import de.marhali.easyi18n.model.TranslationCreate; +import de.marhali.easyi18n.model.*; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.border.EtchedBorder; @@ -25,19 +26,23 @@ import java.util.ResourceBundle; */ public class AddDialog { - private final Project project; - private String preKey; + private final @NotNull Project project; + private final @NotNull KeyPathConverter converter; + + private @NotNull KeyPath preKey; private JBTextField keyTextField; private Map valueTextFields; - public AddDialog(Project project, String preKey) { + public AddDialog(@NotNull Project project, @Nullable KeyPath preKey) { this(project); - this.preKey = preKey; + this.preKey = preKey == null ? new KeyPath() : preKey; } - public AddDialog(Project project) { + public AddDialog(@NotNull Project project) { this.project = project; + this.converter = new KeyPathConverter(project); + this.preKey = new KeyPath(); } public void showAndHandle() { @@ -57,7 +62,8 @@ public class AddDialog { } }); - TranslationCreate creation = new TranslationCreate(new KeyedTranslation(keyTextField.getText(), translation)); + KeyedTranslation keyedTranslation = new KeyedTranslation(converter.split(keyTextField.getText()), translation); + TranslationCreate creation = new TranslationCreate(keyedTranslation); InstanceManager.get(project).processUpdate(creation); } @@ -67,13 +73,17 @@ public class AddDialog { JPanel keyPanel = new JPanel(new GridLayout(0, 1, 2, 2)); JBLabel keyLabel = new JBLabel(ResourceBundle.getBundle("messages").getString("translation.key")); - keyTextField = new JBTextField(this.preKey); + keyTextField = new JBTextField(this.converter.concat(this.preKey)); keyLabel.setLabelFor(keyTextField); keyPanel.add(keyLabel); keyPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0)); keyPanel.add(keyTextField); rootPanel.add(keyPanel); + if(!this.preKey.isEmpty()) { // Add delimiter if pre key is defined + keyTextField.setText(keyTextField.getText() + KeyPath.DELIMITER); + } + JPanel valuePanel = new JPanel(new GridLayout(0, 1, 2, 2)); valueTextFields = new HashMap<>(); diff --git a/src/main/java/de/marhali/easyi18n/dialog/EditDialog.java b/src/main/java/de/marhali/easyi18n/dialog/EditDialog.java index 7e788bf..cc47e27 100644 --- a/src/main/java/de/marhali/easyi18n/dialog/EditDialog.java +++ b/src/main/java/de/marhali/easyi18n/dialog/EditDialog.java @@ -6,12 +6,10 @@ import com.intellij.openapi.ui.DialogWrapper; import com.intellij.ui.components.JBLabel; import com.intellij.ui.components.JBScrollPane; import com.intellij.ui.components.JBTextField; + import de.marhali.easyi18n.InstanceManager; -import de.marhali.easyi18n.model.KeyedTranslation; -import de.marhali.easyi18n.model.Translation; -import de.marhali.easyi18n.model.TranslationDelete; +import de.marhali.easyi18n.model.*; import de.marhali.easyi18n.dialog.descriptor.DeleteActionDescriptor; -import de.marhali.easyi18n.model.TranslationUpdate; import javax.swing.*; import javax.swing.border.EtchedBorder; @@ -27,6 +25,8 @@ import java.util.ResourceBundle; public class EditDialog { private final Project project; + private final KeyPathConverter converter; + private final KeyedTranslation origin; private JBTextField keyTextField; @@ -34,6 +34,7 @@ public class EditDialog { public EditDialog(Project project, KeyedTranslation origin) { this.project = project; + this.converter = new KeyPathConverter(project); this.origin = origin; } @@ -56,7 +57,7 @@ public class EditDialog { } }); - return new KeyedTranslation(keyTextField.getText(), translation); + return new KeyedTranslation(converter.split(keyTextField.getText()), translation); } private DialogBuilder prepare() { @@ -65,7 +66,7 @@ public class EditDialog { JPanel keyPanel = new JPanel(new GridLayout(0, 1, 2,2)); JBLabel keyLabel = new JBLabel(ResourceBundle.getBundle("messages").getString("translation.key")); - keyTextField = new JBTextField(this.origin.getKey()); + keyTextField = new JBTextField(this.converter.concat(this.origin.getKey())); keyLabel.setLabelFor(keyTextField); keyPanel.add(keyLabel); keyPanel.add(keyTextField); diff --git a/src/main/java/de/marhali/easyi18n/dialog/SettingsDialog.java b/src/main/java/de/marhali/easyi18n/dialog/SettingsDialog.java index da916b6..1c6b3a1 100644 --- a/src/main/java/de/marhali/easyi18n/dialog/SettingsDialog.java +++ b/src/main/java/de/marhali/easyi18n/dialog/SettingsDialog.java @@ -51,9 +51,8 @@ public class SettingsDialog { // Reload instance InstanceManager manager = InstanceManager.get(project); - manager.store().loadFromPersistenceLayer((success) -> { - manager.bus().propagate().onUpdateData(manager.store().getData()); - }); + manager.store().loadFromPersistenceLayer((success) -> + manager.bus().propagate().onUpdateData(manager.store().getData())); } } diff --git a/src/main/java/de/marhali/easyi18n/editor/KeyAnnotator.java b/src/main/java/de/marhali/easyi18n/editor/KeyAnnotator.java index 6bb9fe7..919a97a 100644 --- a/src/main/java/de/marhali/easyi18n/editor/KeyAnnotator.java +++ b/src/main/java/de/marhali/easyi18n/editor/KeyAnnotator.java @@ -5,6 +5,9 @@ import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.openapi.project.Project; import de.marhali.easyi18n.InstanceManager; +import de.marhali.easyi18n.model.KeyPath; +import de.marhali.easyi18n.model.KeyPathConverter; +import de.marhali.easyi18n.model.SettingsState; import de.marhali.easyi18n.model.TranslationNode; import de.marhali.easyi18n.service.SettingsService; @@ -28,18 +31,21 @@ public class KeyAnnotator { return; } - String previewLocale = SettingsService.getInstance(project).getState().getPreviewLocale(); - String pathPrefix = SettingsService.getInstance(project).getState().getPathPrefix(); + SettingsState state = SettingsService.getInstance(project).getState(); + String pathPrefix = state.getPathPrefix(); + String previewLocale = state.getPreviewLocale(); + + KeyPathConverter converter = new KeyPathConverter(project); String searchKey = key.length() >= pathPrefix.length() ? key.substring(pathPrefix.length()) : key; - if(searchKey.startsWith(".")) { - searchKey = searchKey.substring(1); + if(searchKey.startsWith(KeyPath.DELIMITER)) { + searchKey = searchKey.substring(KeyPath.DELIMITER.length()); } - TranslationNode node = InstanceManager.get(project).store().getData().getNode(searchKey); + TranslationNode node = InstanceManager.get(project).store().getData().getNode(converter.split(searchKey)); if(node == null) { // Unknown translation. Just ignore it return; diff --git a/src/main/java/de/marhali/easyi18n/editor/KeyCompletionProvider.java b/src/main/java/de/marhali/easyi18n/editor/KeyCompletionProvider.java index 39e6a27..c866428 100644 --- a/src/main/java/de/marhali/easyi18n/editor/KeyCompletionProvider.java +++ b/src/main/java/de/marhali/easyi18n/editor/KeyCompletionProvider.java @@ -5,11 +5,13 @@ import com.intellij.codeInsight.lookup.*; import com.intellij.icons.AllIcons; import com.intellij.openapi.project.*; import com.intellij.util.*; + import de.marhali.easyi18n.DataStore; import de.marhali.easyi18n.InstanceManager; +import de.marhali.easyi18n.model.KeyPath; import de.marhali.easyi18n.model.Translation; import de.marhali.easyi18n.service.*; -import de.marhali.easyi18n.util.PathUtil; + import org.jetbrains.annotations.*; import java.util.*; @@ -32,58 +34,29 @@ public class KeyCompletionProvider extends CompletionProvider 0 && !pathPrefix.endsWith(KeyPath.DELIMITER)) { + pathPrefix += KeyPath.DELIMITER; } - if(pathPrefix.length() > 0 && !pathPrefix.endsWith(".")) { - pathPrefix += "."; - } + Set fullKeys = store.getData().getFullKeys(); - Set fullKeys = store.getData().getFullKeys(); - - int sections = path.split("\\.").length; - int maxSectionForwardLookup = 5; - - for(String key : fullKeys) { - // Path matches - if(key.startsWith(path)) { - String[] keySections = key.split("\\."); - - if(keySections.length > sections + maxSectionForwardLookup) { // Key is too deep nested - String shrinkKey = pathUtil.concat(Arrays.asList( - Arrays.copyOf(keySections, sections + maxSectionForwardLookup) - )); - - result.addElement(LookupElementBuilder.create(pathPrefix + shrinkKey) - .appendTailText(" I18n([])", true)); - - } else { - Translation translation = store.getData().getTranslation(key); - - if(translation != null) { - String content = translation.get(previewLocale); - - result.addElement(LookupElementBuilder.create(pathPrefix + key) - .withIcon(AllIcons.Actions.PreserveCaseHover) - .appendTailText(" I18n(" + previewLocale + ": " + content + ")", true) - ); - } - } - } + for(KeyPath currentKey : fullKeys) { + result.addElement(createElement( + pathPrefix, + currentKey, + previewLocale, + Objects.requireNonNull(store.getData().getTranslation(currentKey)) + )); } } -} + + private LookupElement createElement(String prefix, KeyPath path, String locale, Translation translation) { + return LookupElementBuilder.create(prefix + path.toSimpleString()) + .withIcon(AllIcons.Actions.PreserveCaseHover) + .appendTailText(" I18n(" + locale + ": " + translation.get(locale) + ")", true); + } +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/editor/KeyReference.java b/src/main/java/de/marhali/easyi18n/editor/KeyReference.java index 56d5733..d848bc1 100644 --- a/src/main/java/de/marhali/easyi18n/editor/KeyReference.java +++ b/src/main/java/de/marhali/easyi18n/editor/KeyReference.java @@ -7,12 +7,18 @@ import com.intellij.psi.impl.FakePsiElement; import de.marhali.easyi18n.InstanceManager; import de.marhali.easyi18n.dialog.AddDialog; import de.marhali.easyi18n.dialog.EditDialog; - +import de.marhali.easyi18n.model.KeyPath; +import de.marhali.easyi18n.model.KeyPathConverter; import de.marhali.easyi18n.model.KeyedTranslation; import de.marhali.easyi18n.model.Translation; + import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +/** + * Go to declaration reference for i18n keys. + * @author marhali + */ public class KeyReference extends PsiReferenceBase { @Nullable private final String myKey; @@ -52,12 +58,14 @@ public class KeyReference extends PsiReferenceBase { @Override public void navigate(boolean requestFocus) { - Translation translation = InstanceManager.get(getProject()).store().getData().getTranslation(getKey()); + KeyPathConverter converter = new KeyPathConverter(getProject()); + KeyPath path = converter.split(getKey()); + Translation translation = InstanceManager.get(getProject()).store().getData().getTranslation(path); if(translation != null) { - new EditDialog(getProject(), new KeyedTranslation(getKey(), translation)).showAndHandle(); + new EditDialog(getProject(), new KeyedTranslation(path, translation)).showAndHandle(); } else { - new AddDialog(getProject(), getKey()).showAndHandle(); + new AddDialog(getProject(), path).showAndHandle(); } } diff --git a/src/main/java/de/marhali/easyi18n/editor/generic/GenericFoldingBuilder.java b/src/main/java/de/marhali/easyi18n/editor/generic/GenericFoldingBuilder.java index 114847f..cbda752 100644 --- a/src/main/java/de/marhali/easyi18n/editor/generic/GenericFoldingBuilder.java +++ b/src/main/java/de/marhali/easyi18n/editor/generic/GenericFoldingBuilder.java @@ -11,6 +11,7 @@ import com.intellij.psi.util.PsiTreeUtil; import de.marhali.easyi18n.DataStore; import de.marhali.easyi18n.InstanceManager; +import de.marhali.easyi18n.model.KeyPathConverter; import de.marhali.easyi18n.model.Translation; import de.marhali.easyi18n.service.SettingsService; @@ -37,12 +38,13 @@ public class GenericFoldingBuilder extends FoldingBuilderEx { } DataStore store = InstanceManager.get(root.getProject()).store(); + KeyPathConverter converter = new KeyPathConverter(root.getProject()); for(final PsiLiteralValue literalValue : literalValues) { String value = literalValue.getValue() instanceof String ? (String) literalValue.getValue() : null; // Undefined string literal or not a translation - if(value == null || store.getData().getTranslation(value) == null) { + if(value == null || store.getData().getTranslation(converter.split(value)) == null) { continue; } @@ -65,7 +67,9 @@ public class GenericFoldingBuilder extends FoldingBuilderEx { } DataStore store = InstanceManager.get(literalValue.getProject()).store(); - Translation translation = store.getData().getTranslation(value); + KeyPathConverter converter = new KeyPathConverter(literalValue.getProject()); + + Translation translation = store.getData().getTranslation(converter.split(value)); if(translation == null) { return null; diff --git a/src/main/java/de/marhali/easyi18n/editor/generic/GenericKeyReferenceContributor.java b/src/main/java/de/marhali/easyi18n/editor/generic/GenericKeyReferenceContributor.java index a6b0542..5127178 100644 --- a/src/main/java/de/marhali/easyi18n/editor/generic/GenericKeyReferenceContributor.java +++ b/src/main/java/de/marhali/easyi18n/editor/generic/GenericKeyReferenceContributor.java @@ -6,6 +6,7 @@ import com.intellij.util.ProcessingContext; import de.marhali.easyi18n.InstanceManager; import de.marhali.easyi18n.editor.KeyReference; +import de.marhali.easyi18n.model.KeyPathConverter; import de.marhali.easyi18n.service.SettingsService; import org.jetbrains.annotations.NotNull; @@ -38,7 +39,9 @@ public class GenericKeyReferenceContributor extends PsiReferenceContributor { return PsiReference.EMPTY_ARRAY; } - if(InstanceManager.get(element.getProject()).store().getData().getTranslation(value) == null) { + KeyPathConverter converter = new KeyPathConverter(element.getProject()); + + if(InstanceManager.get(element.getProject()).store().getData().getTranslation(converter.split(value)) == null) { if(!KeyReference.isReferencable(value)) { // Creation policy return PsiReference.EMPTY_ARRAY; } diff --git a/src/main/java/de/marhali/easyi18n/editor/kotlin/KotlinKeyReferenceContributor.java b/src/main/java/de/marhali/easyi18n/editor/kotlin/KotlinKeyReferenceContributor.java index 77bfd20..bbb9203 100644 --- a/src/main/java/de/marhali/easyi18n/editor/kotlin/KotlinKeyReferenceContributor.java +++ b/src/main/java/de/marhali/easyi18n/editor/kotlin/KotlinKeyReferenceContributor.java @@ -7,6 +7,7 @@ import com.intellij.util.ProcessingContext; import de.marhali.easyi18n.InstanceManager; import de.marhali.easyi18n.editor.KeyReference; +import de.marhali.easyi18n.model.KeyPathConverter; import de.marhali.easyi18n.service.SettingsService; import org.jetbrains.annotations.NotNull; @@ -45,7 +46,9 @@ public class KotlinKeyReferenceContributor extends PsiReferenceContributor { return PsiReference.EMPTY_ARRAY; } - if(InstanceManager.get(element.getProject()).store().getData().getNode(value) == null) { + KeyPathConverter converter = new KeyPathConverter(element.getProject()); + + if(InstanceManager.get(element.getProject()).store().getData().getNode(converter.split(value)) == null) { return PsiReference.EMPTY_ARRAY; } diff --git a/src/main/java/de/marhali/easyi18n/io/json/JsonIOStrategy.java b/src/main/java/de/marhali/easyi18n/io/json/JsonIOStrategy.java index 0e32211..3d45ffa 100644 --- a/src/main/java/de/marhali/easyi18n/io/json/JsonIOStrategy.java +++ b/src/main/java/de/marhali/easyi18n/io/json/JsonIOStrategy.java @@ -67,7 +67,7 @@ public class JsonIOStrategy implements IOStrategy { throw new IllegalArgumentException("Specified folder is invalid (" + localesPath + ")"); } - TranslationData data = new TranslationData(state.isSortKeys(), state.isNestedKeys()); + TranslationData data = new TranslationData(state.isSortKeys()); for(VirtualFile file : directory.getChildren()) { if(file.isDirectory() || !isFileRelevant(state, file)) { diff --git a/src/main/java/de/marhali/easyi18n/io/json/ModularizedJsonIOStrategy.java b/src/main/java/de/marhali/easyi18n/io/json/ModularizedJsonIOStrategy.java index 518fe48..ce90a71 100644 --- a/src/main/java/de/marhali/easyi18n/io/json/ModularizedJsonIOStrategy.java +++ b/src/main/java/de/marhali/easyi18n/io/json/ModularizedJsonIOStrategy.java @@ -9,6 +9,7 @@ import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import de.marhali.easyi18n.io.IOStrategy; +import de.marhali.easyi18n.model.KeyPath; import de.marhali.easyi18n.model.SettingsState; import de.marhali.easyi18n.model.TranslationData; import de.marhali.easyi18n.model.TranslationNode; @@ -80,7 +81,7 @@ public class ModularizedJsonIOStrategy implements IOStrategy { throw new IllegalArgumentException("Specified folder is invalid (" + localesPath + ")"); } - TranslationData data = new TranslationData(state.isSortKeys(), state.isNestedKeys()); + TranslationData data = new TranslationData(state.isSortKeys()); VirtualFile[] localeDirectories = directory.getChildren(); for(VirtualFile localeDir : localeDirectories) { @@ -95,8 +96,8 @@ public class ModularizedJsonIOStrategy implements IOStrategy { String moduleName = module.getNameWithoutExtension(); - TranslationNode moduleNode = data.getNode(moduleName) != null - ? data.getNode(moduleName) + TranslationNode moduleNode = data.getNode(KeyPath.of(moduleName)) != null + ? data.getNode(KeyPath.of(moduleName)) : new TranslationNode(state.isSortKeys() ? new TreeMap<>() : new LinkedHashMap<>()); try { diff --git a/src/main/java/de/marhali/easyi18n/io/properties/PropertiesIOStrategy.java b/src/main/java/de/marhali/easyi18n/io/properties/PropertiesIOStrategy.java index 23d9f2a..74236a4 100644 --- a/src/main/java/de/marhali/easyi18n/io/properties/PropertiesIOStrategy.java +++ b/src/main/java/de/marhali/easyi18n/io/properties/PropertiesIOStrategy.java @@ -59,7 +59,7 @@ public class PropertiesIOStrategy implements IOStrategy { throw new IllegalArgumentException("Specified folder is invalid (" + localesPath + ")"); } - TranslationData data = new TranslationData(state.isSortKeys(), state.isNestedKeys()); + TranslationData data = new TranslationData(state.isSortKeys()); for(VirtualFile file : directory.getChildren()) { if(file.isDirectory() || !isFileRelevant(state, file)) { diff --git a/src/main/java/de/marhali/easyi18n/io/properties/PropertiesMapper.java b/src/main/java/de/marhali/easyi18n/io/properties/PropertiesMapper.java index ba6aa6a..8ed0a8b 100644 --- a/src/main/java/de/marhali/easyi18n/io/properties/PropertiesMapper.java +++ b/src/main/java/de/marhali/easyi18n/io/properties/PropertiesMapper.java @@ -1,8 +1,8 @@ package de.marhali.easyi18n.io.properties; +import de.marhali.easyi18n.model.KeyPath; import de.marhali.easyi18n.model.Translation; import de.marhali.easyi18n.model.TranslationData; -import de.marhali.easyi18n.model.TranslationNode; import de.marhali.easyi18n.util.StringUtil; import org.apache.commons.lang.math.NumberUtils; @@ -17,7 +17,7 @@ public class PropertiesMapper { public static void read(String locale, SortableProperties properties, TranslationData data) { for(Map.Entry entry : properties.entrySet()) { - String key = String.valueOf(entry.getKey()); + KeyPath key = new KeyPath(String.valueOf(entry.getKey())); Object value = entry.getValue(); Translation translation = data.getTranslation(key); @@ -36,18 +36,19 @@ public class PropertiesMapper { } public static void write(String locale, SortableProperties properties, TranslationData data) { - for(String key : data.getFullKeys()) { + for(KeyPath key : data.getFullKeys()) { Translation translation = data.getTranslation(key); if(translation != null && translation.containsKey(locale)) { + String simpleKey = key.toSimpleString(); String content = translation.get(locale); if(PropertiesArrayMapper.isArray(content)) { - properties.put(key, PropertiesArrayMapper.write(content)); + properties.put(simpleKey, PropertiesArrayMapper.write(content)); } else if(NumberUtils.isNumber(content)) { - properties.put(key, NumberUtils.createNumber(content)); + properties.put(simpleKey, NumberUtils.createNumber(content)); } else { - properties.put(key, content); + properties.put(simpleKey, content); } } } diff --git a/src/main/java/de/marhali/easyi18n/io/yaml/YamlIOStrategy.java b/src/main/java/de/marhali/easyi18n/io/yaml/YamlIOStrategy.java index 79b6424..4caf7b2 100644 --- a/src/main/java/de/marhali/easyi18n/io/yaml/YamlIOStrategy.java +++ b/src/main/java/de/marhali/easyi18n/io/yaml/YamlIOStrategy.java @@ -66,7 +66,7 @@ public class YamlIOStrategy implements IOStrategy { throw new IllegalArgumentException("Specified folder is invalid (" + localesPath + ")"); } - TranslationData data = new TranslationData(state.isSortKeys(), state.isNestedKeys()); + TranslationData data = new TranslationData(state.isSortKeys()); for(VirtualFile file : directory.getChildren()) { if(file.isDirectory() || !isFileRelevant(state, file)) { diff --git a/src/main/java/de/marhali/easyi18n/io/yaml/YamlMapper.java b/src/main/java/de/marhali/easyi18n/io/yaml/YamlMapper.java index 07a078e..55da295 100644 --- a/src/main/java/de/marhali/easyi18n/io/yaml/YamlMapper.java +++ b/src/main/java/de/marhali/easyi18n/io/yaml/YamlMapper.java @@ -2,7 +2,6 @@ package de.marhali.easyi18n.io.yaml; import de.marhali.easyi18n.model.Translation; import de.marhali.easyi18n.model.TranslationNode; -import de.marhali.easyi18n.util.PathUtil; import de.marhali.easyi18n.util.StringUtil; import org.apache.commons.lang.StringEscapeUtils; @@ -23,10 +22,6 @@ public class YamlMapper { public static void read(String locale, Section section, TranslationNode node) { for(String key : section.getKeys()) { Object value = section.getInScope(key).get(); - - key = StringUtil.escapeControls( - key.replace(PathUtil.DELIMITER, "\\" + PathUtil.DELIMITER), true); - TranslationNode childNode = node.getOrCreateChildren(key); if(value instanceof MapSection) { @@ -47,9 +42,7 @@ public class YamlMapper { public static void write(String locale, Section section, TranslationNode node) { for(Map.Entry entry : node.getChildren().entrySet()) { - String key = StringEscapeUtils.unescapeJava( - entry.getKey().replace("\\" + PathUtil.DELIMITER, PathUtil.DELIMITER)); - + String key = entry.getKey(); TranslationNode childNode = entry.getValue(); if(!childNode.isLeaf()) { diff --git a/src/main/java/de/marhali/easyi18n/model/KeyPath.java b/src/main/java/de/marhali/easyi18n/model/KeyPath.java index 9091539..600a66a 100644 --- a/src/main/java/de/marhali/easyi18n/model/KeyPath.java +++ b/src/main/java/de/marhali/easyi18n/model/KeyPath.java @@ -5,6 +5,7 @@ import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.regex.Pattern; /** * Represents a full translation key with all sections. @@ -16,7 +17,7 @@ public class KeyPath extends ArrayList { public static final String DELIMITER = "."; - public static KeyPath of(String... path) { + public static KeyPath of(@NotNull String... path) { return new KeyPath(List.of(path)); } @@ -24,7 +25,34 @@ public class KeyPath extends ArrayList { super(); } + public KeyPath(@NotNull KeyPath path, String... pathToAppend) { + this(path); + this.addAll(List.of(pathToAppend)); + } + public KeyPath(@NotNull Collection c) { super(c); } + + public KeyPath(@NotNull String simplePath) { + this(List.of(simplePath.split(Pattern.quote(DELIMITER)))); + } + + /** + * Note: Use {@link KeyPathConverter} if you want to keep hierarchy. + * @return simple path representation by adding delimiter between the secton nodes + */ + public String toSimpleString() { + StringBuilder builder = new StringBuilder(); + + for(String section : this) { + if(builder.length() > 0) { + builder.append(DELIMITER); + } + + builder.append(section); + } + + return builder.toString(); + } } \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/model/KeyedTranslation.java b/src/main/java/de/marhali/easyi18n/model/KeyedTranslation.java index 97a415a..04a409f 100644 --- a/src/main/java/de/marhali/easyi18n/model/KeyedTranslation.java +++ b/src/main/java/de/marhali/easyi18n/model/KeyedTranslation.java @@ -9,19 +9,19 @@ import org.jetbrains.annotations.Nullable; */ public class KeyedTranslation { - private @NotNull String key; + private @NotNull KeyPath key; private @Nullable Translation translation; - public KeyedTranslation(@NotNull String key, @Nullable Translation translation) { + public KeyedTranslation(@NotNull KeyPath key, @Nullable Translation translation) { this.key = key; this.translation = translation; } - public @NotNull String getKey() { + public KeyPath getKey() { return key; } - public void setKey(@NotNull String key) { + public void setKey(KeyPath key) { this.key = key; } diff --git a/src/main/java/de/marhali/easyi18n/model/TranslationData.java b/src/main/java/de/marhali/easyi18n/model/TranslationData.java index ba042b2..087048b 100644 --- a/src/main/java/de/marhali/easyi18n/model/TranslationData.java +++ b/src/main/java/de/marhali/easyi18n/model/TranslationData.java @@ -1,7 +1,5 @@ package de.marhali.easyi18n.model; -import de.marhali.easyi18n.util.PathUtil; - import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -11,21 +9,21 @@ import java.util.*; * Cached translation data. The data is stored in a tree structure. * Tree behaviour (sorted, non-sorted) can be specified via constructor. * For more please see {@link TranslationNode}. Example tree view: - *
- * user:
- * -- principal: 'Principal'
- * -- username:
- * -- -- title: 'Username'
- * auth:
- * -- logout: 'Logout'
- * -- login: 'Login'
- * + *
+ * {@code
+ * user:
+ *     principal: 'Principal'
+ *     username:
+ *         title: 'Username'
+ * auth:
+ *     logout: 'Logout'
+ *     login: 'Login'
+ * }
+ * 
* @author marhali */ public class TranslationData { - private final PathUtil pathUtil; - @NotNull private final Set locales; @@ -36,17 +34,15 @@ public class TranslationData { * Creates an empty instance. * @param sort Should the translation keys be sorted alphabetically */ - public TranslationData(boolean sort, boolean nestKeys) { - this(nestKeys, new HashSet<>(), new TranslationNode(sort ? new TreeMap<>() : new LinkedHashMap<>())); + public TranslationData(boolean sort) { + this(new HashSet<>(), new TranslationNode(sort ? new TreeMap<>() : new LinkedHashMap<>())); } /** - * @param nestKeys Apply key nesting. See {@link PathUtil} * @param locales Languages which can be used for translation * @param rootNode Translation tree structure */ - public TranslationData(boolean nestKeys, @NotNull Set locales, @NotNull TranslationNode rootNode) { - this.pathUtil = new PathUtil(nestKeys); + public TranslationData(@NotNull Set locales, @NotNull TranslationNode rootNode) { this.locales = locales; this.rootNode = rootNode; } @@ -76,15 +72,14 @@ public class TranslationData { * @param fullPath Absolute translation path * @return Translation node which leads to translations or nested child's */ - public @Nullable TranslationNode getNode(@NotNull String fullPath) { - List sections = this.pathUtil.split(fullPath); + public @Nullable TranslationNode getNode(@NotNull KeyPath fullPath) { TranslationNode node = this.rootNode; if(fullPath.isEmpty()) { // Return root node if empty path was supplied return node; } - for(String section : sections) { + for(String section : fullPath) { if(node == null) { return null; } @@ -98,7 +93,7 @@ public class TranslationData { * @param fullPath Absolute translation key path * @return Found translation. Can be null if path is empty or is not a leaf element */ - public @Nullable Translation getTranslation(@NotNull String fullPath) { + public @Nullable Translation getTranslation(@NotNull KeyPath fullPath) { TranslationNode node = this.getNode(fullPath); if(node == null || !node.isLeaf()) { @@ -109,50 +104,52 @@ public class TranslationData { } /** + * Create / Update or Delete a specific translation. + * The parent path of the translation will be changed if necessary. * @param fullPath Absolute translation key path * @param translation Translation to set. Can be null to delete the corresponding node */ - public void setTranslation(@NotNull String fullPath, @Nullable Translation translation) { - List sections = this.pathUtil.split(fullPath); - String nodeKey = sections.remove(sections.size() - 1); // Edge case last section - TranslationNode node = this.rootNode; - + public void setTranslation(@NotNull KeyPath fullPath, @Nullable Translation translation) { if(fullPath.isEmpty()) { - throw new IllegalArgumentException("Path cannot be empty"); + throw new IllegalArgumentException("Key path cannot be empty"); } - for(String section : sections) { // Go to the level of the key (@nodeKey) + fullPath = new KeyPath(fullPath); + String leafKey = fullPath.remove(fullPath.size() - 1); // Extract edge section as children key of parent + TranslationNode node = this.rootNode; + + for(String section : fullPath) { // Go to nested level at @leafKey TranslationNode childNode = node.getChildren().get(section); if(childNode == null) { - if(translation == null) { // Path should not be empty for delete + if(translation == null) { // Path must not be empty on delete throw new IllegalArgumentException("Delete action on empty path"); } - // Created nested section childNode = node.setChildren(section); } node = childNode; } - if(translation == null) { // Delete - node.removeChildren(nodeKey); + if(translation == null) { // Delete action + node.removeChildren(leafKey); - if(node.getChildren().isEmpty() && !node.isRoot()) { // Parent is empty now. Run delete recursively - this.setTranslation(this.pathUtil.concat(sections), null); + if(node.getChildren().isEmpty() && !node.isRoot()) { // Node is empty now. Run delete recursively + this.setTranslation(fullPath, null); } - - } else { // Create or overwrite - node.setChildren(nodeKey, translation); + return; } + + // Create or overwrite + node.setChildren(leafKey, translation); } /** * @return All translation keys as absolute paths (full-key) */ - public @NotNull Set getFullKeys() { - return this.getFullKeys("", this.rootNode); // Just use root node + public @NotNull Set getFullKeys() { + return this.getFullKeys(new KeyPath(), this.rootNode); // Just use root node } /** @@ -160,15 +157,15 @@ public class TranslationData { * @param node Node section to begin with * @return All translation keys where the path contains the specified @parentPath */ - public @NotNull Set getFullKeys(String parentPath, TranslationNode node) { - Set keys = new LinkedHashSet<>(); + public @NotNull Set getFullKeys(KeyPath parentPath, TranslationNode node) { + Set keys = new LinkedHashSet<>(); if(node.isLeaf()) { // This node does not lead to child's - just add the key keys.add(parentPath); } for(Map.Entry children : node.getChildren().entrySet()) { - keys.addAll(this.getFullKeys(this.pathUtil.append(parentPath, children.getKey()), children.getValue())); + keys.addAll(this.getFullKeys(new KeyPath(parentPath, children.getKey()), children.getValue())); } return keys; @@ -178,7 +175,6 @@ public class TranslationData { public String toString() { return "TranslationData{" + "mapClass=" + rootNode.getChildren().getClass().getSimpleName() + - ", pathUtil=" + pathUtil + ", locales=" + locales + ", rootNode=" + rootNode + '}'; diff --git a/src/main/java/de/marhali/easyi18n/model/TranslationNode.java b/src/main/java/de/marhali/easyi18n/model/TranslationNode.java index dc91f3b..744cad7 100644 --- a/src/main/java/de/marhali/easyi18n/model/TranslationNode.java +++ b/src/main/java/de/marhali/easyi18n/model/TranslationNode.java @@ -7,14 +7,13 @@ import java.util.Map; /** * Translation tree node. Manages child nodes which can be translations or also - * nodes which can lead to another translation or node. + * nodes which can lead to another translation or node.
* Navigation inside a node can be upward and downward. To construct the full - * translation key (full-key) every parent needs to be resolved recursively. - * - + * translation key (full-key) every parent needs to be resolved recursively.
+ *
* Whether the children nodes should be sorted is determined by the parent node. * For root nodes (empty parent) the {@link java.util.Map}-Type must be specified * to determine which sorting should be applied. - * * @author marhali */ public class TranslationNode { diff --git a/src/main/java/de/marhali/easyi18n/model/bus/FocusKeyListener.java b/src/main/java/de/marhali/easyi18n/model/bus/FocusKeyListener.java index ce3069f..6cae087 100644 --- a/src/main/java/de/marhali/easyi18n/model/bus/FocusKeyListener.java +++ b/src/main/java/de/marhali/easyi18n/model/bus/FocusKeyListener.java @@ -1,6 +1,8 @@ package de.marhali.easyi18n.model.bus; -import org.jetbrains.annotations.Nullable; +import de.marhali.easyi18n.model.KeyPath; + +import org.jetbrains.annotations.NotNull; /** * Single event listener. @@ -11,5 +13,5 @@ public interface FocusKeyListener { * Move the specified translation key (full-key) into focus. * @param key Absolute translation key */ - void onFocusKey(@Nullable String key); + void onFocusKey(@NotNull KeyPath key); } \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/tabs/TableView.java b/src/main/java/de/marhali/easyi18n/tabs/TableView.java index 94b4f22..596d846 100644 --- a/src/main/java/de/marhali/easyi18n/tabs/TableView.java +++ b/src/main/java/de/marhali/easyi18n/tabs/TableView.java @@ -28,15 +28,16 @@ import java.util.ResourceBundle; */ public class TableView implements BusListener { + private final JBTable table; + private final Project project; private TableModelMapper currentMapper; + private KeyPathConverter converter; private JPanel rootPanel; private JPanel containerPanel; - private JBTable table; - public TableView(Project project) { this.project = project; @@ -55,7 +56,7 @@ public class TableView implements BusListener { return; } - String fullPath = String.valueOf(table.getValueAt(row, 0)); + KeyPath fullPath = this.converter.split(String.valueOf(this.table.getValueAt(row, 0))); Translation translation = InstanceManager.get(project).store().getData().getTranslation(fullPath); if (translation != null) { @@ -65,7 +66,7 @@ public class TableView implements BusListener { private void deleteSelectedRows() { for (int selectedRow : table.getSelectedRows()) { - String fullPath = String.valueOf(table.getValueAt(selectedRow, 0)); + KeyPath fullPath = this.converter.split(String.valueOf(table.getValueAt(selectedRow, 0))); InstanceManager.get(project).processUpdate( new TranslationDelete(new KeyedTranslation(fullPath, null)) @@ -75,16 +76,19 @@ public class TableView implements BusListener { @Override public void onUpdateData(@NotNull TranslationData data) { - table.setModel(this.currentMapper = new TableModelMapper(data, update -> + this.converter = new KeyPathConverter(project); + + table.setModel(this.currentMapper = new TableModelMapper(data, this.converter, update -> InstanceManager.get(project).processUpdate(update))); } @Override - public void onFocusKey(@Nullable String key) { + public void onFocusKey(@NotNull KeyPath key) { + String concatKey = this.converter.concat(key); int row = -1; for (int i = 0; i < table.getRowCount(); i++) { - if (String.valueOf(table.getValueAt(i, 0)).equals(key)) { + if (table.getValueAt(i, 0).equals(concatKey)) { row = i; } } diff --git a/src/main/java/de/marhali/easyi18n/tabs/TreeView.java b/src/main/java/de/marhali/easyi18n/tabs/TreeView.java index d49f907..71957ab 100644 --- a/src/main/java/de/marhali/easyi18n/tabs/TreeView.java +++ b/src/main/java/de/marhali/easyi18n/tabs/TreeView.java @@ -10,10 +10,7 @@ import com.intellij.ui.treeStructure.Tree; import de.marhali.easyi18n.InstanceManager; import de.marhali.easyi18n.listener.ReturnKeyListener; -import de.marhali.easyi18n.model.KeyedTranslation; -import de.marhali.easyi18n.model.Translation; -import de.marhali.easyi18n.model.TranslationData; -import de.marhali.easyi18n.model.TranslationDelete; +import de.marhali.easyi18n.model.*; import de.marhali.easyi18n.model.bus.BusListener; import de.marhali.easyi18n.action.treeview.CollapseTreeViewAction; import de.marhali.easyi18n.action.treeview.ExpandTreeViewAction; @@ -40,6 +37,8 @@ import java.util.ResourceBundle; */ public class TreeView implements BusListener { + private final Tree tree; + private final Project project; private TreeModelMapper currentMapper; @@ -48,8 +47,6 @@ public class TreeView implements BusListener { private JPanel toolBarPanel; private JPanel containerPanel; - private Tree tree; - public TreeView(Project project) { this.project = project; @@ -87,8 +84,8 @@ public class TreeView implements BusListener { } @Override - public void onFocusKey(@Nullable String key) { - if (key != null && currentMapper != null) { + public void onFocusKey(@NotNull KeyPath key) { + if (currentMapper != null) { TreePath path = currentMapper.findTreePath(key); this.tree.getSelectionModel().setSelectionPath(path); @@ -120,7 +117,7 @@ public class TreeView implements BusListener { return; } - String fullPath = TreeUtil.getFullPath(path); + KeyPath fullPath = TreeUtil.getFullPath(path); Translation translation = InstanceManager.get(project).store().getData().getTranslation(fullPath); if (translation == null) { @@ -138,7 +135,7 @@ public class TreeView implements BusListener { } for (TreePath path : tree.getSelectionPaths()) { - String fullPath = TreeUtil.getFullPath(path); + KeyPath fullPath = TreeUtil.getFullPath(path); InstanceManager.get(project).processUpdate( new TranslationDelete(new KeyedTranslation(fullPath, null)) diff --git a/src/main/java/de/marhali/easyi18n/tabs/mapper/TableModelMapper.java b/src/main/java/de/marhali/easyi18n/tabs/mapper/TableModelMapper.java index f434c5b..209f6b0 100644 --- a/src/main/java/de/marhali/easyi18n/tabs/mapper/TableModelMapper.java +++ b/src/main/java/de/marhali/easyi18n/tabs/mapper/TableModelMapper.java @@ -20,13 +20,18 @@ import java.util.function.Consumer; public class TableModelMapper implements TableModel, SearchQueryListener { private final @NotNull TranslationData data; + private final @NotNull KeyPathConverter converter; + private final @NotNull List locales; - private @NotNull List fullKeys; + private @NotNull List fullKeys; private final @NotNull Consumer updater; - public TableModelMapper(@NotNull TranslationData data, @NotNull Consumer updater) { + public TableModelMapper(@NotNull TranslationData data, @NotNull KeyPathConverter converter, + @NotNull Consumer updater) { this.data = data; + this.converter = converter; + this.locales = new ArrayList<>(data.getLocales()); this.fullKeys = new ArrayList<>(data.getFullKeys()); @@ -41,10 +46,10 @@ public class TableModelMapper implements TableModel, SearchQueryListener { } query = query.toLowerCase(); - List matches = new ArrayList<>(); + List matches = new ArrayList<>(); - for(String key : this.data.getFullKeys()) { - if(key.toLowerCase().contains(query)) { + for(KeyPath key : this.data.getFullKeys()) { + if(this.converter.concat(key).toLowerCase().contains(query)) { matches.add(key); } else { for(String content : this.data.getTranslation(key).values()) { @@ -90,11 +95,12 @@ public class TableModelMapper implements TableModel, SearchQueryListener { @Override public Object getValueAt(int rowIndex, int columnIndex) { + KeyPath key = this.fullKeys.get(rowIndex); + if(columnIndex == 0) { // Keys - return this.fullKeys.get(rowIndex); + return this.converter.concat(key); } - String key = this.fullKeys.get(rowIndex); String locale = this.locales.get(columnIndex - 1); Translation translation = this.data.getTranslation(key); @@ -103,14 +109,14 @@ public class TableModelMapper implements TableModel, SearchQueryListener { @Override public void setValueAt(Object aValue, int rowIndex, int columnIndex) { - String key = String.valueOf(this.getValueAt(rowIndex, 0)); + KeyPath key = this.fullKeys.get(rowIndex); Translation translation = this.data.getTranslation(key); if(translation == null) { // Unknown cell return; } - String newKey = columnIndex == 0 ? String.valueOf(aValue) : key; + KeyPath newKey = columnIndex == 0 ? this.converter.split(String.valueOf(aValue)) : key; // Translation content update if(columnIndex > 0) { diff --git a/src/main/java/de/marhali/easyi18n/tabs/mapper/TreeModelMapper.java b/src/main/java/de/marhali/easyi18n/tabs/mapper/TreeModelMapper.java index 621bb10..4049e10 100644 --- a/src/main/java/de/marhali/easyi18n/tabs/mapper/TreeModelMapper.java +++ b/src/main/java/de/marhali/easyi18n/tabs/mapper/TreeModelMapper.java @@ -3,12 +3,8 @@ package de.marhali.easyi18n.tabs.mapper; import com.intellij.ide.projectView.PresentationData; import com.intellij.ui.JBColor; -import de.marhali.easyi18n.model.SettingsState; -import de.marhali.easyi18n.model.Translation; -import de.marhali.easyi18n.model.TranslationData; -import de.marhali.easyi18n.model.TranslationNode; +import de.marhali.easyi18n.model.*; import de.marhali.easyi18n.model.bus.SearchQueryListener; -import de.marhali.easyi18n.util.PathUtil; import de.marhali.easyi18n.util.UiUtil; import org.jetbrains.annotations.NotNull; @@ -26,12 +22,14 @@ import java.util.Map; public class TreeModelMapper extends DefaultTreeModel implements SearchQueryListener { private final TranslationData data; + private final KeyPathConverter converter; private final SettingsState state; public TreeModelMapper(TranslationData data, SettingsState state) { super(null); this.data = data; + this.converter = new KeyPathConverter(state.isNestedKeys()); this.state = state; DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(); @@ -42,7 +40,7 @@ public class TreeModelMapper extends DefaultTreeModel implements SearchQueryList @Override public void onSearchQuery(@Nullable String query) { DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(); - TranslationData shadow = new TranslationData(this.state.isSortKeys(), this.state.isNestedKeys()); + TranslationData shadow = new TranslationData(this.state.isSortKeys()); if(query == null) { this.generateNodes(rootNode, this.data.getRootNode()); @@ -52,9 +50,9 @@ public class TreeModelMapper extends DefaultTreeModel implements SearchQueryList query = query.toLowerCase(); - for(String currentKey : this.data.getFullKeys()) { + for(KeyPath currentKey : this.data.getFullKeys()) { Translation translation = this.data.getTranslation(currentKey); - String loweredKey = currentKey.toLowerCase(); + String loweredKey = this.converter.concat(currentKey).toLowerCase(); if(query.contains(loweredKey) || loweredKey.contains(query)) { shadow.setTranslation(currentKey, translation); @@ -100,14 +98,13 @@ public class TreeModelMapper extends DefaultTreeModel implements SearchQueryList } } - public @NotNull TreePath findTreePath(@NotNull String fullPath) { - List sections = new PathUtil(this.state.isNestedKeys()).split(fullPath); + public @NotNull TreePath findTreePath(@NotNull KeyPath fullPath) { List nodes = new ArrayList<>(); TreeNode currentNode = (TreeNode) this.getRoot(); nodes.add(currentNode); - for(String section : sections) { + for(String section : fullPath) { currentNode = this.findNode(currentNode, section); if(currentNode == null) { @@ -120,7 +117,7 @@ public class TreeModelMapper extends DefaultTreeModel implements SearchQueryList return new TreePath(nodes.toArray()); } - public @Nullable DefaultMutableTreeNode findNode(@NotNull TreeNode parent, @NotNull String key) { + private @Nullable DefaultMutableTreeNode findNode(@NotNull TreeNode parent, @NotNull String key) { for(int i = 0; i < parent.getChildCount(); i++) { TreeNode child = parent.getChildAt(i); diff --git a/src/main/java/de/marhali/easyi18n/util/PathUtil.java b/src/main/java/de/marhali/easyi18n/util/PathUtil.java deleted file mode 100644 index 25ac7e8..0000000 --- a/src/main/java/de/marhali/easyi18n/util/PathUtil.java +++ /dev/null @@ -1,77 +0,0 @@ -package de.marhali.easyi18n.util; - -import de.marhali.easyi18n.service.SettingsService; - -import com.intellij.openapi.project.Project; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.regex.Pattern; - -/** - * Utility tool for split and merge translation key paths. - * Some i18n implementations require to NOT nest the translation keys. - * This util takes care of this and checks the configured setting for this case. - * @author marhali - * @deprecated Replaced by KeyPathConverter - */ -@Deprecated -public class PathUtil { - - public static final String DELIMITER = "."; - - private final boolean nestKeys; - - public PathUtil(boolean nestKeys) { - this.nestKeys = nestKeys; - } - - public PathUtil(Project project) { - this.nestKeys = SettingsService.getInstance(project).getState().isNestedKeys(); - } - - public @NotNull List split(@NotNull String path) { - // Does not contain any sections or key nesting is disabled - if(!path.contains(DELIMITER) || !nestKeys) { - return new ArrayList<>(Collections.singletonList(path)); - } - - return new ArrayList<>(Arrays.asList( - path.split("(? sections) { - StringBuilder builder = new StringBuilder(); - - // For disabled key nesting this should be only one section - for(String section : sections) { - if(builder.length() > 0) { - builder.append(DELIMITER); - } - - builder.append(section); - } - - return builder.toString(); - } - - public @NotNull String append(@NotNull String parentPath, @NotNull String children) { - StringBuilder builder = new StringBuilder(parentPath); - - if(builder.length() > 0) { // Only add delimiter between parent and child if parent is NOT empty - builder.append(DELIMITER); - } - - return builder.append(children).toString(); - } - - @Override - public String toString() { - return "PathUtil{" + - "nestKeys=" + nestKeys + - '}'; - } -} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/util/TreeUtil.java b/src/main/java/de/marhali/easyi18n/util/TreeUtil.java index 03e3821..f71f281 100644 --- a/src/main/java/de/marhali/easyi18n/util/TreeUtil.java +++ b/src/main/java/de/marhali/easyi18n/util/TreeUtil.java @@ -1,6 +1,7 @@ package de.marhali.easyi18n.util; import com.intellij.ide.projectView.PresentationData; +import de.marhali.easyi18n.model.KeyPath; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreePath; @@ -13,13 +14,13 @@ public class TreeUtil { /** * Constructs the full path for a given {@link TreePath} - * @param path TreePath - * @return Full key (e.g user.username.title) + * @param treePath TreePath + * @return Corresponding key path */ - public static String getFullPath(TreePath path) { - StringBuilder builder = new StringBuilder(); + public static KeyPath getFullPath(TreePath treePath) { + KeyPath keyPath = new KeyPath(); - for (Object obj : path.getPath()) { + for (Object obj : treePath.getPath()) { DefaultMutableTreeNode node = (DefaultMutableTreeNode) obj; Object value = node.getUserObject(); String section = value instanceof PresentationData ? @@ -29,13 +30,9 @@ public class TreeUtil { continue; } - if(builder.length() != 0) { - builder.append(PathUtil.DELIMITER); - } - - builder.append(section); + keyPath.add(section); } - return builder.toString(); + return keyPath; } } \ No newline at end of file diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index 790d8f4..ead960a 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -19,6 +19,6 @@ settings.path.file-pattern-tooltip=Defines a wildcard matcher to filter relevant settings.path.prefix=Path prefix settings.preview=Preview locale settings.keys.sort=Sort translation keys alphabetically -settings.keys.nested=Nest translation keys if possible +settings.keys.nested=Escape delimiter character within a section layer. settings.editor.assistance=I18n key completion, annotation and reference inside editor error.io=Could not process file {0} with {1}. Unwanted files can be ignored via Translation file wildcard matcher option. \ No newline at end of file diff --git a/src/test/java/de/marhali/easyi18n/TranslationDataTest.java b/src/test/java/de/marhali/easyi18n/TranslationDataTest.java index 7e09eed..4e788f0 100644 --- a/src/test/java/de/marhali/easyi18n/TranslationDataTest.java +++ b/src/test/java/de/marhali/easyi18n/TranslationDataTest.java @@ -1,5 +1,6 @@ package de.marhali.easyi18n; +import de.marhali.easyi18n.model.KeyPath; import de.marhali.easyi18n.model.Translation; import de.marhali.easyi18n.model.TranslationData; import de.marhali.easyi18n.model.TranslationNode; @@ -15,256 +16,184 @@ import java.util.*; */ public class TranslationDataTest { - private final int numOfTranslations = 18; + private final int numOfTranslations = 14; + private final Translation translation = new Translation("en", "test"); private void addTranslations(TranslationData data) { - data.setTranslation("zulu", new Translation("en", "test")); - data.setTranslation("gamma", new Translation("en", "test")); + data.setTranslation(KeyPath.of("zulu"), translation); + data.setTranslation(KeyPath.of("gamma"), translation); - data.setTranslation("foxtrot.super.long.key", new Translation("en", "test")); + data.setTranslation(KeyPath.of("foxtrot.super.long.key"), translation); + data.setTranslation(KeyPath.of("foxtrot", "super", "long", "key"), translation); - data.setTranslation("bravo.b", new Translation("en", "test")); - data.setTranslation("bravo.c", new Translation("en", "test")); - data.setTranslation("bravo.a", new Translation("en", "test")); - data.setTranslation("bravo.d", new Translation("en", "test")); - data.setTranslation("bravo.long.bravo", new Translation("en", "test")); - data.setTranslation("bravo.long.charlie.a", new Translation("en", "test")); - data.setTranslation("bravo.long.alpha", new Translation("en", "test")); + data.setTranslation(KeyPath.of("charlie.b", "sub"), translation); + data.setTranslation(KeyPath.of("charlie.a", "sub"), translation); - data.setTranslation("alpha.b", new Translation("en", "test")); - data.setTranslation("alpha.c", new Translation("en", "test")); - data.setTranslation("alpha.a", new Translation("en", "test")); - data.setTranslation("alpha.d", new Translation("en", "test")); + data.setTranslation(KeyPath.of("bravo.b"), translation); + data.setTranslation(KeyPath.of("bravo.c"), translation); + data.setTranslation(KeyPath.of("bravo.a"), translation); + data.setTranslation(KeyPath.of("bravo.d"), translation); - data.setTranslation("charlie.b", new Translation("en", "test")); - data.setTranslation("charlie.c", new Translation("en", "test")); - data.setTranslation("charlie.a", new Translation("en", "test")); - data.setTranslation("charlie.d", new Translation("en", "test")); + data.setTranslation(KeyPath.of("bravo", "b"), translation); + data.setTranslation(KeyPath.of("bravo", "c"), translation); + data.setTranslation(KeyPath.of("bravo", "a"), translation); + data.setTranslation(KeyPath.of("bravo", "d"), translation); } @Test public void testKeySorting() { - TranslationData data = new TranslationData(true, true); + TranslationData data = new TranslationData(true); this.addTranslations(data); - Set expectation = new LinkedHashSet<>(Arrays.asList( - "alpha.a", "alpha.b", "alpha.c", "alpha.d", - "bravo.a", "bravo.b", "bravo.c", "bravo.d", - "bravo.long.alpha", "bravo.long.bravo", "bravo.long.charlie.a", - "charlie.a", "charlie.b", "charlie.c", "charlie.d", - "foxtrot.super.long.key", - "gamma", - "zulu" + Set expectation = new LinkedHashSet<>(Arrays.asList( + KeyPath.of("bravo", "a"), KeyPath.of("bravo", "b"), KeyPath.of("bravo", "c"), KeyPath.of("bravo", "d"), + KeyPath.of("bravo.a"), KeyPath.of("bravo.b"), KeyPath.of("bravo.c"), KeyPath.of("bravo.d"), + KeyPath.of("charlie.a", "sub"), KeyPath.of("charlie.b", "sub"), + KeyPath.of("foxtrot", "super", "long", "key"), + KeyPath.of("foxtrot.super.long.key"), + KeyPath.of("gamma"), + KeyPath.of("zulu") )); Assert.assertEquals(data.getFullKeys(), expectation); + Assert.assertEquals(data.getFullKeys().size(), numOfTranslations); } @Test public void testKeyUnordered() { - TranslationData data = new TranslationData(false, true); + TranslationData data = new TranslationData(false); this.addTranslations(data); - Set expectation = new LinkedHashSet<>(Arrays.asList( - "zulu", - "gamma", - "foxtrot.super.long.key", - "bravo.b", "bravo.c", "bravo.a", "bravo.d", - "bravo.long.bravo", "bravo.long.charlie.a", "bravo.long.alpha", - "alpha.b", "alpha.c", "alpha.a", "alpha.d", - "charlie.b", "charlie.c", "charlie.a", "charlie.d" + Set expectation = new LinkedHashSet<>(Arrays.asList( + KeyPath.of("zulu"), + KeyPath.of("gamma"), + KeyPath.of("foxtrot.super.long.key"), + KeyPath.of("foxtrot", "super", "long", "key"), + KeyPath.of("charlie.b", "sub"), KeyPath.of("charlie.a", "sub"), + KeyPath.of("bravo.b"), KeyPath.of("bravo.c"), KeyPath.of("bravo.a"), KeyPath.of("bravo.d"), + KeyPath.of("bravo", "b"), KeyPath.of("bravo", "c"), KeyPath.of("bravo", "a"), KeyPath.of("bravo", "d") )); Assert.assertEquals(data.getFullKeys(), expectation); + Assert.assertEquals(data.getFullKeys().size(), numOfTranslations); } @Test - public void testKeyNesting() { - TranslationData data = new TranslationData(true, true); + public void testDelete() { + TranslationData data = new TranslationData(true); - data.setTranslation("nested.alpha", new Translation("en", "test")); - data.setTranslation("nested.bravo", new Translation("en", "test")); - data.setTranslation("other.alpha", new Translation("en", "test")); - data.setTranslation("other.bravo", new Translation("en", "test")); + data.setTranslation(KeyPath.of("alpha"), translation); + data.setTranslation(KeyPath.of("nested.alpha"), translation); + data.setTranslation(KeyPath.of("nested.long.bravo"), translation); - Assert.assertEquals(data.getRootNode().getChildren().size(), 2); + data.setTranslation(KeyPath.of("beta"), translation); + data.setTranslation(KeyPath.of("nested", "alpha"), translation); + data.setTranslation(KeyPath.of("nested", "long", "bravo"), translation); - for(TranslationNode node : data.getRootNode().getChildren().values()) { - Assert.assertFalse(node.isLeaf()); - } - } + Assert.assertEquals(data.getFullKeys().size(), 6); - @Test - public void testKeyNonNested() { - TranslationData data = new TranslationData(true, false); - this.addTranslations(data); - - Assert.assertEquals(data.getRootNode().getChildren().size(), this.numOfTranslations); - - for(TranslationNode node : data.getRootNode().getChildren().values()) { - Assert.assertTrue(node.isLeaf()); - } - } - - @Test - public void testDeleteNested() { - TranslationData data = new TranslationData(true, true); - - Translation value = new Translation("en", "test"); - - data.setTranslation("alpha", value); - data.setTranslation("nested.alpha", value); - data.setTranslation("nested.long.bravo", value); + data.setTranslation(KeyPath.of("alpha"), null); + data.setTranslation(KeyPath.of("nested.alpha"), null); + data.setTranslation(KeyPath.of("nested.long.bravo"), null); Assert.assertEquals(data.getFullKeys().size(), 3); - data.setTranslation("alpha", null); - data.setTranslation("nested.alpha", null); - data.setTranslation("nested.long.bravo", null); + data.setTranslation(KeyPath.of("beta"), null); + data.setTranslation(KeyPath.of("nested", "alpha"), null); + data.setTranslation(KeyPath.of("nested", "long", "bravo"), null); Assert.assertEquals(data.getFullKeys().size(), 0); - Assert.assertNull(data.getTranslation("alpha")); - Assert.assertNull(data.getTranslation("nested.alpha")); - Assert.assertNull(data.getTranslation("nested.long.bravo")); + + Assert.assertNull(data.getTranslation(KeyPath.of("alpha"))); + Assert.assertNull(data.getTranslation(KeyPath.of("nested.alpha"))); + Assert.assertNull(data.getTranslation(KeyPath.of("nested.long.bravo"))); + + Assert.assertNull(data.getTranslation(KeyPath.of("beta"))); + Assert.assertNull(data.getTranslation(KeyPath.of("nested", "alpha"))); + Assert.assertNull(data.getTranslation(KeyPath.of("nested", "long", "bravo"))); } @Test - public void testDeleteNonNested() { - TranslationData data = new TranslationData(true, false); - - Translation value = new Translation("en", "test"); - - data.setTranslation("alpha", value); - data.setTranslation("nested.alpha", value); - data.setTranslation("nested.long.bravo", value); - - Assert.assertEquals(data.getFullKeys().size(), 3); - - data.setTranslation("alpha", null); - data.setTranslation("nested.alpha", null); - data.setTranslation("nested.long.bravo", null); - - Assert.assertEquals(data.getFullKeys().size(), 0); - Assert.assertNull(data.getTranslation("alpha")); - Assert.assertNull(data.getTranslation("nested.alpha")); - Assert.assertNull(data.getTranslation("nested.long.bravo")); - } - - @Test - public void testRecurseDeleteNonNested() { - TranslationData data = new TranslationData(true, false); + public void testDeleteRecursively() { + TranslationData data = new TranslationData(true); this.addTranslations(data); - data.setTranslation("foxtrot.super.long.key", null); + data.setTranslation(KeyPath.of("foxtrot.super.long.key"), null); + data.setTranslation(KeyPath.of("foxtrot", "super", "long", "key"), null); - Assert.assertNull(data.getTranslation("foxtrot.super.long.key")); + Assert.assertNull(data.getTranslation(KeyPath.of("foxtrot.super.long.key"))); Assert.assertNull(data.getRootNode().getChildren().get("foxtrot")); + Assert.assertEquals(data.getFullKeys().size(), numOfTranslations - 2); } @Test - public void testRecurseDeleteNested() { - TranslationData data = new TranslationData(true, true); - this.addTranslations(data); - - data.setTranslation("foxtrot.super.long.key", null); - - Assert.assertNull(data.getTranslation("foxtrot.super.long.key")); - Assert.assertNull(data.getRootNode().getChildren().get("foxtrot")); - } - - @Test - public void testOverwriteNonNested() { - TranslationData data = new TranslationData(true, false); + public void testOverwrite() { + TranslationData data = new TranslationData(true); Translation before = new Translation("en", "before"); Translation after = new Translation("en", "after"); - data.setTranslation("alpha", before); - data.setTranslation("nested.alpha", before); - data.setTranslation("nested.long.bravo", before); + data.setTranslation(KeyPath.of("alpha"), before); + data.setTranslation(KeyPath.of("nested.alpha"), before); + data.setTranslation(KeyPath.of("nested.long.bravo"), before); + data.setTranslation(KeyPath.of("beta"), before); + data.setTranslation(KeyPath.of("nested", "alpha"), before); + data.setTranslation(KeyPath.of("nested", "long", "bravo"), before); - Assert.assertEquals(data.getTranslation("alpha"), before); - Assert.assertEquals(data.getTranslation("alpha"), before); - Assert.assertEquals(data.getTranslation("alpha"), before); + Assert.assertEquals(data.getTranslation(KeyPath.of("alpha")), before); + Assert.assertEquals(data.getTranslation(KeyPath.of("nested.alpha")), before); + Assert.assertEquals(data.getTranslation(KeyPath.of("nested.long.bravo")), before); + Assert.assertEquals(data.getTranslation(KeyPath.of("beta")), before); + Assert.assertEquals(data.getTranslation(KeyPath.of("nested", "alpha")), before); + Assert.assertEquals(data.getTranslation(KeyPath.of("nested", "long", "bravo")), before); - data.setTranslation("alpha", after); - data.setTranslation("nested.alpha", after); - data.setTranslation("nested.long.bravo", after); + data.setTranslation(KeyPath.of("alpha"), after); + data.setTranslation(KeyPath.of("nested.alpha"), after); + data.setTranslation(KeyPath.of("nested.long.bravo"), after); + data.setTranslation(KeyPath.of("beta"), after); + data.setTranslation(KeyPath.of("nested", "alpha"), after); + data.setTranslation(KeyPath.of("nested", "long", "bravo"), after); - Assert.assertEquals(data.getTranslation("alpha"), after); - Assert.assertEquals(data.getTranslation("alpha"), after); - Assert.assertEquals(data.getTranslation("alpha"), after); + Assert.assertEquals(data.getTranslation(KeyPath.of("alpha")), after); + Assert.assertEquals(data.getTranslation(KeyPath.of("nested.alpha")), after); + Assert.assertEquals(data.getTranslation(KeyPath.of("nested.long.bravo")), after); + Assert.assertEquals(data.getTranslation(KeyPath.of("beta")), after); + Assert.assertEquals(data.getTranslation(KeyPath.of("nested", "alpha")), after); + Assert.assertEquals(data.getTranslation(KeyPath.of("nested", "long", "bravo")), after); } @Test - public void testOverwriteNested() { - TranslationData data = new TranslationData(true, true); + public void testTransformRecursively() { + TranslationData data = new TranslationData(true); - Translation before = new Translation("en", "before"); - Translation after = new Translation("en", "after"); + data.setTranslation(KeyPath.of("alpha.nested.key"), translation); + data.setTranslation(KeyPath.of("alpha.other"), translation); + data.setTranslation(KeyPath.of("bravo"), translation); + data.setTranslation(KeyPath.of("alpha", "nested", "key"), translation); + data.setTranslation(KeyPath.of("alpha", "other"), translation); + data.setTranslation(KeyPath.of("charlie"), translation); - data.setTranslation("alpha", before); - data.setTranslation("nested.alpha", before); - data.setTranslation("nested.long.bravo", before); + Assert.assertEquals(6, data.getFullKeys().size()); - Assert.assertEquals(data.getTranslation("alpha"), before); - Assert.assertEquals(data.getTranslation("alpha"), before); - Assert.assertEquals(data.getTranslation("alpha"), before); + data.setTranslation(KeyPath.of("alpha.nested"), translation); + data.setTranslation(KeyPath.of("alpha.other.new"), translation); + data.setTranslation(KeyPath.of("bravo"), null); + data.setTranslation(KeyPath.of("alpha", "nested"), translation); + data.setTranslation(KeyPath.of("alpha", "other", "new"), translation); + data.setTranslation(KeyPath.of("charlie"), null); - data.setTranslation("alpha", after); - data.setTranslation("nested.alpha", after); - data.setTranslation("nested.long.bravo", after); + Assert.assertEquals(6, data.getFullKeys().size()); - Assert.assertEquals(data.getTranslation("alpha"), after); - Assert.assertEquals(data.getTranslation("alpha"), after); - Assert.assertEquals(data.getTranslation("alpha"), after); - } + Assert.assertNotNull(data.getTranslation(KeyPath.of("alpha.nested.key"))); + Assert.assertNotNull(data.getTranslation(KeyPath.of("alpha.other"))); + Assert.assertNull(data.getTranslation(KeyPath.of("bravo"))); + Assert.assertEquals(data.getTranslation(KeyPath.of("alpha.nested")), translation); + Assert.assertEquals(data.getTranslation(KeyPath.of("alpha.other.new")), translation); - @Test - public void testRecurseTransformNested() { - TranslationData data = new TranslationData(true, true); - - Translation value = new Translation("en", "test"); - - data.setTranslation("alpha.nested.key", value); - data.setTranslation("alpha.other", value); - data.setTranslation("bravo", value); - - Assert.assertEquals(data.getFullKeys().size(), 3); - - data.setTranslation("alpha.nested", value); - data.setTranslation("alpha.other.new", value); - data.setTranslation("bravo", null); - - Assert.assertEquals(data.getFullKeys().size(), 2); - Assert.assertNull(data.getTranslation("alpha.nested.key")); - Assert.assertNull(data.getTranslation("alpha.other")); - Assert.assertNull(data.getTranslation("bravo")); - Assert.assertEquals(data.getTranslation("alpha.nested"), value); - Assert.assertEquals(data.getTranslation("alpha.other.new"), value); - } - - @Test - public void testRecurseTransformNonNested() { - TranslationData data = new TranslationData(true, false); - - Translation value = new Translation("en", "test"); - - data.setTranslation("alpha.nested.key", value); - data.setTranslation("alpha.other", value); - data.setTranslation("bravo", value); - - Assert.assertEquals(data.getFullKeys().size(), 3); - - data.setTranslation("alpha.nested", value); - data.setTranslation("alpha.other.new", value); - data.setTranslation("bravo", null); - - Assert.assertEquals(data.getFullKeys().size(), 4); - Assert.assertNull(data.getTranslation("bravo")); - Assert.assertEquals(data.getTranslation("alpha.nested.key"), value); - Assert.assertEquals(data.getTranslation("alpha.other"), value); - Assert.assertEquals(data.getTranslation("alpha.nested"), value); - Assert.assertEquals(data.getTranslation("alpha.other.new"), value); + Assert.assertNull(data.getTranslation(KeyPath.of("alpha", "nested", "key"))); + Assert.assertNull(data.getTranslation(KeyPath.of("alpha", "other"))); + Assert.assertNull(data.getTranslation(KeyPath.of("charlie"))); + Assert.assertEquals(data.getTranslation(KeyPath.of("alpha", "nested")), translation); + Assert.assertEquals(data.getTranslation(KeyPath.of("alpha", "other", "new")), translation); } } \ No newline at end of file diff --git a/src/test/java/de/marhali/easyi18n/mapper/JsonMapperTest.java b/src/test/java/de/marhali/easyi18n/mapper/JsonMapperTest.java index 656244d..087a688 100644 --- a/src/test/java/de/marhali/easyi18n/mapper/JsonMapperTest.java +++ b/src/test/java/de/marhali/easyi18n/mapper/JsonMapperTest.java @@ -6,6 +6,7 @@ import com.google.gson.JsonPrimitive; import de.marhali.easyi18n.io.json.JsonArrayMapper; import de.marhali.easyi18n.io.json.JsonMapper; +import de.marhali.easyi18n.model.KeyPath; import de.marhali.easyi18n.model.TranslationData; import org.apache.commons.lang.StringEscapeUtils; @@ -16,7 +17,7 @@ import java.util.LinkedHashSet; import java.util.Set; /** - * Unit tests for {@link de.marhali.easyi18n.io.json.JsonMapper} + * Unit tests for {@link JsonMapper}. * @author marhali */ public class JsonMapperTest extends AbstractMapperTest { @@ -28,7 +29,7 @@ public class JsonMapperTest extends AbstractMapperTest { input.add("alpha", new JsonPrimitive("test")); input.add("bravo", new JsonPrimitive("test")); - TranslationData data = new TranslationData(false, true); + TranslationData data = new TranslationData(false); JsonMapper.read("en", input, data.getRootNode()); JsonObject output = new JsonObject(); @@ -45,7 +46,7 @@ public class JsonMapperTest extends AbstractMapperTest { input.add("alpha", new JsonPrimitive("test")); input.add("bravo", new JsonPrimitive("test")); - TranslationData data = new TranslationData(true, true); + TranslationData data = new TranslationData(true); JsonMapper.read("en", input, data.getRootNode()); JsonObject output = new JsonObject(); @@ -57,9 +58,9 @@ public class JsonMapperTest extends AbstractMapperTest { @Override public void testArrays() { - TranslationData data = new TranslationData(true, true); - data.setTranslation("simple", create(arraySimple)); - data.setTranslation("escaped", create(arrayEscaped)); + TranslationData data = new TranslationData(true); + data.setTranslation(KeyPath.of("simple"), create(arraySimple)); + data.setTranslation(KeyPath.of("escaped"), create(arrayEscaped)); JsonObject output = new JsonObject(); JsonMapper.write("en", output, data.getRootNode()); @@ -69,81 +70,82 @@ public class JsonMapperTest extends AbstractMapperTest { Assert.assertTrue(output.get("escaped").isJsonArray()); Assert.assertEquals(arrayEscaped, StringEscapeUtils.unescapeJava(JsonArrayMapper.read(output.get("escaped").getAsJsonArray()))); - TranslationData input = new TranslationData(true, true); + TranslationData input = new TranslationData(true); JsonMapper.read("en", output, input.getRootNode()); - Assert.assertTrue(JsonArrayMapper.isArray(input.getTranslation("simple").get("en"))); - Assert.assertTrue(JsonArrayMapper.isArray(input.getTranslation("escaped").get("en"))); + Assert.assertTrue(JsonArrayMapper.isArray(input.getTranslation(KeyPath.of("simple")).get("en"))); + Assert.assertTrue(JsonArrayMapper.isArray(input.getTranslation(KeyPath.of("escaped")).get("en"))); } @Override public void testSpecialCharacters() { - TranslationData data = new TranslationData(true, true); - data.setTranslation("chars", create(specialCharacters)); + TranslationData data = new TranslationData(true); + data.setTranslation(KeyPath.of("chars"), create(specialCharacters)); JsonObject output = new JsonObject(); JsonMapper.write("en", output, data.getRootNode()); Assert.assertEquals(specialCharacters, output.get("chars").getAsString()); - TranslationData input = new TranslationData(true, true); + TranslationData input = new TranslationData(true); JsonMapper.read("en", output, input.getRootNode()); - Assert.assertEquals(specialCharacters, StringEscapeUtils.unescapeJava(input.getTranslation("chars").get("en"))); + Assert.assertEquals(specialCharacters, + StringEscapeUtils.unescapeJava(input.getTranslation(KeyPath.of("chars")).get("en"))); } @Override public void testNestedKeys() { - TranslationData data = new TranslationData(true, true); - data.setTranslation("nested.key.section", create("test")); + TranslationData data = new TranslationData(true); + data.setTranslation(KeyPath.of("nested", "key", "section"), create("test")); JsonObject output = new JsonObject(); JsonMapper.write("en", output, data.getRootNode()); Assert.assertEquals("test", output.getAsJsonObject("nested").getAsJsonObject("key").get("section").getAsString()); - TranslationData input = new TranslationData(true, true); + TranslationData input = new TranslationData(true); JsonMapper.read("en", output, input.getRootNode()); - Assert.assertEquals("test", input.getTranslation("nested.key.section").get("en")); + Assert.assertEquals("test", input.getTranslation(KeyPath.of("nested", "key", "section")).get("en")); } @Override public void testNonNestedKeys() { - TranslationData data = new TranslationData(true, false); - data.setTranslation("long.key.with.many.sections", create("test")); + TranslationData data = new TranslationData(true); + data.setTranslation(KeyPath.of("long.key.with.many.sections"), create("test")); JsonObject output = new JsonObject(); JsonMapper.write("en", output, data.getRootNode()); Assert.assertTrue(output.has("long.key.with.many.sections")); - TranslationData input = new TranslationData(true, false); + TranslationData input = new TranslationData(true); JsonMapper.read("en", output, input.getRootNode()); - Assert.assertEquals("test", input.getTranslation("long.key.with.many.sections").get("en")); + Assert.assertEquals("test", input.getTranslation(KeyPath.of("long.key.with.many.sections")).get("en")); } @Override public void testLeadingSpace() { - TranslationData data = new TranslationData(true, true); - data.setTranslation("space", create(leadingSpace)); + TranslationData data = new TranslationData(true); + data.setTranslation(KeyPath.of("space"), create(leadingSpace)); JsonObject output = new JsonObject(); JsonMapper.write("en", output, data.getRootNode()); Assert.assertEquals(leadingSpace, output.get("space").getAsString()); - TranslationData input = new TranslationData(true, true); + TranslationData input = new TranslationData(true); JsonMapper.read("en", output, input.getRootNode()); - Assert.assertEquals(leadingSpace, input.getTranslation("space").get("en")); + Assert.assertEquals(leadingSpace, input.getTranslation(KeyPath.of("space")).get("en")); } @Override public void testNumbers() { - TranslationData data = new TranslationData(true, true); - data.setTranslation("numbered", create("15000")); + TranslationData data = new TranslationData(true); + data.setTranslation(KeyPath.of("numbered"), create("15000")); JsonObject output = new JsonObject(); JsonMapper.write("en", output, data.getRootNode()); @@ -154,6 +156,6 @@ public class JsonMapperTest extends AbstractMapperTest { input.addProperty("numbered", 143.23); JsonMapper.read("en", input, data.getRootNode()); - Assert.assertEquals("143.23", data.getTranslation("numbered").get("en")); + Assert.assertEquals("143.23", data.getTranslation(KeyPath.of("numbered")).get("en")); } } \ No newline at end of file diff --git a/src/test/java/de/marhali/easyi18n/mapper/PropertiesMapperTest.java b/src/test/java/de/marhali/easyi18n/mapper/PropertiesMapperTest.java index e883b3e..a17e6fd 100644 --- a/src/test/java/de/marhali/easyi18n/mapper/PropertiesMapperTest.java +++ b/src/test/java/de/marhali/easyi18n/mapper/PropertiesMapperTest.java @@ -3,6 +3,7 @@ package de.marhali.easyi18n.mapper; import de.marhali.easyi18n.io.properties.PropertiesArrayMapper; import de.marhali.easyi18n.io.properties.PropertiesMapper; import de.marhali.easyi18n.io.properties.SortableProperties; +import de.marhali.easyi18n.model.KeyPath; import de.marhali.easyi18n.model.TranslationData; import org.apache.commons.lang.StringEscapeUtils; @@ -11,7 +12,7 @@ import org.junit.Assert; import java.util.*; /** - * Unit tests for {@link de.marhali.easyi18n.io.properties.PropertiesMapper} + * Unit tests for {@link PropertiesMapper}. * @author marhali */ public class PropertiesMapperTest extends AbstractMapperTest { @@ -23,7 +24,7 @@ public class PropertiesMapperTest extends AbstractMapperTest { input.setProperty("alpha", "test"); input.setProperty("bravo", "test"); - TranslationData data = new TranslationData(false, true); + TranslationData data = new TranslationData(false); PropertiesMapper.read("en", input, data); SortableProperties output = new SortableProperties(false); @@ -40,7 +41,7 @@ public class PropertiesMapperTest extends AbstractMapperTest { input.setProperty("alpha", "test"); input.setProperty("bravo", "test"); - TranslationData data = new TranslationData(true, true); + TranslationData data = new TranslationData(true); PropertiesMapper.read("en", input, data); SortableProperties output = new SortableProperties(true); @@ -52,9 +53,9 @@ public class PropertiesMapperTest extends AbstractMapperTest { @Override public void testArrays() { - TranslationData data = new TranslationData(true, true); - data.setTranslation("simple", create(arraySimple)); - data.setTranslation("escaped", create(arrayEscaped)); + TranslationData data = new TranslationData(true); + data.setTranslation(KeyPath.of("simple"), create(arraySimple)); + data.setTranslation(KeyPath.of("escaped"), create(arrayEscaped)); SortableProperties output = new SortableProperties(true); PropertiesMapper.write("en", output, data); @@ -64,83 +65,84 @@ public class PropertiesMapperTest extends AbstractMapperTest { Assert.assertTrue(output.get("escaped") instanceof String[]); Assert.assertEquals(arrayEscaped, StringEscapeUtils.unescapeJava(PropertiesArrayMapper.read((String[]) output.get("escaped")))); - TranslationData input = new TranslationData(true, true); + TranslationData input = new TranslationData(true); PropertiesMapper.read("en", output, input); - Assert.assertTrue(PropertiesArrayMapper.isArray(input.getTranslation("simple").get("en"))); - Assert.assertTrue(PropertiesArrayMapper.isArray(input.getTranslation("escaped").get("en"))); + Assert.assertTrue(PropertiesArrayMapper.isArray(input.getTranslation(KeyPath.of("simple")).get("en"))); + Assert.assertTrue(PropertiesArrayMapper.isArray(input.getTranslation(KeyPath.of("escaped")).get("en"))); } @Override public void testSpecialCharacters() { - TranslationData data = new TranslationData(true, true); - data.setTranslation("chars", create(specialCharacters)); + TranslationData data = new TranslationData(true); + data.setTranslation(KeyPath.of("chars"), create(specialCharacters)); SortableProperties output = new SortableProperties(true); PropertiesMapper.write("en", output, data); Assert.assertEquals(specialCharacters, output.get("chars")); - TranslationData input = new TranslationData(true, true); + TranslationData input = new TranslationData(true); PropertiesMapper.read("en", output, input); - Assert.assertEquals(specialCharacters, StringEscapeUtils.unescapeJava(input.getTranslation("chars").get("en"))); + Assert.assertEquals(specialCharacters, StringEscapeUtils.unescapeJava(input.getTranslation(KeyPath.of("chars")).get("en"))); } @Override public void testNestedKeys() { - TranslationData data = new TranslationData(true, true); - data.setTranslation("nested.key.sections", create("test")); + TranslationData data = new TranslationData(true); + data.setTranslation(KeyPath.of("nested", "key", "sections"), create("test")); SortableProperties output = new SortableProperties(true); PropertiesMapper.write("en", output, data); Assert.assertEquals("test", output.get("nested.key.sections")); - TranslationData input = new TranslationData(true, true); + TranslationData input = new TranslationData(true); PropertiesMapper.read("en", output, input); + System.out.println(input); + Assert.assertTrue(input.getRootNode().getChildren().containsKey("nested")); - Assert.assertEquals("test", input.getTranslation("nested.key.sections").get("en")); + Assert.assertEquals("test", input.getTranslation(KeyPath.of("nested", "key", "sections")).get("en")); } @Override - public void testNonNestedKeys() { - TranslationData data = new TranslationData(true, false); - data.setTranslation("long.key.with.many.sections", create("test")); + public void testNonNestedKeys() { // Note: Key nesting is not supported in properties file. + TranslationData data = new TranslationData(true); + data.setTranslation(KeyPath.of("long.key.with.many.sections"), create("test")); SortableProperties output = new SortableProperties(true); PropertiesMapper.write("en", output, data); Assert.assertNotNull(output.get("long.key.with.many.sections")); - TranslationData input = new TranslationData(true, false); + TranslationData input = new TranslationData(true); PropertiesMapper.read("en", output, input); - Assert.assertEquals("test", input.getRootNode().getChildren() - .get("long.key.with.many.sections").getValue().get("en")); + Assert.assertEquals("test", input.getTranslation(KeyPath.of("long", "key", "with", "many", "sections")).get("en")); } @Override public void testLeadingSpace() { - TranslationData data = new TranslationData(true, true); - data.setTranslation("space", create(leadingSpace)); + TranslationData data = new TranslationData(true); + data.setTranslation(KeyPath.of("space"), create(leadingSpace)); SortableProperties output = new SortableProperties(true); PropertiesMapper.write("en", output, data); Assert.assertEquals(leadingSpace, output.get("space")); - TranslationData input = new TranslationData(true, true); + TranslationData input = new TranslationData(true); PropertiesMapper.read("en", output, input); - Assert.assertEquals(leadingSpace, input.getTranslation("space").get("en")); + Assert.assertEquals(leadingSpace, input.getTranslation(KeyPath.of("space")).get("en")); } @Override public void testNumbers() { - TranslationData data = new TranslationData(true, true); - data.setTranslation("numbered", create("15000")); + TranslationData data = new TranslationData(true); + data.setTranslation(KeyPath.of("numbered"), create("15000")); SortableProperties output = new SortableProperties(true); PropertiesMapper.write("en", output, data); @@ -151,6 +153,6 @@ public class PropertiesMapperTest extends AbstractMapperTest { input.put("numbered", 143.23); PropertiesMapper.read("en", input, data); - Assert.assertEquals("143.23", data.getTranslation("numbered").get("en")); + Assert.assertEquals("143.23", data.getTranslation(KeyPath.of("numbered")).get("en")); } } \ No newline at end of file diff --git a/src/test/java/de/marhali/easyi18n/mapper/YamlMapperTest.java b/src/test/java/de/marhali/easyi18n/mapper/YamlMapperTest.java index 77d1bcd..ca3cf7b 100644 --- a/src/test/java/de/marhali/easyi18n/mapper/YamlMapperTest.java +++ b/src/test/java/de/marhali/easyi18n/mapper/YamlMapperTest.java @@ -2,6 +2,7 @@ package de.marhali.easyi18n.mapper; import de.marhali.easyi18n.io.yaml.YamlArrayMapper; import de.marhali.easyi18n.io.yaml.YamlMapper; +import de.marhali.easyi18n.model.KeyPath; import de.marhali.easyi18n.model.TranslationData; import org.apache.commons.lang.StringEscapeUtils; @@ -15,7 +16,7 @@ import java.util.LinkedHashSet; import java.util.Set; /** - * Unit tests for {@link de.marhali.easyi18n.io.yaml.YamlMapper} + * Unit tests for {@link YamlMapper}. * @author marhali */ public class YamlMapperTest extends AbstractMapperTest { @@ -27,7 +28,7 @@ public class YamlMapperTest extends AbstractMapperTest { input.set("alpha", "test"); input.set("bravo", "test"); - TranslationData data = new TranslationData(false, true); + TranslationData data = new TranslationData(false); YamlMapper.read("en", input, data.getRootNode()); Section output = new MapSection(); @@ -44,7 +45,7 @@ public class YamlMapperTest extends AbstractMapperTest { input.set("alpha", "test"); input.set("bravo", "test"); - TranslationData data = new TranslationData(true, true); + TranslationData data = new TranslationData(true); YamlMapper.read("en", input, data.getRootNode()); Section output = new MapSection(); @@ -56,9 +57,9 @@ public class YamlMapperTest extends AbstractMapperTest { @Override public void testArrays() { - TranslationData data = new TranslationData(true, true); - data.setTranslation("simple", create(arraySimple)); - data.setTranslation("escaped", create(arrayEscaped)); + TranslationData data = new TranslationData(true); + data.setTranslation(KeyPath.of("simple"), create(arraySimple)); + data.setTranslation(KeyPath.of("escaped"), create(arrayEscaped)); Section output = new MapSection(); YamlMapper.write("en", output, data.getRootNode()); @@ -68,81 +69,82 @@ public class YamlMapperTest extends AbstractMapperTest { Assert.assertTrue(output.isList("escaped")); Assert.assertEquals(arrayEscaped, StringEscapeUtils.unescapeJava(YamlArrayMapper.read(output.getList("escaped").get()))); - TranslationData input = new TranslationData(true, true); + TranslationData input = new TranslationData(true); YamlMapper.read("en", output, input.getRootNode()); - Assert.assertTrue(YamlArrayMapper.isArray(input.getTranslation("simple").get("en"))); - Assert.assertTrue(YamlArrayMapper.isArray(input.getTranslation("escaped").get("en"))); + Assert.assertTrue(YamlArrayMapper.isArray(input.getTranslation(KeyPath.of("simple")).get("en"))); + Assert.assertTrue(YamlArrayMapper.isArray(input.getTranslation(KeyPath.of("escaped")).get("en"))); } @Override public void testSpecialCharacters() { - TranslationData data = new TranslationData(true, true); - data.setTranslation("chars", create(specialCharacters)); + TranslationData data = new TranslationData(true); + data.setTranslation(KeyPath.of("chars"), create(specialCharacters)); Section output = new MapSection(); YamlMapper.write("en", output, data.getRootNode()); Assert.assertEquals(specialCharacters, output.getString("chars").get()); - TranslationData input = new TranslationData(true, true); + TranslationData input = new TranslationData(true); YamlMapper.read("en", output, input.getRootNode()); - Assert.assertEquals(specialCharacters, StringEscapeUtils.unescapeJava(input.getTranslation("chars").get("en"))); + Assert.assertEquals(specialCharacters, + StringEscapeUtils.unescapeJava(input.getTranslation(KeyPath.of("chars")).get("en"))); } @Override public void testNestedKeys() { - TranslationData data = new TranslationData(true, true); - data.setTranslation("nested.key.section", create("test")); + TranslationData data = new TranslationData(true); + data.setTranslation(KeyPath.of("nested", "key", "section"), create("test")); Section output = new MapSection(); YamlMapper.write("en", output, data.getRootNode()); Assert.assertEquals("test", output.getString("nested.key.section").get()); - TranslationData input = new TranslationData(true, true); + TranslationData input = new TranslationData(true); YamlMapper.read("en", output, input.getRootNode()); - Assert.assertEquals("test", input.getTranslation("nested.key.section").get("en")); + Assert.assertEquals("test", input.getTranslation(KeyPath.of("nested", "key", "section")).get("en")); } @Override public void testNonNestedKeys() { - TranslationData data = new TranslationData(true, false); - data.setTranslation("long.key.with.many.sections", create("test")); + TranslationData data = new TranslationData(true); + data.setTranslation(KeyPath.of("long.key.with.many.sections"), create("test")); Section output = new MapSection(); YamlMapper.write("en", output, data.getRootNode()); Assert.assertTrue(output.getKeys().contains("long.key.with.many.sections")); - TranslationData input = new TranslationData(true, false); + TranslationData input = new TranslationData(true); YamlMapper.read("en", output, input.getRootNode()); - Assert.assertEquals("test", input.getTranslation("long.key.with.many.sections").get("en")); + Assert.assertEquals("test", input.getTranslation(KeyPath.of("long.key.with.many.sections")).get("en")); } @Override public void testLeadingSpace() { - TranslationData data = new TranslationData(true, true); - data.setTranslation("space", create(leadingSpace)); + TranslationData data = new TranslationData(true); + data.setTranslation(KeyPath.of("space"), create(leadingSpace)); Section output = new MapSection(); YamlMapper.write("en", output, data.getRootNode()); Assert.assertEquals(leadingSpace, output.getString("space").get()); - TranslationData input = new TranslationData(true, true); + TranslationData input = new TranslationData(true); YamlMapper.read("en", output, input.getRootNode()); - Assert.assertEquals(leadingSpace, input.getTranslation("space").get("en")); + Assert.assertEquals(leadingSpace, input.getTranslation(KeyPath.of("space")).get("en")); } @Override public void testNumbers() { - TranslationData data = new TranslationData(true, true); - data.setTranslation("numbered", create("15000")); + TranslationData data = new TranslationData(true); + data.setTranslation(KeyPath.of("numbered"), create("15000")); Section output = new MapSection(); YamlMapper.write("en", output, data.getRootNode()); @@ -153,6 +155,6 @@ public class YamlMapperTest extends AbstractMapperTest { input.set("numbered", 143.23); YamlMapper.read("en", input, data.getRootNode()); - Assert.assertEquals("143.23", data.getTranslation("numbered").get("en")); + Assert.assertEquals("143.23", data.getTranslation(KeyPath.of("numbered")).get("en")); } } \ No newline at end of file