upgrade to new data structure

This commit is contained in:
Marcel Haßlinger 2021-11-05 15:10:23 +01:00
parent d48986ea78
commit 5fa8c46efc
40 changed files with 371 additions and 841 deletions

View File

@ -1,6 +1,6 @@
package de.marhali.easyi18n; package de.marhali.easyi18n;
import de.marhali.easyi18n.model.BusListener; import de.marhali.easyi18n.model.bus.BusListener;
import de.marhali.easyi18n.model.TranslationData; import de.marhali.easyi18n.model.TranslationData;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;

View File

@ -4,7 +4,7 @@ import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.AnActionEvent;
import de.marhali.easyi18n.service.LegacyDataStore; import de.marhali.easyi18n.InstanceManager;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -23,6 +23,6 @@ public class ReloadAction extends AnAction {
@Override @Override
public void actionPerformed(@NotNull AnActionEvent e) { public void actionPerformed(@NotNull AnActionEvent e) {
LegacyDataStore.getInstance(e.getProject()).reloadFromDisk(); InstanceManager.get(e.getProject()).store().loadFromPersistenceLayer((success) -> {});
} }
} }

View File

@ -7,8 +7,9 @@ import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.JBScrollPane; import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.components.JBTextField; import com.intellij.ui.components.JBTextField;
import de.marhali.easyi18n.service.LegacyDataStore; import de.marhali.easyi18n.InstanceManager;
import de.marhali.easyi18n.model.LegacyKeyedTranslation; import de.marhali.easyi18n.model.KeyedTranslation;
import de.marhali.easyi18n.model.Translation;
import de.marhali.easyi18n.model.TranslationCreate; import de.marhali.easyi18n.model.TranslationCreate;
import javax.swing.*; import javax.swing.*;
@ -48,16 +49,16 @@ public class AddDialog {
} }
private void saveTranslation() { private void saveTranslation() {
Map<String, String> messages = new HashMap<>(); Translation translation = new Translation();
valueTextFields.forEach((k, v) -> { valueTextFields.forEach((k, v) -> {
if(!v.getText().isEmpty()) { if(!v.getText().isEmpty()) {
messages.put(k, v.getText()); translation.put(k, v.getText());
} }
}); });
TranslationCreate creation = new TranslationCreate(new LegacyKeyedTranslation(keyTextField.getText(), messages)); TranslationCreate creation = new TranslationCreate(new KeyedTranslation(keyTextField.getText(), translation));
LegacyDataStore.getInstance(project).processUpdate(creation); InstanceManager.get(project).processUpdate(creation);
} }
private DialogBuilder prepare() { private DialogBuilder prepare() {
@ -75,7 +76,8 @@ public class AddDialog {
JPanel valuePanel = new JPanel(new GridLayout(0, 1, 2, 2)); JPanel valuePanel = new JPanel(new GridLayout(0, 1, 2, 2));
valueTextFields = new HashMap<>(); valueTextFields = new HashMap<>();
for(String locale : LegacyDataStore.getInstance(project).getTranslations().getLocales()) {
for(String locale : InstanceManager.get(project).store().getData().getLocales()) {
JBLabel localeLabel = new JBLabel(locale); JBLabel localeLabel = new JBLabel(locale);
JBTextField localeText = new JBTextField(); JBTextField localeText = new JBTextField();
localeLabel.setLabelFor(localeText); localeLabel.setLabelFor(localeText);

View File

@ -6,11 +6,12 @@ import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.ui.components.JBLabel; import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.JBScrollPane; import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.components.JBTextField; import com.intellij.ui.components.JBTextField;
import de.marhali.easyi18n.service.LegacyDataStore; import de.marhali.easyi18n.InstanceManager;
import de.marhali.easyi18n.model.LegacyKeyedTranslation; import de.marhali.easyi18n.model.KeyedTranslation;
import de.marhali.easyi18n.model.Translation;
import de.marhali.easyi18n.model.TranslationDelete; import de.marhali.easyi18n.model.TranslationDelete;
import de.marhali.easyi18n.model.LegacyTranslationUpdate;
import de.marhali.easyi18n.dialog.descriptor.DeleteActionDescriptor; import de.marhali.easyi18n.dialog.descriptor.DeleteActionDescriptor;
import de.marhali.easyi18n.model.TranslationUpdate;
import javax.swing.*; import javax.swing.*;
import javax.swing.border.EtchedBorder; import javax.swing.border.EtchedBorder;
@ -26,12 +27,12 @@ import java.util.ResourceBundle;
public class EditDialog { public class EditDialog {
private final Project project; private final Project project;
private final LegacyKeyedTranslation origin; private final KeyedTranslation origin;
private JBTextField keyTextField; private JBTextField keyTextField;
private Map<String, JBTextField> valueTextFields; private Map<String, JBTextField> valueTextFields;
public EditDialog(Project project, LegacyKeyedTranslation origin) { public EditDialog(Project project, KeyedTranslation origin) {
this.project = project; this.project = project;
this.origin = origin; this.origin = origin;
} }
@ -40,23 +41,22 @@ public class EditDialog {
int code = prepare().show(); int code = prepare().show();
if(code == DialogWrapper.OK_EXIT_CODE) { // Edit if(code == DialogWrapper.OK_EXIT_CODE) { // Edit
LegacyDataStore.getInstance(project).processUpdate(new LegacyTranslationUpdate(origin, getChanges())); InstanceManager.get(project).processUpdate(new TranslationUpdate(origin, getChanges()));
} else if(code == DeleteActionDescriptor.EXIT_CODE) { // Delete } else if(code == DeleteActionDescriptor.EXIT_CODE) { // Delete
LegacyDataStore.getInstance(project).processUpdate(new TranslationDelete(origin)); InstanceManager.get(project).processUpdate(new TranslationDelete(origin));
} }
} }
private LegacyKeyedTranslation getChanges() { private KeyedTranslation getChanges() {
Map<String, String> messages = new HashMap<>(); Translation translation = new Translation();
valueTextFields.forEach((k, v) -> { valueTextFields.forEach((k, v) -> {
if(!v.getText().isEmpty()) { if(!v.getText().isEmpty()) {
messages.put(k, v.getText()); translation.put(k, v.getText());
} }
}); });
return new LegacyKeyedTranslation(keyTextField.getText(), messages); return new KeyedTranslation(keyTextField.getText(), translation);
} }
private DialogBuilder prepare() { private DialogBuilder prepare() {
@ -74,9 +74,10 @@ public class EditDialog {
JPanel valuePanel = new JPanel(new GridLayout(0, 1, 2, 2)); JPanel valuePanel = new JPanel(new GridLayout(0, 1, 2, 2));
valueTextFields = new HashMap<>(); valueTextFields = new HashMap<>();
for(String locale : LegacyDataStore.getInstance(project).getTranslations().getLocales()) {
for(String locale : InstanceManager.get(project).store().getData().getLocales()) {
JBLabel localeLabel = new JBLabel(locale); JBLabel localeLabel = new JBLabel(locale);
JBTextField localeText = new JBTextField(this.origin.getTranslations().get(locale)); JBTextField localeText = new JBTextField(this.origin.getTranslation().get(locale));
localeLabel.setLabelFor(localeText); localeLabel.setLabelFor(localeText);
valuePanel.add(localeLabel); valuePanel.add(localeLabel);

View File

@ -9,9 +9,9 @@ import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.components.JBLabel; import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.JBTextField; import com.intellij.ui.components.JBTextField;
import de.marhali.easyi18n.InstanceManager;
import de.marhali.easyi18n.model.SettingsState; import de.marhali.easyi18n.model.SettingsState;
import de.marhali.easyi18n.service.SettingsService; import de.marhali.easyi18n.service.SettingsService;
import de.marhali.easyi18n.service.LegacyDataStore;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
@ -50,7 +50,7 @@ public class SettingsDialog {
state.setCodeAssistance(codeAssistanceCheckbox.isSelected()); state.setCodeAssistance(codeAssistanceCheckbox.isSelected());
// Reload instance // Reload instance
LegacyDataStore.getInstance(project).reloadFromDisk(); InstanceManager.get(project).store().loadFromPersistenceLayer((success) -> {});
} }
} }

View File

@ -4,8 +4,6 @@ import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import de.marhali.easyi18n.model.LocalizedNode;
import de.marhali.easyi18n.service.LegacyDataStore;
import de.marhali.easyi18n.service.SettingsService; import de.marhali.easyi18n.service.SettingsService;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;

View File

@ -5,9 +5,7 @@ import com.intellij.codeInsight.lookup.*;
import com.intellij.icons.AllIcons; import com.intellij.icons.AllIcons;
import com.intellij.openapi.project.*; import com.intellij.openapi.project.*;
import com.intellij.util.*; import com.intellij.util.*;
import de.marhali.easyi18n.model.*;
import de.marhali.easyi18n.service.*; import de.marhali.easyi18n.service.*;
import de.marhali.easyi18n.util.TranslationsUtil;
import org.jetbrains.annotations.*; import org.jetbrains.annotations.*;
import java.util.*; import java.util.*;

View File

@ -6,9 +6,6 @@ import com.intellij.psi.impl.FakePsiElement;
import de.marhali.easyi18n.dialog.AddDialog; import de.marhali.easyi18n.dialog.AddDialog;
import de.marhali.easyi18n.dialog.EditDialog; import de.marhali.easyi18n.dialog.EditDialog;
import de.marhali.easyi18n.model.LegacyKeyedTranslation;
import de.marhali.easyi18n.model.LocalizedNode;
import de.marhali.easyi18n.service.LegacyDataStore;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;

View File

@ -5,7 +5,6 @@ import com.intellij.psi.*;
import com.intellij.util.ProcessingContext; import com.intellij.util.ProcessingContext;
import de.marhali.easyi18n.editor.KeyReference; import de.marhali.easyi18n.editor.KeyReference;
import de.marhali.easyi18n.service.LegacyDataStore;
import de.marhali.easyi18n.service.SettingsService; import de.marhali.easyi18n.service.SettingsService;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;

View File

@ -6,7 +6,6 @@ import com.intellij.psi.*;
import com.intellij.util.ProcessingContext; import com.intellij.util.ProcessingContext;
import de.marhali.easyi18n.editor.KeyReference; import de.marhali.easyi18n.editor.KeyReference;
import de.marhali.easyi18n.service.LegacyDataStore;
import de.marhali.easyi18n.service.SettingsService; import de.marhali.easyi18n.service.SettingsService;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;

View File

@ -2,8 +2,6 @@ package de.marhali.easyi18n.io;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import de.marhali.easyi18n.model.Translations;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer; import java.util.function.Consumer;

View File

@ -7,10 +7,6 @@ import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFile;
import de.marhali.easyi18n.io.TranslatorIO; import de.marhali.easyi18n.io.TranslatorIO;
import de.marhali.easyi18n.model.LocalizedNode;
import de.marhali.easyi18n.model.Translations;
import de.marhali.easyi18n.util.IOUtil;
import de.marhali.easyi18n.util.JsonUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;

View File

@ -10,10 +10,6 @@ import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFile;
import de.marhali.easyi18n.io.TranslatorIO; import de.marhali.easyi18n.io.TranslatorIO;
import de.marhali.easyi18n.model.LocalizedNode;
import de.marhali.easyi18n.model.Translations;
import de.marhali.easyi18n.util.IOUtil;
import de.marhali.easyi18n.util.JsonUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;

View File

@ -6,12 +6,8 @@ import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFile;
import de.marhali.easyi18n.io.TranslatorIO; import de.marhali.easyi18n.io.TranslatorIO;
import de.marhali.easyi18n.model.LocalizedNode;
import de.marhali.easyi18n.model.Translations;
import de.marhali.easyi18n.util.IOUtil;
import de.marhali.easyi18n.util.SortedProperties; import de.marhali.easyi18n.util.SortedProperties;
import de.marhali.easyi18n.util.StringUtil; import de.marhali.easyi18n.util.StringUtil;
import de.marhali.easyi18n.util.TranslationsUtil;
import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang.StringEscapeUtils;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;

View File

@ -1,29 +0,0 @@
package de.marhali.easyi18n.model;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Interface for communication of changes for participants of the data bus.
* @author marhali
*/
public interface BusListener {
/**
* Update the translations based on the supplied data.
* @param data Updated translations
*/
void onUpdateData(@NotNull TranslationData data);
/**
* Move the specified translation key (full-key) into focus.
* @param key Absolute translation key
*/
void onFocusKey(@Nullable String key);
/**
* Filter the displayed data according to the search query. Supply 'null' to return to the normal state.
* The keys and the content itself should be considered.
* @param query Filter key or content
*/
void onSearchQuery(@Nullable String query);
}

View File

@ -1,20 +0,0 @@
package de.marhali.easyi18n.model;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Interface to communicate data changes between data store and ui components.
* @author marhali
*/
@Deprecated
public interface DataSynchronizer {
/**
* Propagates data changes to implementation classes.
* @param translations Updated translations model
* @param searchQuery Can be used to filter visible data. Like a search function for the full key path
* @param scrollToKey Focus specific translation. Can be null to disable this function
*/
void synchronize(@NotNull Translations translations, @Nullable String searchQuery, @Nullable String scrollToKey);
}

View File

@ -1,43 +0,0 @@
package de.marhali.easyi18n.model;
import java.util.Map;
/**
* Translated messages for a dedicated key.
* @author marhali
*/
@Deprecated // Might be deprecated
public class LegacyKeyedTranslation {
private String key;
private Map<String, String> translations;
public LegacyKeyedTranslation(String key, Map<String, String> translations) {
this.key = key;
this.translations = translations;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public Map<String, String> getTranslations() {
return translations;
}
public void setTranslations(Map<String, String> translations) {
this.translations = translations;
}
@Override
public String toString() {
return "KeyedTranslation{" +
"key='" + key + '\'' +
", translations=" + translations +
'}';
}
}

View File

@ -1,47 +0,0 @@
package de.marhali.easyi18n.model;
import org.jetbrains.annotations.Nullable;
/**
* Represents an update for a translated I18n-Key. Supports key creation, manipulation and deletion.
* @author marhali
*/
@Deprecated
public class LegacyTranslationUpdate {
private final @Nullable LegacyKeyedTranslation origin;
private final @Nullable LegacyKeyedTranslation change;
public LegacyTranslationUpdate(@Nullable LegacyKeyedTranslation origin, @Nullable LegacyKeyedTranslation change) {
this.origin = origin;
this.change = change;
}
public LegacyKeyedTranslation getOrigin() {
return origin;
}
public LegacyKeyedTranslation getChange() {
return change;
}
public boolean isCreation() {
return origin == null;
}
public boolean isDeletion() {
return change == null;
}
public boolean isKeyChange() {
return origin != null && change != null && !origin.getKey().equals(change.getKey());
}
@Override
public String toString() {
return "TranslationUpdate{" +
"origin=" + origin +
", change=" + change +
'}';
}
}

View File

@ -1,78 +0,0 @@
package de.marhali.easyi18n.model;
import de.marhali.easyi18n.util.MapUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
/**
* Represents structured tree view for translated messages.
* @author marhali
*/
@Deprecated
public class LocalizedNode {
public static final String ROOT_KEY = "root";
@NotNull
private final String key;
@NotNull
private TreeMap<String, LocalizedNode> children;
@NotNull
private Map<String, String> value;
public LocalizedNode(@NotNull String key, @NotNull List<LocalizedNode> children) {
this.key = key;
this.children = MapUtil.convertToTreeMap(children);
this.value = new HashMap<>();
}
public LocalizedNode(@NotNull String key, @NotNull Map<String, String> value) {
this.key = key;
this.children = new TreeMap<>();
this.value = value;
}
public @NotNull String getKey() {
return key;
}
public boolean isLeaf() {
return children.isEmpty();
}
public @NotNull Collection<LocalizedNode> getChildren() {
return children.values();
}
public @Nullable LocalizedNode getChildren(@NotNull String key) {
return children.get(key);
}
public void setChildren(@NotNull LocalizedNode... children) {
this.value.clear();
this.children = MapUtil.convertToTreeMap(Arrays.asList(children));
}
public void addChildren(@NotNull LocalizedNode... children) {
this.value.clear();
Arrays.stream(children).forEach(e -> this.children.put(e.getKey(), e));
}
public void removeChildren(@NotNull String key) {
this.children.remove(key);
}
public @NotNull Map<String, String> getValue() {
return value;
}
public void setValue(@NotNull Map<String, String> value) {
this.children.clear();
this.value = value;
}
}

View File

@ -6,8 +6,8 @@ import org.jetbrains.annotations.NotNull;
* Represents update request to create a new translation. * Represents update request to create a new translation.
* @author marhali * @author marhali
*/ */
public class TranslationCreate extends LegacyTranslationUpdate { public class TranslationCreate extends TranslationUpdate {
public TranslationCreate(@NotNull LegacyKeyedTranslation translation) { public TranslationCreate(@NotNull KeyedTranslation translation) {
super(null, translation); super(null, translation);
} }
} }

View File

@ -6,8 +6,8 @@ import org.jetbrains.annotations.NotNull;
* Represents update request to delete a existing translation. * Represents update request to delete a existing translation.
* @author marhali * @author marhali
*/ */
public class TranslationDelete extends LegacyTranslationUpdate { public class TranslationDelete extends TranslationUpdate {
public TranslationDelete(@NotNull LegacyKeyedTranslation translation) { public TranslationDelete(@NotNull KeyedTranslation translation) {
super(translation, null); super(translation, null);
} }
} }

View File

@ -1,109 +0,0 @@
package de.marhali.easyi18n.model;
import de.marhali.easyi18n.util.TranslationsUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* Represents translation state instance. IO operations will be based on this file.
* @author marhali
*/
@Deprecated
public class Translations {
public static Translations empty() {
return new Translations(new ArrayList<>(), new LocalizedNode(LocalizedNode.ROOT_KEY, new ArrayList<>()));
}
@NotNull
private final List<String> locales;
@NotNull
private final LocalizedNode nodes;
/**
* Constructs a new translation state instance.
* @param locales List of all locales which are used for create / edit I18n-Key operations
* @param nodes Represents the translation state. Internally handled as a tree. See {@link LocalizedNode}
*/
public Translations(@NotNull List<String> locales, @NotNull LocalizedNode nodes) {
this.locales = locales;
this.nodes = nodes;
}
public @NotNull List<String> getLocales() {
return locales;
}
public @NotNull LocalizedNode getNodes() {
return nodes;
}
public @Nullable LocalizedNode getNode(@NotNull String fullPath) {
List<String> sections = TranslationsUtil.getSections(fullPath);
LocalizedNode node = nodes;
for(String section : sections) {
if(node == null) {
return null;
}
node = node.getChildren(section);
}
return node;
}
public @NotNull LocalizedNode getOrCreateNode(@NotNull String fullPath) {
List<String> sections = TranslationsUtil.getSections(fullPath);
LocalizedNode node = nodes;
for(String section : sections) {
LocalizedNode subNode = node.getChildren(section);
if(subNode == null) {
subNode = new LocalizedNode(section, new ArrayList<>());
node.addChildren(subNode);
}
node = subNode;
}
return node;
}
public @NotNull List<String> getFullKeys() {
List<String> keys = new ArrayList<>();
if(nodes.isLeaf()) { // Root has no children
return keys;
}
for(LocalizedNode children : nodes.getChildren()) {
keys.addAll(getFullKeys("", children));
}
return keys;
}
public @NotNull List<String> getFullKeys(String parentFullPath, LocalizedNode localizedNode) {
List<String> keys = new ArrayList<>();
if(localizedNode.isLeaf()) {
keys.add(parentFullPath + (parentFullPath.isEmpty() ? "" : ".") + localizedNode.getKey());
return keys;
}
for(LocalizedNode children : localizedNode.getChildren()) {
String childrenPath = parentFullPath + (parentFullPath.isEmpty() ? "" : ".") + localizedNode.getKey();
keys.addAll(getFullKeys(childrenPath, children));
}
return keys;
}
}

View File

@ -0,0 +1,8 @@
package de.marhali.easyi18n.model.bus;
/**
* Interface for communication of changes for participants of the data bus.
* Every listener needs to be registered manually via {@link de.marhali.easyi18n.DataBus}.
* @author marhali
*/
public interface BusListener extends UpdateDataListener, FocusKeyListener, SearchQueryListener {}

View File

@ -0,0 +1,15 @@
package de.marhali.easyi18n.model.bus;
import org.jetbrains.annotations.Nullable;
/**
* Single event listener.
* @author marhali
*/
public interface FocusKeyListener {
/**
* Move the specified translation key (full-key) into focus.
* @param key Absolute translation key
*/
void onFocusKey(@Nullable String key);
}

View File

@ -0,0 +1,16 @@
package de.marhali.easyi18n.model.bus;
import org.jetbrains.annotations.Nullable;
/**
* Single event listener.
* @author marhali
*/
public interface SearchQueryListener {
/**
* Filter the displayed data according to the search query. Supply 'null' to return to the normal state.
* The keys and the content itself should be considered.
* @param query Filter key or content
*/
void onSearchQuery(@Nullable String query);
}

View File

@ -0,0 +1,16 @@
package de.marhali.easyi18n.model.bus;
import de.marhali.easyi18n.model.TranslationData;
import org.jetbrains.annotations.NotNull;
/**
* Single event listener.
* @author marhali
*/
public interface UpdateDataListener {
/**
* Update the translations based on the supplied data.
* @param data Updated translations
*/
void onUpdateData(@NotNull TranslationData data);
}

View File

@ -1,10 +1,5 @@
package de.marhali.easyi18n.model.table; package de.marhali.easyi18n.model.table;
import de.marhali.easyi18n.model.LocalizedNode;
import de.marhali.easyi18n.model.LegacyKeyedTranslation;
import de.marhali.easyi18n.model.LegacyTranslationUpdate;
import de.marhali.easyi18n.model.Translations;
import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.Nls;
import javax.swing.event.TableModelListener; import javax.swing.event.TableModelListener;

View File

@ -5,9 +5,6 @@ import com.intellij.openapi.project.Project;
import com.intellij.ui.JBColor; import com.intellij.ui.JBColor;
import de.marhali.easyi18n.service.SettingsService; import de.marhali.easyi18n.service.SettingsService;
import de.marhali.easyi18n.model.LocalizedNode;
import de.marhali.easyi18n.model.Translations;
import de.marhali.easyi18n.util.TranslationsUtil;
import de.marhali.easyi18n.util.UiUtil; import de.marhali.easyi18n.util.UiUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;

View File

@ -1,174 +0,0 @@
package de.marhali.easyi18n.service;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.project.Project;
import de.marhali.easyi18n.model.LocalizedNode;
import de.marhali.easyi18n.model.Translations;
import de.marhali.easyi18n.io.TranslatorIO;
import de.marhali.easyi18n.model.DataSynchronizer;
import de.marhali.easyi18n.model.LegacyKeyedTranslation;
import de.marhali.easyi18n.model.TranslationDelete;
import de.marhali.easyi18n.model.LegacyTranslationUpdate;
import de.marhali.easyi18n.util.IOUtil;
import de.marhali.easyi18n.util.TranslationsUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.function.Consumer;
/**
* Factory service to manage localized messages for multiple projects at once.
* @author marhali
*/
@Deprecated
public class LegacyDataStore {
private static final Map<Project, LegacyDataStore> INSTANCES = new WeakHashMap<>();
private final Project project;
private final List<DataSynchronizer> synchronizer;
private Translations translations;
private String searchQuery;
public static LegacyDataStore getInstance(@NotNull Project project) {
LegacyDataStore store = INSTANCES.get(project);
if(store == null) {
store = new LegacyDataStore(project);
INSTANCES.put(project, store);
}
return store;
}
private LegacyDataStore(@NotNull Project project) {
this.project = project;
this.synchronizer = new ArrayList<>();
this.translations = Translations.empty();
// Load data after first initialization
ApplicationManager.getApplication().invokeLater(this::reloadFromDisk, ModalityState.NON_MODAL);
}
/**
* Registers a new synchronizer which will receive {@link #translations} updates.
* @param synchronizer Synchronizer. See {@link DataSynchronizer}
*/
public void addSynchronizer(DataSynchronizer synchronizer) {
this.synchronizer.add(synchronizer);
}
/**
* Loads all translations from disk and overrides current {@link #translations} state.
*/
public void reloadFromDisk() {
String localesPath = SettingsService.getInstance(project).getState().getLocalesPath();
if(localesPath == null || localesPath.isEmpty()) {
// Propagate empty state
this.translations = Translations.empty();
synchronize(searchQuery, null);
} else {
TranslatorIO io = IOUtil.determineFormat(project, localesPath);
io.read(project, localesPath, (loadedTranslations) -> {
this.translations = loadedTranslations == null ? Translations.empty() : loadedTranslations;
synchronize(searchQuery, null);
});
}
}
/**
* Saves the current translation state to disk. See {@link TranslatorIO#save(Project, Translations, String, Consumer)}
* @param callback Complete callback. Indicates if operation was successful(true) or not
*/
public void saveToDisk(@NotNull Consumer<Boolean> callback) {
String localesPath = SettingsService.getInstance(project).getState().getLocalesPath();
if(localesPath == null || localesPath.isEmpty()) { // Cannot save without valid path
return;
}
TranslatorIO io = IOUtil.determineFormat(project, localesPath);
io.save(project, translations, localesPath, callback);
}
/**
* Propagates provided search string to all synchronizer to display only relevant keys
* @param fullPath Full i18n key (e.g. user.username.title). Can be null to display all keys
*/
public void searchBeyKey(@Nullable String fullPath) {
// Use synchronizer to propagate search instance to all views
synchronize(this.searchQuery = fullPath, null);
}
/**
* Processes the provided update. Updates translation instance and propagates changes. See {@link DataSynchronizer}
* @param update The update to process. For more information see {@link LegacyTranslationUpdate}
*/
public void processUpdate(LegacyTranslationUpdate update) {
if(update.isDeletion() || update.isKeyChange()) { // Delete origin i18n key
String originKey = update.getOrigin().getKey();
List<String> sections = TranslationsUtil.getSections(originKey);
String nodeKey = sections.remove(sections.size() - 1); // Remove last node, which needs to be removed by parent
LocalizedNode node = translations.getNodes();
for(String section : sections) {
if(node == null) { // Might be possible on multi-delete
break;
}
node = node.getChildren(section);
}
if(node != null) { // Only remove if parent exists. Might be already deleted on multi-delete
node.removeChildren(nodeKey);
// Parent is empty now, we need to remove it as well (except root)
if(node.getChildren().isEmpty() && !node.getKey().equals(LocalizedNode.ROOT_KEY)) {
processUpdate(new TranslationDelete(new LegacyKeyedTranslation(
TranslationsUtil.sectionsToFullPath(sections), null)));
}
}
}
String scrollTo = update.isDeletion() ? null : update.getChange().getKey();
if(!update.isDeletion()) { // Recreate with changed val / create
LocalizedNode node = translations.getOrCreateNode(update.getChange().getKey());
node.setValue(update.getChange().getTranslations());
}
// Persist changes and propagate them on success
saveToDisk(success -> {
if(success) {
synchronize(searchQuery, scrollTo);
}
});
}
/**
* @return Current translation state
*/
public @NotNull Translations getTranslations() {
return translations;
}
/**
* Synchronizes current translation's state to all connected subscribers.
* @param searchQuery Optional search by full key filter (ui view)
* @param scrollTo Optional scroll to full key (ui view)
*/
public void synchronize(@Nullable String searchQuery, @Nullable String scrollTo) {
synchronizer.forEach(subscriber -> subscriber.synchronize(this.translations, searchQuery, scrollTo));
}
}

View File

@ -7,8 +7,7 @@ import com.intellij.openapi.wm.ToolWindowFactory;
import com.intellij.ui.content.Content; import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentFactory; import com.intellij.ui.content.ContentFactory;
import de.marhali.easyi18n.service.LegacyDataStore; import de.marhali.easyi18n.InstanceManager;
import de.marhali.easyi18n.service.WindowManager;
import de.marhali.easyi18n.action.*; import de.marhali.easyi18n.action.*;
import de.marhali.easyi18n.tabs.TableView; import de.marhali.easyi18n.tabs.TableView;
import de.marhali.easyi18n.tabs.TreeView; import de.marhali.easyi18n.tabs.TreeView;
@ -48,16 +47,16 @@ public class TranslatorToolWindowFactory implements ToolWindowFactory {
actions.add(new AddAction()); actions.add(new AddAction());
actions.add(new ReloadAction()); actions.add(new ReloadAction());
actions.add(new SettingsAction()); actions.add(new SettingsAction());
actions.add(new SearchAction((searchString) -> LegacyDataStore.getInstance(project).searchBeyKey(searchString))); actions.add(new SearchAction((query) -> InstanceManager.get(project).bus().propagate().onSearchQuery(query)));
toolWindow.setTitleActions(actions); toolWindow.setTitleActions(actions);
// Initialize Window Manager // Initialize Window Manager
WindowManager.getInstance().initialize(toolWindow, treeView, tableView); WindowManager.getInstance().initialize(toolWindow, treeView, tableView);
// Synchronize ui with underlying data // Synchronize ui with underlying data
LegacyDataStore store = LegacyDataStore.getInstance(project); InstanceManager manager = InstanceManager.get(project);
store.addSynchronizer(treeView); manager.bus().addListener(treeView);
store.addSynchronizer(tableView); manager.bus().addListener(tableView);
store.synchronize(null, null); manager.bus().propagate().onUpdateData(manager.store().getData());
} }
} }

View File

@ -4,17 +4,14 @@ import com.intellij.openapi.project.Project;
import com.intellij.ui.components.JBScrollPane; import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.table.JBTable; import com.intellij.ui.table.JBTable;
import de.marhali.easyi18n.service.LegacyDataStore; import de.marhali.easyi18n.InstanceManager;
import de.marhali.easyi18n.model.LocalizedNode; import de.marhali.easyi18n.model.*;
import de.marhali.easyi18n.model.DataSynchronizer;
import de.marhali.easyi18n.model.Translations;
import de.marhali.easyi18n.model.LegacyKeyedTranslation;
import de.marhali.easyi18n.model.TranslationDelete;
import de.marhali.easyi18n.model.table.TableModelTranslator;
import de.marhali.easyi18n.dialog.EditDialog; import de.marhali.easyi18n.dialog.EditDialog;
import de.marhali.easyi18n.listener.DeleteKeyListener; import de.marhali.easyi18n.listener.DeleteKeyListener;
import de.marhali.easyi18n.listener.PopupClickListener; import de.marhali.easyi18n.listener.PopupClickListener;
import de.marhali.easyi18n.model.bus.BusListener;
import de.marhali.easyi18n.renderer.TableRenderer; import de.marhali.easyi18n.renderer.TableRenderer;
import de.marhali.easyi18n.tabs.mapper.TableModelMapper;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -28,7 +25,7 @@ import java.util.ResourceBundle;
* Shows translation state as table. * Shows translation state as table.
* @author marhali * @author marhali
*/ */
public class TableView implements DataSynchronizer { public class TableView implements BusListener {
private final Project project; private final Project project;
@ -54,10 +51,10 @@ public class TableView implements DataSynchronizer {
if(row >= 0) { if(row >= 0) {
String fullPath = String.valueOf(table.getValueAt(row, 0)); String fullPath = String.valueOf(table.getValueAt(row, 0));
LocalizedNode node = LegacyDataStore.getInstance(project).getTranslations().getNode(fullPath); Translation translation = InstanceManager.get(project).store().getData().getTranslation(fullPath);
if(node != null) { if(translation != null) {
new EditDialog(project, new LegacyKeyedTranslation(fullPath, node.getValue())).showAndHandle(); new EditDialog(project, new KeyedTranslation(fullPath, translation)).showAndHandle();
} }
} }
} }
@ -67,24 +64,25 @@ public class TableView implements DataSynchronizer {
for (int selectedRow : table.getSelectedRows()) { for (int selectedRow : table.getSelectedRows()) {
String fullPath = String.valueOf(table.getValueAt(selectedRow, 0)); String fullPath = String.valueOf(table.getValueAt(selectedRow, 0));
LegacyDataStore.getInstance(project).processUpdate( InstanceManager.get(project).processUpdate(
new TranslationDelete(new LegacyKeyedTranslation(fullPath, null))); new TranslationDelete(new KeyedTranslation(fullPath, null))
);
} }
}; };
} }
@Override @Override
public void synchronize(@NotNull Translations translations, public void onUpdateData(@NotNull TranslationData data) {
@Nullable String searchQuery, @Nullable String scrollTo) { table.setModel(new TableModelMapper(data, update ->
InstanceManager.get(project).processUpdate(update)));
}
table.setModel(new TableModelTranslator(translations, searchQuery, update -> @Override
LegacyDataStore.getInstance(project).processUpdate(update))); public void onFocusKey(@Nullable String key) {
if(scrollTo != null) {
int row = -1; int row = -1;
for (int i = 0; i < table.getRowCount(); i++) { for (int i = 0; i < table.getRowCount(); i++) {
if (String.valueOf(table.getValueAt(i, 0)).equals(scrollTo)) { if (String.valueOf(table.getValueAt(i, 0)).equals(key)) {
row = i; row = i;
} }
} }
@ -94,6 +92,10 @@ public class TableView implements DataSynchronizer {
new Rectangle(0, (row * table.getRowHeight()) + table.getHeight(), 0, 0)); new Rectangle(0, (row * table.getRowHeight()) + table.getHeight(), 0, 0));
} }
} }
@Override
public void onSearchQuery(@Nullable String query) {
// TODO: handle search functionality
} }
public JPanel getRootPanel() { public JPanel getRootPanel() {

View File

@ -8,19 +8,20 @@ import com.intellij.openapi.project.Project;
import com.intellij.ui.components.JBScrollPane; import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.treeStructure.Tree; import com.intellij.ui.treeStructure.Tree;
import de.marhali.easyi18n.service.LegacyDataStore; import de.marhali.easyi18n.InstanceManager;
import de.marhali.easyi18n.model.LocalizedNode; import de.marhali.easyi18n.model.KeyedTranslation;
import de.marhali.easyi18n.model.DataSynchronizer; import de.marhali.easyi18n.model.Translation;
import de.marhali.easyi18n.model.Translations; import de.marhali.easyi18n.model.TranslationData;
import de.marhali.easyi18n.model.LegacyKeyedTranslation;
import de.marhali.easyi18n.model.TranslationDelete; import de.marhali.easyi18n.model.TranslationDelete;
import de.marhali.easyi18n.model.tree.TreeModelTranslator; import de.marhali.easyi18n.model.bus.BusListener;
import de.marhali.easyi18n.action.treeview.CollapseTreeViewAction; import de.marhali.easyi18n.action.treeview.CollapseTreeViewAction;
import de.marhali.easyi18n.action.treeview.ExpandTreeViewAction; import de.marhali.easyi18n.action.treeview.ExpandTreeViewAction;
import de.marhali.easyi18n.dialog.EditDialog; import de.marhali.easyi18n.dialog.EditDialog;
import de.marhali.easyi18n.listener.DeleteKeyListener; import de.marhali.easyi18n.listener.DeleteKeyListener;
import de.marhali.easyi18n.listener.PopupClickListener; import de.marhali.easyi18n.listener.PopupClickListener;
import de.marhali.easyi18n.renderer.TreeRenderer; import de.marhali.easyi18n.renderer.TreeRenderer;
import de.marhali.easyi18n.service.SettingsService;
import de.marhali.easyi18n.tabs.mapper.TreeModelMapper;
import de.marhali.easyi18n.util.TreeUtil; import de.marhali.easyi18n.util.TreeUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -36,7 +37,7 @@ import java.util.ResourceBundle;
* Show translation state as tree. * Show translation state as tree.
* @author marhali * @author marhali
*/ */
public class TreeView implements DataSynchronizer { public class TreeView implements BusListener {
private final Project project; private final Project project;
@ -46,6 +47,8 @@ public class TreeView implements DataSynchronizer {
private Tree tree; private Tree tree;
private TreeModelMapper mapper;
public TreeView(Project project) { public TreeView(Project project) {
this.project = project; this.project = project;
@ -77,21 +80,22 @@ public class TreeView implements DataSynchronizer {
} }
@Override @Override
public void synchronize(@NotNull Translations translations, public void onUpdateData(@NotNull TranslationData data) {
@Nullable String searchQuery, @Nullable String scrollTo) { tree.setModel(this.mapper = new TreeModelMapper(data, SettingsService.getInstance(project).getState(), null));
TreeModelTranslator model = new TreeModelTranslator(project, translations, searchQuery);
tree.setModel(model);
if(searchQuery != null && !searchQuery.isEmpty()) {
expandAll().run();
} }
if(scrollTo != null) { @Override
tree.scrollPathToVisible(model.findTreePath(scrollTo)); public void onFocusKey(@Nullable String key) {
if(key != null && mapper != null) {
this.tree.scrollPathToVisible(mapper.findTreePath(key));
} }
} }
@Override
public void onSearchQuery(@Nullable String query) {
// TODO: handle search functionality
}
private void handlePopup(MouseEvent e) { private void handlePopup(MouseEvent e) {
TreePath path = tree.getPathForLocation(e.getX(), e.getY()); TreePath path = tree.getPathForLocation(e.getX(), e.getY());
@ -100,10 +104,10 @@ public class TreeView implements DataSynchronizer {
if(node.getUserObject() instanceof PresentationData) { if(node.getUserObject() instanceof PresentationData) {
String fullPath = TreeUtil.getFullPath(path); String fullPath = TreeUtil.getFullPath(path);
LocalizedNode localizedNode = LegacyDataStore.getInstance(project).getTranslations().getNode(fullPath); Translation translation = InstanceManager.get(project).store().getData().getTranslation(fullPath);
if(localizedNode != null) { if(translation != null) {
new EditDialog(project,new LegacyKeyedTranslation(fullPath, localizedNode.getValue())).showAndHandle(); new EditDialog(project, new KeyedTranslation(fullPath, translation)).showAndHandle();
} }
} }
} }
@ -120,8 +124,9 @@ public class TreeView implements DataSynchronizer {
for (TreePath path : tree.getSelectionPaths()) { for (TreePath path : tree.getSelectionPaths()) {
String fullPath = TreeUtil.getFullPath(path); String fullPath = TreeUtil.getFullPath(path);
LegacyDataStore.getInstance(project).processUpdate( InstanceManager.get(project).processUpdate(
new TranslationDelete(new LegacyKeyedTranslation(fullPath, null))); new TranslationDelete(new KeyedTranslation(fullPath, null))
);
} }
}; };
} }

View File

@ -0,0 +1,112 @@
package de.marhali.easyi18n.tabs.mapper;
import de.marhali.easyi18n.model.*;
import de.marhali.easyi18n.model.bus.BusListener;
import de.marhali.easyi18n.model.bus.SearchQueryListener;
import de.marhali.easyi18n.model.bus.UpdateDataListener;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
/**
* Mapping {@link TranslationData} to {@link TableModel}.
* @author marhali
*/
public class TableModelMapper implements TableModel {
private final @NotNull TranslationData data;
private final @NotNull List<String> locales;
private final @NotNull List<String> fullKeys;
private final @NotNull Consumer<TranslationUpdate> updater;
public TableModelMapper(@NotNull TranslationData data, Consumer<TranslationUpdate> updater) {
this.data = data;
this.locales = new ArrayList<>(data.getLocales());
this.fullKeys = new ArrayList<>(data.getFullKeys());
this.updater = updater;
}
@Override
public int getRowCount() {
return this.fullKeys.size();
}
@Override
public int getColumnCount() {
return this.locales.size() + 1; // Number of locales + 1 (key column)
}
@Nls
@Override
public String getColumnName(int columnIndex) {
if(columnIndex == 0) {
return "<html><b>Key</b></html>";
}
return "<html><b>" + this.locales.get(columnIndex - 1) + "</b></html>";
}
@Override
public Class<?> getColumnClass(int columnIndex) {
return String.class;
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return rowIndex > 0; // Everything should be editable except the headline
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
if(columnIndex == 0) { // Keys
return this.fullKeys.get(rowIndex);
}
String key = this.fullKeys.get(rowIndex);
String locale = this.locales.get(columnIndex - 1);
Translation translation = this.data.getTranslation(key);
return translation == null ? null : translation.get(locale);
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
String key = String.valueOf(this.getValueAt(rowIndex, 0));
Translation translation = this.data.getTranslation(key);
if(translation == null) { // Unknown cell
return;
}
String newKey = columnIndex == 0 ? String.valueOf(aValue) : key;
// Translation content update
if(columnIndex > 0) {
if(aValue == null || ((String) aValue).isEmpty()) {
translation.remove(this.locales.get(columnIndex - 1));
} else {
translation.put(this.locales.get(columnIndex - 1), String.valueOf(aValue));
}
}
TranslationUpdate update = new TranslationUpdate(new KeyedTranslation(key, translation),
new KeyedTranslation(newKey, translation));
this.updater.accept(update);
}
@Override
public void addTableModelListener(TableModelListener l) {}
@Override
public void removeTableModelListener(TableModelListener l) {}
}

View File

@ -0,0 +1,104 @@
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.TranslationData;
import de.marhali.easyi18n.model.TranslationNode;
import de.marhali.easyi18n.util.PathUtil;
import de.marhali.easyi18n.util.UiUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.tree.*;
import java.util.List;
import java.util.Map;
/**
* Mapping {@link TranslationData} to {@link TreeModel}.
* @author marhali
*/
public class TreeModelMapper extends DefaultTreeModel {
private final TranslationData data;
private final SettingsState state;
public TreeModelMapper(TranslationData data, SettingsState state, String searchQuery) {
super(null);
this.data = data;
this.state = state;
DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode();
this.generateNodes(rootNode, this.data.getRootNode());
super.setRoot(rootNode);
}
private void generateNodes(DefaultMutableTreeNode parent, TranslationNode translationNode) {
for(Map.Entry<String, TranslationNode> entry : translationNode.getChildren().entrySet()) {
String key = entry.getKey();
TranslationNode childTranslationNode = entry.getValue();
if(!childTranslationNode.isLeaf()) {
// Nested node - run recursively
DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(key);
this.generateNodes(childNode, childTranslationNode);
parent.add(childNode);
} else {
String previewLocale = this.state.getPreviewLocale();
String sub = "(" + previewLocale + ": " + childTranslationNode.getValue().get(previewLocale) + ")";
String tooltip = UiUtil.generateHtmlTooltip(childTranslationNode.getValue());
PresentationData data = new PresentationData(key, sub, null, null);
data.setTooltip(tooltip);
if(childTranslationNode.getValue().size() != this.data.getLocales().size()) {
data.setForcedTextForeground(JBColor.RED);
}
parent.add(new DefaultMutableTreeNode(data));
}
}
}
public @NotNull TreePath findTreePath(@NotNull String fullPath) {
List<String> sections = new PathUtil(this.state.isNestedKeys()).split(fullPath);
Object[] nodes = new Object[sections.size() + 1];
int pos = 0;
TreeNode currentNode = (TreeNode) this.getRoot();
nodes[pos] = currentNode;
for(String section : sections) {
pos++;
currentNode = this.findNode(currentNode, section);
nodes[pos] = currentNode;
}
return new TreePath(nodes);
}
public @Nullable DefaultMutableTreeNode findNode(@NotNull TreeNode parent, @NotNull String key) {
for(int i = 0; i < parent.getChildCount(); i++) {
TreeNode child = parent.getChildAt(i);
if(child instanceof DefaultMutableTreeNode) {
DefaultMutableTreeNode mutableChild = (DefaultMutableTreeNode) child;
String childKey = mutableChild.getUserObject().toString();
if(mutableChild.getUserObject() instanceof PresentationData) {
childKey = ((PresentationData) mutableChild.getUserObject()).getPresentableText();
}
if(childKey != null && childKey.equals(key)) {
return mutableChild;
}
}
}
throw new NullPointerException("Cannot find node by key: " + key);
}
}

View File

@ -1,72 +0,0 @@
package de.marhali.easyi18n.util;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import de.marhali.easyi18n.io.implementation.*;
import de.marhali.easyi18n.io.TranslatorIO;
import de.marhali.easyi18n.service.SettingsService;
import org.jetbrains.annotations.NotNull;
import java.io.File;
/**
* IO operations utility.
* @author marhali
*/
@Deprecated
public class IOUtil {
/**
* Determines the {@link TranslatorIO} which should be used for the specified directoryPath
* @param project Current intellij project
* @param directoryPath The full path to the parent directory which holds the translation files
* @return IO handler to use for file operations
*/
public static TranslatorIO determineFormat(@NotNull Project project, @NotNull String directoryPath) {
VirtualFile directory = LocalFileSystem.getInstance().findFileByIoFile(new File(directoryPath));
if(directory == null || directory.getChildren() == null) {
throw new IllegalArgumentException("Specified folder is invalid (" + directoryPath + ")");
}
VirtualFile[] children = directory.getChildren();
for(VirtualFile file : children) {
if(file.isDirectory()) { // Modularized locale files
// ATM we only support modularized JSON files
return new ModularizedJsonTranslatorIO();
}
if(!isFileRelevant(project, file)) {
continue;
}
switch(file.getFileType().getDefaultExtension().toLowerCase()) {
case "json":
return new JsonTranslatorIO();
case "properties":
return new PropertiesTranslatorIO();
case "yml":
return new YamlTranslatorIO();
default:
System.err.println("Unsupported i18n locale file format: "
+ file.getFileType().getDefaultExtension());
}
}
throw new IllegalStateException("Could not determine i18n format. At least one locale file must be defined");
}
/**
* Checks if the provided file matches the file pattern specified by configuration
* @param project Current intellij project
* @param file File to check
* @return True if relevant otherwise false
*/
public static boolean isFileRelevant(@NotNull Project project, @NotNull VirtualFile file) {
String pattern = SettingsService.getInstance(project).getState().getFilePattern();
return file.getName().matches(pattern);
}
}

View File

@ -1,97 +0,0 @@
package de.marhali.easyi18n.util;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import de.marhali.easyi18n.model.LocalizedNode;
import de.marhali.easyi18n.util.array.JsonArrayUtil;
import org.apache.commons.lang.StringEscapeUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
/**
* Json tree utilities for writing and reading {@link LocalizedNode}'s
* @author marhali
*/
public class JsonUtil {
/**
* Creates a {@link JsonObject} based from an {@link LocalizedNode}
* @param locale Current locale
* @param parent Parent json. Can be an entire json document
* @param node The node instance
*/
public static void writeTree(String locale, JsonObject parent, LocalizedNode node) {
if(node.isLeaf() && !node.getKey().equals(LocalizedNode.ROOT_KEY)) {
if(node.getValue().get(locale) != null) {
if(JsonArrayUtil.isArray(node.getValue().get(locale))) {
parent.add(node.getKey(), JsonArrayUtil.write(node.getValue().get(locale)));
} else {
String value = StringEscapeUtils.unescapeJava(node.getValue().get(locale));
parent.add(node.getKey(), new JsonPrimitive(value));
}
}
} else {
for(LocalizedNode children : node.getChildren()) {
if(children.isLeaf()) {
writeTree(locale, parent, children);
} else {
JsonObject childrenJson = new JsonObject();
writeTree(locale, childrenJson, children);
if(childrenJson.size() > 0) {
parent.add(children.getKey(), childrenJson);
}
}
}
}
}
/**
* Reads a {@link JsonObject} and writes the tree into the provided {@link LocalizedNode}
* @param locale Current locale
* @param json Json to read
* @param data Node. Can be a root node
*/
public static void readTree(String locale, JsonObject json, LocalizedNode data) {
for(Map.Entry<String, JsonElement> entry : json.entrySet()) {
String key = entry.getKey();
try {
// Try to go one level deeper
JsonObject childObject = entry.getValue().getAsJsonObject();
LocalizedNode childrenNode = data.getChildren(key);
if(childrenNode == null) {
childrenNode = new LocalizedNode(key, new ArrayList<>());
data.addChildren(childrenNode);
}
readTree(locale, childObject, childrenNode);
} catch(IllegalStateException e) { // Reached end for this node
LocalizedNode leafNode = data.getChildren(key);
if(leafNode == null) {
leafNode = new LocalizedNode(key, new HashMap<>());
data.addChildren(leafNode);
}
Map<String, String> messages = leafNode.getValue();
String value = entry.getValue().isJsonArray()
? JsonArrayUtil.read(entry.getValue().getAsJsonArray())
: StringUtil.escapeControls(entry.getValue().getAsString(), true);
messages.put(locale, value);
leafNode.setValue(messages);
}
}
}
}

View File

@ -1,7 +1,5 @@
package de.marhali.easyi18n.util; package de.marhali.easyi18n.util;
import de.marhali.easyi18n.model.LocalizedNode;
import java.util.List; import java.util.List;
import java.util.TreeMap; import java.util.TreeMap;
@ -9,6 +7,7 @@ import java.util.TreeMap;
* Map utilities. * Map utilities.
* @author marhali * @author marhali
*/ */
@Deprecated
public class MapUtil { public class MapUtil {
/** /**

View File

@ -6,6 +6,7 @@ import java.util.*;
* Applies sorting to {@link Properties} files. * Applies sorting to {@link Properties} files.
* @author marhali * @author marhali
*/ */
@Deprecated
public class SortedProperties extends Properties { public class SortedProperties extends Properties {
@Override @Override

View File

@ -1,48 +0,0 @@
package de.marhali.easyi18n.util;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Utility tool to support the translations instance
* @author marhali
*/
@Deprecated // SectionUtil
public class TranslationsUtil {
/**
* Retrieve all sections for the specified path (mostly fullPath)
* @param path The path
* @return Sections. E.g. input user.username.title -> Output: [user, username, title]
*/
public static @NotNull List<String> getSections(@NotNull String path) {
if(!path.contains(".")) {
return new ArrayList<>(Collections.singletonList(path));
}
return new ArrayList<>(Arrays.asList(path.split("\\.")));
}
/**
* Concatenate the given sections to a single string.
* @param sections The sections
* @return Full path. E.g. input [user, username, title] -> Output: user.username.title
*/
public static @NotNull String sectionsToFullPath(@NotNull List<String> sections) {
StringBuilder builder = new StringBuilder();
for (String section : sections) {
if(builder.length() > 0) {
builder.append(".");
}
builder.append(section);
}
return builder.toString();
}
}

View File

@ -1,7 +1,6 @@
package de.marhali.easyi18n.util; package de.marhali.easyi18n.util;
import com.intellij.ide.projectView.PresentationData; import com.intellij.ide.projectView.PresentationData;
import de.marhali.easyi18n.model.LocalizedNode;
import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath; import javax.swing.tree.TreePath;
@ -20,14 +19,13 @@ public class TreeUtil {
public static String getFullPath(TreePath path) { public static String getFullPath(TreePath path) {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
for (Object obj : path.getPath()) { for (Object obj : path.getPath()) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) obj; DefaultMutableTreeNode node = (DefaultMutableTreeNode) obj;
Object value = node.getUserObject(); Object value = node.getUserObject();
String section = value instanceof PresentationData ? String section = value instanceof PresentationData ?
((PresentationData) value).getPresentableText() : String.valueOf(value); ((PresentationData) value).getPresentableText() : String.valueOf(value);
if(section == null || section.equals(LocalizedNode.ROOT_KEY)) { // Skip root node if(section == null) { // Skip empty sections
continue; continue;
} }