diff --git a/README.md b/README.md index 9eff9e0..858b137 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# intellij-i18n +# easy-i18n -![Build](https://github.com/marhali/intellij-i18n/workflows/Build/badge.svg) +![Build](https://github.com/marhali/easy-i18n/workflows/Build/badge.svg) [![Version](https://img.shields.io/jetbrains/plugin/v/PLUGIN_ID.svg)](https://plugins.jetbrains.com/plugin/PLUGIN_ID) [![Downloads](https://img.shields.io/jetbrains/plugin/d/PLUGIN_ID.svg)](https://plugins.jetbrains.com/plugin/PLUGIN_ID) @@ -25,12 +25,12 @@ To keep everything working, do not remove `` sections. - Using IDE built-in plugin system: - Settings/Preferences > Plugins > Marketplace > Search for "intellij-i18n" > + Settings/Preferences > Plugins > Marketplace > Search for "easy-i18n" > Install Plugin - Manually: - Download the [latest release](https://github.com/marhali/intellij-i18n/releases/latest) and install it manually using + Download the [latest release](https://github.com/marhali/easy-i18n/releases/latest) and install it manually using Settings/Preferences > Plugins > ⚙️ > Install plugin from disk... diff --git a/gradle.properties b/gradle.properties index 0bc0dad..a23e919 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,7 +11,7 @@ pluginUntilBuild = 203.* pluginVerifierIdeVersions = 2020.2.4, 2020.3.2, 2021.1 platformType = IC -platformVersion = 2020.2.4 +platformVersion = 2020.3.2 platformDownloadSources = true # Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html # Example: platformPlugins = com.intellij.java, com.jetbrains.php:203.4449.22 diff --git a/src/main/java/de/marhali/easyi18n/SettingsService.java b/src/main/java/de/marhali/easyi18n/SettingsService.java new file mode 100644 index 0000000..d8bd269 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/SettingsService.java @@ -0,0 +1,39 @@ +package de.marhali.easyi18n; + +import com.intellij.openapi.components.PersistentStateComponent; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.components.State; +import com.intellij.openapi.project.Project; + +import de.marhali.easyi18n.data.SettingsState; + +import org.jetbrains.annotations.NotNull; + +/** + * Persistent settings storage at project level. + * @author marhali + */ +@State(name = "EasyI18nSettings") +public class SettingsService implements PersistentStateComponent { + + public static SettingsService getInstance(Project project) { + ServiceManager.getService(project, SettingsService.class).initializeComponent(); + return ServiceManager.getService(project, SettingsService.class); + } + + private SettingsState state; + + public SettingsService() { + this.state = new SettingsState(); + } + + @Override + public @NotNull SettingsState getState() { + return state; + } + + @Override + public void loadState(@NotNull SettingsState state) { + this.state = state; + } +} diff --git a/src/main/java/de/marhali/easyi18n/TranslatorToolWindowFactory.java b/src/main/java/de/marhali/easyi18n/TranslatorToolWindowFactory.java new file mode 100644 index 0000000..b0c8ddb --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/TranslatorToolWindowFactory.java @@ -0,0 +1,60 @@ +package de.marhali.easyi18n; + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.wm.ToolWindow; +import com.intellij.openapi.wm.ToolWindowFactory; +import com.intellij.ui.content.Content; +import com.intellij.ui.content.ContentFactory; + +import de.marhali.easyi18n.data.DataStore; +import de.marhali.easyi18n.ui.action.*; +import de.marhali.easyi18n.ui.panel.TableView; +import de.marhali.easyi18n.ui.panel.TreeView; + +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class TranslatorToolWindowFactory implements ToolWindowFactory { + + @Override + public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) { + ContentFactory contentFactory = ContentFactory.SERVICE.getInstance(); + + // Translations tree view + TreeView treeView = new TreeView(project); + Content treeContent = contentFactory.createContent(treeView.getRootPanel(),"TreeView", false); + toolWindow.getContentManager().addContent(treeContent); + + // Translations table view + TableView tableView = new TableView(project); + Content tableContent = contentFactory.createContent(tableView.getRootPanel(), "TableView", false); + toolWindow.getContentManager().addContent(tableContent); + + // ToolWindow Actions (Can be used for every view) + List actions = new ArrayList<>(); + actions.add(new AddAction()); + actions.add(new ReloadAction()); + actions.add(new SettingsAction()); + actions.add(new SearchAction((searchString) -> DataStore.getInstance(project).searchBeyKey(searchString))); + toolWindow.setTitleActions(actions); + + // Initialize Window Manager + WindowManager.getInstance().initialize(toolWindow, treeView, tableView); + + // Initialize data store and load from disk + DataStore store = DataStore.getInstance(project); + store.addSynchronizer(treeView); + store.addSynchronizer(tableView); + + try { + store.reloadFromDisk(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/de/marhali/easyi18n/WindowManager.java b/src/main/java/de/marhali/easyi18n/WindowManager.java new file mode 100644 index 0000000..c6dfb32 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/WindowManager.java @@ -0,0 +1,39 @@ +package de.marhali.easyi18n; + +import com.intellij.openapi.wm.ToolWindow; + +import de.marhali.easyi18n.ui.panel.TableView; +import de.marhali.easyi18n.ui.panel.TreeView; + +public class WindowManager { + + private static WindowManager INSTANCE; + + private ToolWindow toolWindow; + private TreeView treeView; + private TableView tableView; + + public static WindowManager getInstance() { + return INSTANCE == null ? INSTANCE = new WindowManager() : INSTANCE; + } + + private WindowManager() {} + + public void initialize(ToolWindow toolWindow, TreeView treeView, TableView tableView) { + this.toolWindow = toolWindow; + this.treeView = treeView; + this.tableView = tableView; + } + + public ToolWindow getToolWindow() { + return toolWindow; + } + + public TreeView getTreeView() { + return treeView; + } + + public TableView getTableView() { + return tableView; + } +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/data/DataStore.java b/src/main/java/de/marhali/easyi18n/data/DataStore.java new file mode 100644 index 0000000..482f06e --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/data/DataStore.java @@ -0,0 +1,116 @@ +package de.marhali.easyi18n.data; + +import com.intellij.openapi.project.Project; + +import de.marhali.easyi18n.SettingsService; +import de.marhali.easyi18n.io.translator.TranslatorIO; +import de.marhali.easyi18n.model.DataSynchronizer; +import de.marhali.easyi18n.model.KeyedTranslation; +import de.marhali.easyi18n.model.TranslationDelete; +import de.marhali.easyi18n.model.TranslationUpdate; +import de.marhali.easyi18n.util.IOUtil; +import de.marhali.easyi18n.util.TranslationsUtil; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * Singleton service to manage localized messages. + * @author marhali + */ +public class DataStore { + + private static DataStore INSTANCE; + + private final Project project; + private final List synchronizer; + + private Translations translations; + private String searchQuery; + + public static DataStore getInstance(Project project) { + return INSTANCE == null ? INSTANCE = new DataStore(project) : INSTANCE; + } + + private DataStore(Project project) { + this.project = project; + this.synchronizer = new ArrayList<>(); + } + + public void addSynchronizer(DataSynchronizer synchronizer) { + this.synchronizer.add(synchronizer); + } + + public void reloadFromDisk() throws IOException { + String localesPath = SettingsService.getInstance(project).getState().getLocalesPath(); + + if(localesPath == null || localesPath.isEmpty()) { + translations = new Translations(new ArrayList<>(), + new LocalizedNode(LocalizedNode.ROOT_KEY, new ArrayList<>())); + + } else { + TranslatorIO io = IOUtil.determineFormat(localesPath); + translations = io.read(localesPath); + } + + // Propagate changes + synchronizer.forEach(synchronizer -> synchronizer.synchronize(translations, searchQuery)); + } + + public void saveToDisk() { + String localesPath = SettingsService.getInstance(project).getState().getLocalesPath(); + + if(localesPath == null || localesPath.isEmpty()) { // Cannot save without valid path + return; + } + + TranslatorIO io = IOUtil.determineFormat(localesPath); + io.save(translations); + } + + public void searchBeyKey(String fullPath) { + // Use synchronizer to propagate search instance to all views + synchronizer.forEach(synchronizer -> synchronizer.synchronize(translations, this.searchQuery = fullPath)); + } + + public void processUpdate(TranslationUpdate update) { + if(update.isDeletion() || update.isKeyChange()) { // Delete origin i18n key + String originKey = update.getOrigin().getKey(); + List 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 KeyedTranslation( + TranslationsUtil.sectionsToFullPath(sections), null))); + } + } + } + + if(!update.isDeletion()) { // Recreate with changed val / create + LocalizedNode node = translations.getOrCreateNode(update.getChange().getKey()); + node.setValue(update.getChange().getTranslations()); + } + + // Propagate changes and save them + synchronizer.forEach(synchronizer -> synchronizer.synchronize(translations, searchQuery)); + saveToDisk(); + } + + public Translations getTranslations() { + return translations; + } +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/data/LocalizedNode.java b/src/main/java/de/marhali/easyi18n/data/LocalizedNode.java new file mode 100644 index 0000000..874b05f --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/data/LocalizedNode.java @@ -0,0 +1,77 @@ +package de.marhali.easyi18n.data; + +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 + */ +public class LocalizedNode { + + public static final String ROOT_KEY = "root"; + + @NotNull + private final String key; + + @NotNull + private TreeMap children; + + @NotNull + private Map value; + + public LocalizedNode(@NotNull String key, @NotNull List children) { + this.key = key; + this.children = MapUtil.convertToTreeMap(children); + this.value = new HashMap<>(); + } + + public LocalizedNode(@NotNull String key, @NotNull Map 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 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 getValue() { + return value; + } + + public void setValue(@NotNull Map value) { + this.children.clear(); + this.value = value; + } +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/data/SettingsState.java b/src/main/java/de/marhali/easyi18n/data/SettingsState.java new file mode 100644 index 0000000..f206bbe --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/data/SettingsState.java @@ -0,0 +1,33 @@ +package de.marhali.easyi18n.data; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author marhali + */ +public class SettingsState { + + public static final String DEFAULT_PREVIEW_LOCALE = "en"; + + private String localesPath; + private String previewLocale; + + public SettingsState() {} + + public @Nullable String getLocalesPath() { + return localesPath; + } + + public void setLocalesPath(String localesPath) { + this.localesPath = localesPath; + } + + public @NotNull String getPreviewLocale() { + return previewLocale != null ? previewLocale : DEFAULT_PREVIEW_LOCALE; + } + + public void setPreviewLocale(String previewLocale) { + this.previewLocale = previewLocale; + } +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/data/Translations.java b/src/main/java/de/marhali/easyi18n/data/Translations.java new file mode 100644 index 0000000..f40dee0 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/data/Translations.java @@ -0,0 +1,92 @@ +package de.marhali.easyi18n.data; + +import de.marhali.easyi18n.util.TranslationsUtil; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +public class Translations { + + private List locales; + private LocalizedNode nodes; + + public Translations(List locales, LocalizedNode nodes) { + this.locales = locales; + this.nodes = nodes; + } + + public List getLocales() { + return locales; + } + + public LocalizedNode getNodes() { + return nodes; + } + + public @Nullable LocalizedNode getNode(@NotNull String fullPath) { + List 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 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 List getFullKeys() { + List keys = new ArrayList<>(); + + if(nodes.isLeaf()) { // Root has no children + return keys; + } + + for(LocalizedNode children : nodes.getChildren()) { + keys.addAll(getFullKeys("", children)); + } + + return keys; + } + + public List getFullKeys(String parentFullPath, LocalizedNode localizedNode) { + List 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; + } +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/io/Filer.java b/src/main/java/de/marhali/easyi18n/io/Filer.java new file mode 100644 index 0000000..31c2518 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/io/Filer.java @@ -0,0 +1,31 @@ +package de.marhali.easyi18n.io; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; + +import java.io.File; + +/** + * Singleton service for file io operations. + * @author marhali + */ +public class Filer { + + private static Filer INSTANCE; + + private final Project project; + + public static Filer getInstance(Project project) { + return INSTANCE == null ? INSTANCE = new Filer(project) : INSTANCE; + } + + private Filer(Project project) { + this.project = project; + } + + public VirtualFile getFile() { + VirtualFile vfs = LocalFileSystem.getInstance().findFileByIoFile(new File(project.getBasePath() + "/src/lang/de.json")); + return vfs; + } +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/io/translator/JsonTranslatorIO.java b/src/main/java/de/marhali/easyi18n/io/translator/JsonTranslatorIO.java new file mode 100644 index 0000000..59e970b --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/io/translator/JsonTranslatorIO.java @@ -0,0 +1,76 @@ +package de.marhali.easyi18n.io.translator; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; + +import de.marhali.easyi18n.data.LocalizedNode; +import de.marhali.easyi18n.data.Translations; + +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.*; + +/** + * Implementation for JSON translation files. + * @author marhali + */ +public class JsonTranslatorIO implements TranslatorIO { + + @Override + public Translations read(String directoryPath) throws IOException { + VirtualFile directory = LocalFileSystem.getInstance().findFileByIoFile(new File(directoryPath)); + + if(directory == null || directory.getChildren() == null) { + throw new IllegalArgumentException("Specified folder is invalid (" + directoryPath + ")"); + } + + VirtualFile[] files = directory.getChildren(); + + List locales = new ArrayList<>(); + LocalizedNode nodes = new LocalizedNode(LocalizedNode.ROOT_KEY, new ArrayList<>()); + + for(VirtualFile file : files) { + locales.add(file.getNameWithoutExtension()); + JsonObject tree = JsonParser.parseReader(new InputStreamReader(file.getInputStream())).getAsJsonObject(); + readTree(file.getNameWithoutExtension(), tree, nodes); + } + + return new Translations(locales, nodes); + } + + @Override + public void save(Translations translations) { + System.out.println("TODO: save"); + } + + private void readTree(String locale, JsonObject json, LocalizedNode data) { + for(Map.Entry entry : json.entrySet()) { + String key = entry.getKey(); + + try { + // Try to go one level deeper + JsonObject childObject = entry.getValue().getAsJsonObject(); + + LocalizedNode 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 messages = leafNode.getValue(); + messages.put(locale, entry.getValue().getAsString()); + leafNode.setValue(messages); + } + } + } +} diff --git a/src/main/java/de/marhali/easyi18n/io/translator/TranslatorIO.java b/src/main/java/de/marhali/easyi18n/io/translator/TranslatorIO.java new file mode 100644 index 0000000..1ed8a7f --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/io/translator/TranslatorIO.java @@ -0,0 +1,28 @@ +package de.marhali.easyi18n.io.translator; + +import de.marhali.easyi18n.data.Translations; + +import java.io.IOException; + +/** + * Interface to retrieve and save localized messages. + * Can be implemented by various standards. Such as JSON, Properties-Bundle and so on. + * @author marhali + */ +public interface TranslatorIO { + + /** + * Reads localized messages from the persistence layer. + * @param directoryPath The full path from the parent directory which holds the different locale files. + * @return Translations model + * Example entry: username.title => [DE:Benutzername, EN:Username] + */ + Translations read(String directoryPath) throws IOException; + + /** + * Writes the provided messages to the persistence layer. + * @param translations Translatons model to save + * @see #read(String) More information regards the data map + */ + void save(Translations translations); +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/model/DataSynchronizer.java b/src/main/java/de/marhali/easyi18n/model/DataSynchronizer.java new file mode 100644 index 0000000..aab858d --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/model/DataSynchronizer.java @@ -0,0 +1,20 @@ +package de.marhali.easyi18n.model; + +import de.marhali.easyi18n.data.Translations; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Interface to communicate data changes between data store and ui components. + * @author marhali + */ +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. + */ + void synchronize(@NotNull Translations translations, @Nullable String searchQuery); +} \ 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 new file mode 100644 index 0000000..8e5849b --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/model/KeyedTranslation.java @@ -0,0 +1,42 @@ +package de.marhali.easyi18n.model; + +import java.util.Map; + +/** + * Translated messages for a dedicated key. + * @author marhali + */ +public class KeyedTranslation { + + private String key; + private Map translations; + + public KeyedTranslation(String key, Map translations) { + this.key = key; + this.translations = translations; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public Map getTranslations() { + return translations; + } + + public void setTranslations(Map translations) { + this.translations = translations; + } + + @Override + public String toString() { + return "KeyedTranslation{" + + "key='" + key + '\'' + + ", translations=" + translations + + '}'; + } +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/model/TranslationCreate.java b/src/main/java/de/marhali/easyi18n/model/TranslationCreate.java new file mode 100644 index 0000000..9c955a9 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/model/TranslationCreate.java @@ -0,0 +1,13 @@ +package de.marhali.easyi18n.model; + +import org.jetbrains.annotations.NotNull; + +/** + * Represents update request to create a new translation. + * @author marhali + */ +public class TranslationCreate extends TranslationUpdate { + public TranslationCreate(@NotNull KeyedTranslation translation) { + super(null, translation); + } +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/model/TranslationDelete.java b/src/main/java/de/marhali/easyi18n/model/TranslationDelete.java new file mode 100644 index 0000000..763cb16 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/model/TranslationDelete.java @@ -0,0 +1,13 @@ +package de.marhali.easyi18n.model; + +import org.jetbrains.annotations.NotNull; + +/** + * Represents update request to delete a existing translation. + * @author marhali + */ +public class TranslationDelete extends TranslationUpdate { + public TranslationDelete(@NotNull KeyedTranslation translation) { + super(translation, null); + } +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/model/TranslationUpdate.java b/src/main/java/de/marhali/easyi18n/model/TranslationUpdate.java new file mode 100644 index 0000000..d4923b3 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/model/TranslationUpdate.java @@ -0,0 +1,46 @@ +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 + */ +public class TranslationUpdate { + + private final @Nullable KeyedTranslation origin; + private final @Nullable KeyedTranslation change; + + public TranslationUpdate(@Nullable KeyedTranslation origin, @Nullable KeyedTranslation change) { + this.origin = origin; + this.change = change; + } + + public KeyedTranslation getOrigin() { + return origin; + } + + public KeyedTranslation 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 + + '}'; + } +} diff --git a/src/main/java/de/marhali/easyi18n/model/table/TableModelTranslator.java b/src/main/java/de/marhali/easyi18n/model/table/TableModelTranslator.java new file mode 100644 index 0000000..27265d0 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/model/table/TableModelTranslator.java @@ -0,0 +1,122 @@ +package de.marhali.easyi18n.model.table; + +import de.marhali.easyi18n.data.LocalizedNode; +import de.marhali.easyi18n.model.KeyedTranslation; +import de.marhali.easyi18n.model.TranslationUpdate; +import de.marhali.easyi18n.data.Translations; + +import org.jetbrains.annotations.Nls; + +import javax.swing.event.TableModelListener; +import javax.swing.table.TableModel; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +/** + * Table model to represents localized messages. + * @author marhali + */ +public class TableModelTranslator implements TableModel { + + private final Translations translations; + private final List locales; + private final List fullKeys; + + private final Consumer updater; + + /** + * @param translations Translations instance + * @param searchQuery Search / filter param + * @param updater Consumer which can be called on cell change / update + */ + public TableModelTranslator(Translations translations, String searchQuery, Consumer updater) { + this.translations = translations; + this.locales = translations.getLocales(); + this.updater = updater; + + List fullKeys = translations.getFullKeys(); + + if(searchQuery != null && !searchQuery.isEmpty()) { // Filter keys by searchQuery + fullKeys.removeIf(key -> !key.startsWith(searchQuery)); + } + + this.fullKeys = fullKeys; + } + + @Override + public int getRowCount() { + return fullKeys.size(); + } + + @Override + public int getColumnCount() { + return locales.size() + 1; // Number of locales plus 1 for the Key's column + } + + @Nls + @Override + public String getColumnName(int columnIndex) { + if(columnIndex == 0) { + return "Key"; + } + + return "" + locales.get(columnIndex - 1) + ""; + } + + @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 fullKeys.get(rowIndex); + } + + String key = fullKeys.get(rowIndex); + String locale = locales.get(columnIndex - 1); + LocalizedNode node = translations.getNode(key); + + return node == null ? null : node.getValue().get(locale); + } + + @Override + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + String key = String.valueOf(getValueAt(rowIndex, 0)); + LocalizedNode node = translations.getNode(key); + + if(node == null) { // Unknown cell + return; + } + + String newKey = columnIndex == 0 ? String.valueOf(aValue) : key; + Map messages = node.getValue(); + + // Locale message update + if(columnIndex > 0) { + if(aValue == null || ((String) aValue).isEmpty()) { + messages.remove(locales.get(columnIndex - 1)); + } else { + messages.put(locales.get(columnIndex - 1), String.valueOf(aValue)); + } + } + + TranslationUpdate update = new TranslationUpdate(new KeyedTranslation(key, messages), + new KeyedTranslation(newKey, messages)); + + updater.accept(update); + } + + @Override + public void addTableModelListener(TableModelListener l) {} + + @Override + public void removeTableModelListener(TableModelListener l) {} +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/model/tree/TreeModelTranslator.java b/src/main/java/de/marhali/easyi18n/model/tree/TreeModelTranslator.java new file mode 100644 index 0000000..067408a --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/model/tree/TreeModelTranslator.java @@ -0,0 +1,94 @@ +package de.marhali.easyi18n.model.tree; + +import com.intellij.ide.projectView.PresentationData; +import com.intellij.openapi.project.Project; +import com.intellij.ui.JBColor; + +import de.marhali.easyi18n.SettingsService; +import de.marhali.easyi18n.data.LocalizedNode; +import de.marhali.easyi18n.data.Translations; +import de.marhali.easyi18n.util.TranslationsUtil; +import de.marhali.easyi18n.util.UiUtil; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.tree.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * I18n key tree preparation. + * @author marhali + */ +public class TreeModelTranslator extends DefaultTreeModel { + + private final @NotNull Project project; + private final @NotNull Translations translations; + private final @Nullable String searchQuery; + + + public TreeModelTranslator( + @NotNull Project project, @NotNull Translations translations, @Nullable String searchQuery) { + super(null); + + this.project = project; + this.translations = translations; + this.searchQuery = searchQuery; + + setRoot(generateNodes()); + } + + private DefaultMutableTreeNode generateNodes() { + DefaultMutableTreeNode root = new DefaultMutableTreeNode(LocalizedNode.ROOT_KEY); + + if(translations.getNodes().isLeaf()) { // Empty tree + return root; + } + + List searchSections = searchQuery == null ? + Collections.emptyList() : TranslationsUtil.getSections(searchQuery); + + for(LocalizedNode children : translations.getNodes().getChildren()) { + generateSubNodes(root, children, new ArrayList<>(searchSections)); + } + + return root; + } + + private void generateSubNodes(DefaultMutableTreeNode parent, + LocalizedNode localizedNode, List searchSections) { + + String searchKey = searchSections.isEmpty() ? null : searchSections.remove(0); + + if(searchKey != null && !localizedNode.getKey().startsWith(searchKey)) { // Filter node + return; + } + + if(localizedNode.isLeaf()) { + String previewLocale = SettingsService.getInstance(project).getState().getPreviewLocale(); + + String title = localizedNode.getKey(); + String sub = "(" + previewLocale + ": " + localizedNode.getValue().get(previewLocale) + ")"; + String tooltip = UiUtil.generateHtmlTooltip(localizedNode.getValue()); + + PresentationData data = new PresentationData(title, sub, null, null); + data.setTooltip(tooltip); + + if(localizedNode.getValue().size() != translations.getLocales().size()) { + data.setForcedTextForeground(JBColor.RED); + } + + parent.add(new DefaultMutableTreeNode(data)); + + } else { + DefaultMutableTreeNode sub = new DefaultMutableTreeNode(localizedNode.getKey()); + parent.add(sub); + + for(LocalizedNode children : localizedNode.getChildren()) { + generateSubNodes(sub, children, new ArrayList<>(searchSections)); + } + } + } +} diff --git a/src/main/java/de/marhali/easyi18n/ui/ActionsToolbar.form b/src/main/java/de/marhali/easyi18n/ui/ActionsToolbar.form new file mode 100644 index 0000000..76392c6 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/ui/ActionsToolbar.form @@ -0,0 +1,18 @@ + +
+ + + + + + + + + + + + + + + +
diff --git a/src/main/java/de/marhali/easyi18n/ui/ActionsToolbar.java b/src/main/java/de/marhali/easyi18n/ui/ActionsToolbar.java new file mode 100644 index 0000000..2b77820 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/ui/ActionsToolbar.java @@ -0,0 +1,6 @@ +package de.marhali.easyi18n.ui; + +import javax.swing.*; + +public class ActionsToolbar { +} diff --git a/src/main/java/de/marhali/easyi18n/ui/action/AddAction.java b/src/main/java/de/marhali/easyi18n/ui/action/AddAction.java new file mode 100644 index 0000000..916e20f --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/ui/action/AddAction.java @@ -0,0 +1,53 @@ +package de.marhali.easyi18n.ui.action; + +import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; + +import de.marhali.easyi18n.WindowManager; +import de.marhali.easyi18n.ui.dialog.AddDialog; +import de.marhali.easyi18n.util.TreeUtil; + +import org.jetbrains.annotations.NotNull; + +import javax.swing.tree.TreePath; + +public class AddAction extends AnAction { + + public AddAction() { + super("Add Translation", null, AllIcons.General.Add); + } + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + new AddDialog(e.getProject(), detectPreKey()).showAndHandle(); + } + + private String detectPreKey() { + WindowManager manager = WindowManager.getInstance(); + + if(manager == null) { + return null; + } + + if(manager.getToolWindow().getContentManager().getSelectedContent().getDisplayName().equals("TreeView")) { + + TreePath path = manager.getTreeView().getTree().getSelectionPath(); + + if(path != null) { + return TreeUtil.getFullPath(path) + "."; + } + + } else { // Table View + + int row = manager.getTableView().getTable().getSelectedRow(); + + if(row >= 0) { + String fullPath = String.valueOf(manager.getTableView().getTable().getValueAt(row, 0)); + return fullPath + "."; + } + } + + return null; + } +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/ui/action/CollapseTreeViewAction.java b/src/main/java/de/marhali/easyi18n/ui/action/CollapseTreeViewAction.java new file mode 100644 index 0000000..6ac8f2d --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/ui/action/CollapseTreeViewAction.java @@ -0,0 +1,25 @@ +package de.marhali.easyi18n.ui.action; + +import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import org.jetbrains.annotations.NotNull; + +/** + * Action to collapse all tree nodes with children. + * @author marhali + */ +public class CollapseTreeViewAction extends AnAction { + + private final Runnable collapseRunnable; + + public CollapseTreeViewAction(Runnable collapseRunnable) { + super("Collapse Tree", null, AllIcons.Actions.Collapseall); + this.collapseRunnable = collapseRunnable; + } + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + collapseRunnable.run(); + } +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/ui/action/ExpandTreeViewAction.java b/src/main/java/de/marhali/easyi18n/ui/action/ExpandTreeViewAction.java new file mode 100644 index 0000000..a4f2a03 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/ui/action/ExpandTreeViewAction.java @@ -0,0 +1,25 @@ +package de.marhali.easyi18n.ui.action; + +import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import org.jetbrains.annotations.NotNull; + +/** + * Action to expand the entire tree (open all nodes with children). + * @author marhali + */ +public class ExpandTreeViewAction extends AnAction { + + private final Runnable expandRunnable; + + public ExpandTreeViewAction(Runnable expandRunnable) { + super("Expand Tree", null, AllIcons.Actions.Expandall); + this.expandRunnable = expandRunnable; + } + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + expandRunnable.run(); + } +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/ui/action/ReloadAction.java b/src/main/java/de/marhali/easyi18n/ui/action/ReloadAction.java new file mode 100644 index 0000000..0d0584c --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/ui/action/ReloadAction.java @@ -0,0 +1,27 @@ +package de.marhali.easyi18n.ui.action; + +import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; + +import de.marhali.easyi18n.data.DataStore; + +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; + +public class ReloadAction extends AnAction { + + public ReloadAction() { + super("Reload From Disk", null, AllIcons.Actions.Refresh); + } + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + try { + DataStore.getInstance(e.getProject()).reloadFromDisk(); + } catch (IOException ioException) { + ioException.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/ui/action/SearchAction.java b/src/main/java/de/marhali/easyi18n/ui/action/SearchAction.java new file mode 100644 index 0000000..2bebafd --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/ui/action/SearchAction.java @@ -0,0 +1,62 @@ +package de.marhali.easyi18n.ui.action; + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.Presentation; +import com.intellij.openapi.actionSystem.ex.CustomComponentAction; +import com.intellij.ui.components.JBTextField; +import com.intellij.util.ui.JBUI; + +import org.jdesktop.swingx.prompt.PromptSupport; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.util.function.Consumer; + +public class SearchAction extends AnAction implements CustomComponentAction { + + private final Consumer searchCallback; + private JBTextField textField; + + public SearchAction(@NotNull Consumer searchCallback) { + super("Search"); + this.searchCallback = searchCallback; + } + + @Override + public void actionPerformed(@NotNull AnActionEvent e) {} // Should never be called + + public void actionPerformed() { + searchCallback.accept(textField == null ? "" : textField.getText()); + } + + @Override + public @NotNull JComponent createCustomComponent(@NotNull Presentation presentation, @NotNull String place) { + textField = new JBTextField(); + textField.setPreferredSize(new Dimension(160, 25)); + PromptSupport.setPrompt("Search Key...", textField); + + textField.addKeyListener(handleKeyListener()); + textField.setBorder(JBUI.Borders.empty()); + + JPanel panel = new JPanel(new BorderLayout()); + panel.add(textField, BorderLayout.CENTER); + + return panel; + } + + private KeyAdapter handleKeyListener() { + return new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if(e.getKeyCode() == KeyEvent.VK_ENTER) { + e.consume(); + actionPerformed(); + } + } + }; + } +} diff --git a/src/main/java/de/marhali/easyi18n/ui/action/SettingsAction.java b/src/main/java/de/marhali/easyi18n/ui/action/SettingsAction.java new file mode 100644 index 0000000..65ecd00 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/ui/action/SettingsAction.java @@ -0,0 +1,19 @@ +package de.marhali.easyi18n.ui.action; + +import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import de.marhali.easyi18n.ui.dialog.SettingsDialog; +import org.jetbrains.annotations.NotNull; + +public class SettingsAction extends AnAction { + + public SettingsAction() { + super("Settings", null, AllIcons.General.Settings); + } + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + new SettingsDialog(e.getProject()).showAndHandle(); + } +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/ui/dialog/AddDialog.java b/src/main/java/de/marhali/easyi18n/ui/dialog/AddDialog.java new file mode 100644 index 0000000..b70defc --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/ui/dialog/AddDialog.java @@ -0,0 +1,100 @@ +package de.marhali.easyi18n.ui.dialog; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogBuilder; +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.data.DataStore; +import de.marhali.easyi18n.model.KeyedTranslation; +import de.marhali.easyi18n.model.TranslationCreate; + +import javax.swing.*; +import javax.swing.border.EtchedBorder; +import java.awt.*; +import java.util.HashMap; +import java.util.Map; + +/** + * + * @author marhali + */ +public class AddDialog { + + private final Project project; + private String preKey; + + private JBTextField keyTextField; + private Map valueTextFields; + + public AddDialog(Project project, String preKey) { + this(project); + this.preKey = preKey; + } + + public AddDialog(Project project) { + this.project = project; + } + + public void showAndHandle() { + int code = prepare().show(); + + if(code == DialogWrapper.OK_EXIT_CODE) { + saveTranslation(); + } + } + + private void saveTranslation() { + Map messages = new HashMap<>(); + + valueTextFields.forEach((k, v) -> { + if(!v.getText().isEmpty()) { + messages.put(k, v.getText()); + } + }); + + TranslationCreate creation = new TranslationCreate(new KeyedTranslation(keyTextField.getText(), messages)); + DataStore.getInstance(project).processUpdate(creation); + } + + private DialogBuilder prepare() { + JPanel rootPanel = new JPanel(); + rootPanel.setLayout(new BoxLayout(rootPanel, BoxLayout.PAGE_AXIS)); + + JPanel keyPanel = new JPanel(new GridLayout(0, 1, 2, 2)); + JBLabel keyLabel = new JBLabel("Key"); + keyTextField = new JBTextField(this.preKey); + keyLabel.setLabelFor(keyTextField); + keyPanel.add(keyLabel); + keyPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0)); + keyPanel.add(keyTextField); + rootPanel.add(keyPanel); + + JPanel valuePanel = new JPanel(new GridLayout(0, 1, 2, 2)); + valueTextFields = new HashMap<>(); + for(String locale : DataStore.getInstance(project).getTranslations().getLocales()) { + JBLabel localeLabel = new JBLabel(locale); + JBTextField localeText = new JBTextField(); + localeLabel.setLabelFor(localeText); + + valuePanel.add(localeLabel); + valuePanel.add(localeText); + valueTextFields.put(locale, localeText); + } + + JBScrollPane valuePane = new JBScrollPane(valuePanel); + valuePane.setBorder(BorderFactory.createTitledBorder(new EtchedBorder(), "Locales")); + rootPanel.add(valuePane); + + DialogBuilder builder = new DialogBuilder(); + builder.setTitle("Add Translation"); + builder.removeAllActions(); + builder.addOkAction(); + builder.addCancelAction(); + builder.setCenterPanel(rootPanel); + + return builder; + } +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/ui/dialog/EditDialog.java b/src/main/java/de/marhali/easyi18n/ui/dialog/EditDialog.java new file mode 100644 index 0000000..ee7c418 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/ui/dialog/EditDialog.java @@ -0,0 +1,96 @@ +package de.marhali.easyi18n.ui.dialog; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogBuilder; +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.data.DataStore; +import de.marhali.easyi18n.model.KeyedTranslation; +import de.marhali.easyi18n.model.TranslationDelete; +import de.marhali.easyi18n.model.TranslationUpdate; +import de.marhali.easyi18n.ui.dialog.descriptor.DeleteActionDescriptor; + +import javax.swing.*; +import javax.swing.border.EtchedBorder; +import java.awt.*; +import java.util.HashMap; +import java.util.Map; + +public class EditDialog { + + private final Project project; + private final KeyedTranslation origin; + + private JBTextField keyTextField; + private Map valueTextFields; + + public EditDialog(Project project, KeyedTranslation origin) { + this.project = project; + this.origin = origin; + } + + public void showAndHandle() { + int code = prepare().show(); + + if(code == DialogWrapper.OK_EXIT_CODE) { // Edit + DataStore.getInstance(project).processUpdate(new TranslationUpdate(origin, getChanges())); + + } else if(code == DeleteActionDescriptor.EXIT_CODE) { // Delete + DataStore.getInstance(project).processUpdate(new TranslationDelete(origin)); + } + } + + private KeyedTranslation getChanges() { + Map messages = new HashMap<>(); + + valueTextFields.forEach((k, v) -> { + if(!v.getText().isEmpty()) { + messages.put(k, v.getText()); + } + }); + + return new KeyedTranslation(keyTextField.getText(), messages); + } + + private DialogBuilder prepare() { + JPanel rootPanel = new JPanel(); + rootPanel.setLayout(new BoxLayout(rootPanel, BoxLayout.PAGE_AXIS)); + + JPanel keyPanel = new JPanel(new GridLayout(0, 1, 2,2)); + JBLabel keyLabel = new JBLabel("Key"); + keyTextField = new JBTextField(this.origin.getKey()); + keyLabel.setLabelFor(keyTextField); + keyPanel.add(keyLabel); + keyPanel.add(keyTextField); + keyPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0)); + rootPanel.add(keyPanel); + + JPanel valuePanel = new JPanel(new GridLayout(0, 1, 2, 2)); + valueTextFields = new HashMap<>(); + for(String locale : DataStore.getInstance(project).getTranslations().getLocales()) { + JBLabel localeLabel = new JBLabel(locale); + JBTextField localeText = new JBTextField(this.origin.getTranslations().get(locale)); + localeLabel.setLabelFor(localeText); + + valuePanel.add(localeLabel); + valuePanel.add(localeText); + valueTextFields.put(locale, localeText); + } + + JBScrollPane valuePane = new JBScrollPane(valuePanel); + valuePane.setBorder(BorderFactory.createTitledBorder(new EtchedBorder(), "Locales")); + rootPanel.add(valuePane); + + DialogBuilder builder = new DialogBuilder(); + builder.setTitle("Edit Translation"); + builder.removeAllActions(); + builder.addCancelAction(); + builder.addActionDescriptor(new DeleteActionDescriptor()); + builder.addOkAction(); + builder.setCenterPanel(rootPanel); + + return builder; + } +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/ui/dialog/SettingsDialog.java b/src/main/java/de/marhali/easyi18n/ui/dialog/SettingsDialog.java new file mode 100644 index 0000000..5bcc2c8 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/ui/dialog/SettingsDialog.java @@ -0,0 +1,79 @@ +package de.marhali.easyi18n.ui.dialog; + +import com.intellij.openapi.fileChooser.FileChooserDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogBuilder; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.ui.TextFieldWithBrowseButton; +import com.intellij.ui.components.JBLabel; +import com.intellij.ui.components.JBTextField; + +import de.marhali.easyi18n.SettingsService; +import de.marhali.easyi18n.data.DataStore; + +import javax.swing.*; +import java.awt.*; +import java.io.IOException; + +/** + * Plugin configuration dialog. + * @author marhali + */ +public class SettingsDialog { + + private final Project project; + + private TextFieldWithBrowseButton pathText; + private JBTextField previewText; + + public SettingsDialog(Project project) { + this.project = project; + } + + public void showAndHandle() { + String localesPath = SettingsService.getInstance(project).getState().getLocalesPath(); + String previewLocale = SettingsService.getInstance(project).getState().getPreviewLocale(); + + if(prepare(localesPath, previewLocale).show() == DialogWrapper.OK_EXIT_CODE) { // Save changes + SettingsService.getInstance(project).getState().setLocalesPath(pathText.getText()); + SettingsService.getInstance(project).getState().setPreviewLocale(previewText.getText()); + + // Reload instance + try { + DataStore.getInstance(project).reloadFromDisk(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + private DialogBuilder prepare(String localesPath, String previewLocale) { + JPanel rootPanel = new JPanel(new GridLayout(0, 1, 2, 2)); + + JBLabel pathLabel = new JBLabel("Locales directory"); + pathText = new TextFieldWithBrowseButton(new JTextField(localesPath)); + + pathLabel.setLabelFor(pathText); + pathText.addBrowseFolderListener("Locales Directory", null, project, new FileChooserDescriptor( + false, true, false, false, false, false)); + + rootPanel.add(pathLabel); + rootPanel.add(pathText); + + JBLabel previewLabel = new JBLabel("Preview locale"); + previewText = new JBTextField(previewLocale); + previewLabel.setLabelFor(previewText); + + rootPanel.add(previewLabel); + rootPanel.add(previewText); + + DialogBuilder builder = new DialogBuilder(); + builder.setTitle("Settings"); + builder.removeAllActions(); + builder.addCancelAction(); + builder.addOkAction(); + builder.setCenterPanel(rootPanel); + + return builder; + } +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/ui/dialog/descriptor/DeleteActionDescriptor.java b/src/main/java/de/marhali/easyi18n/ui/dialog/descriptor/DeleteActionDescriptor.java new file mode 100644 index 0000000..4c991be --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/ui/dialog/descriptor/DeleteActionDescriptor.java @@ -0,0 +1,36 @@ +package de.marhali.easyi18n.ui.dialog.descriptor; + +import com.intellij.openapi.ui.DialogBuilder; +import com.intellij.openapi.ui.DialogWrapper; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +/** + * Delete action which represents the delete button on the edit translation dialog. + * Action can be monitored using the exit code for the opened dialog. See EXIT_CODE. + * @author marhali + */ +public class DeleteActionDescriptor extends AbstractAction implements DialogBuilder.ActionDescriptor { + + public static final int EXIT_CODE = 10; + + private DialogWrapper dialogWrapper; + + public DeleteActionDescriptor() { + super("Delete"); + } + + @Override + public void actionPerformed(ActionEvent e) { + if(dialogWrapper != null) { + dialogWrapper.close(EXIT_CODE, false); + } + } + + @Override + public Action getAction(DialogWrapper dialogWrapper) { + this.dialogWrapper = dialogWrapper; + return this; + } +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/ui/listener/DeleteKeyListener.java b/src/main/java/de/marhali/easyi18n/ui/listener/DeleteKeyListener.java new file mode 100644 index 0000000..283976d --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/ui/listener/DeleteKeyListener.java @@ -0,0 +1,30 @@ +package de.marhali.easyi18n.ui.listener; + +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; + +/** + * Delete (DEL) keystroke listener. + * @author marhali + */ +public class DeleteKeyListener implements KeyListener { + + private final Runnable deleteRunnable; + + public DeleteKeyListener(Runnable deleteRunnable) { + this.deleteRunnable = deleteRunnable; + } + + @Override + public void keyTyped(KeyEvent e) { + if(e.getKeyChar() == KeyEvent.VK_DELETE) { + deleteRunnable.run(); + } + } + + @Override + public void keyPressed(KeyEvent e) {} + + @Override + public void keyReleased(KeyEvent e) {} +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/ui/listener/PopupClickListener.java b/src/main/java/de/marhali/easyi18n/ui/listener/PopupClickListener.java new file mode 100644 index 0000000..4d2845f --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/ui/listener/PopupClickListener.java @@ -0,0 +1,42 @@ +package de.marhali.easyi18n.ui.listener; + +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.util.function.Consumer; + +/** + * Popup click listener for awt {@link MouseListener}. + * Emits consumer defined in constructor on popup open action. + * @author marhali + */ +public class PopupClickListener implements MouseListener { + + private final Consumer callback; + + public PopupClickListener(Consumer callback) { + this.callback = callback; + } + + @Override + public void mouseClicked(MouseEvent e) {} + + @Override + public void mousePressed(MouseEvent e) { + if(e.isPopupTrigger()) { + this.callback.accept(e); + } + } + + @Override + public void mouseReleased(MouseEvent e) { + if(e.isPopupTrigger()) { + this.callback.accept(e); + } + } + + @Override + public void mouseEntered(MouseEvent e) {} + + @Override + public void mouseExited(MouseEvent e) {} +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/ui/panel/TableRenderer.java b/src/main/java/de/marhali/easyi18n/ui/panel/TableRenderer.java new file mode 100644 index 0000000..79a86c5 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/ui/panel/TableRenderer.java @@ -0,0 +1,41 @@ +package de.marhali.easyi18n.ui.panel; + +import com.intellij.ui.JBColor; + +import javax.swing.*; +import javax.swing.table.DefaultTableCellRenderer; +import java.awt.*; + +/** + * Similar to {@link DefaultTableCellRenderer} but will mark the first column red if any column is empty. + * @author marhali + */ +public class TableRenderer extends DefaultTableCellRenderer { + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + + if(column == 0 && missesValues(row, table)) { + component.setForeground(JBColor.RED); + } else { // Reset color + component.setForeground(null); + } + + return component; + } + + private boolean missesValues(int row, JTable table) { + int columns = table.getColumnCount(); + + for(int i = 1; i < columns; i++) { + Object value = table.getValueAt(row, i); + + if(value == null || value.toString().isEmpty()) { + return true; + } + } + + return false; + } +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/ui/panel/TableView.form b/src/main/java/de/marhali/easyi18n/ui/panel/TableView.form new file mode 100644 index 0000000..00b4c80 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/ui/panel/TableView.form @@ -0,0 +1,29 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/main/java/de/marhali/easyi18n/ui/panel/TableView.java b/src/main/java/de/marhali/easyi18n/ui/panel/TableView.java new file mode 100644 index 0000000..640dd9e --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/ui/panel/TableView.java @@ -0,0 +1,80 @@ +package de.marhali.easyi18n.ui.panel; + +import com.intellij.openapi.project.Project; +import com.intellij.ui.components.JBScrollPane; +import com.intellij.ui.table.JBTable; +import de.marhali.easyi18n.data.DataStore; +import de.marhali.easyi18n.data.LocalizedNode; +import de.marhali.easyi18n.model.DataSynchronizer; +import de.marhali.easyi18n.data.Translations; +import de.marhali.easyi18n.model.KeyedTranslation; +import de.marhali.easyi18n.model.TranslationDelete; +import de.marhali.easyi18n.model.table.TableModelTranslator; +import de.marhali.easyi18n.ui.dialog.EditDialog; +import de.marhali.easyi18n.ui.listener.DeleteKeyListener; +import de.marhali.easyi18n.ui.listener.PopupClickListener; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.event.MouseEvent; + +public class TableView implements DataSynchronizer { + + private final Project project; + + private JPanel rootPanel; + private JPanel containerPanel; + + private JBTable table; + + public TableView(Project project) { + this.project = project; + + table = new JBTable(); + table.getEmptyText().setText("Empty"); + table.addMouseListener(new PopupClickListener(this::handlePopup)); + table.addKeyListener(new DeleteKeyListener(handleDeleteKey())); + table.setDefaultRenderer(String.class, new TableRenderer()); + + containerPanel.add(new JBScrollPane(table)); + } + + private void handlePopup(MouseEvent e) { + int row = table.rowAtPoint(e.getPoint()); + + if(row >= 0) { + String fullPath = String.valueOf(table.getValueAt(row, 0)); + LocalizedNode node = DataStore.getInstance(project).getTranslations().getNode(fullPath); + + if(node != null) { + new EditDialog(project, new KeyedTranslation(fullPath, node.getValue())).showAndHandle(); + } + } + } + + private Runnable handleDeleteKey() { + return () -> { + for (int selectedRow : table.getSelectedRows()) { + String fullPath = String.valueOf(table.getValueAt(selectedRow, 0)); + + DataStore.getInstance(project).processUpdate( + new TranslationDelete(new KeyedTranslation(fullPath, null))); + } + }; + } + + @Override + public void synchronize(@NotNull Translations translations, @Nullable String searchQuery) { + table.setModel(new TableModelTranslator(translations, searchQuery, update -> + DataStore.getInstance(project).processUpdate(update))); + } + + public JPanel getRootPanel() { + return rootPanel; + } + + public JBTable getTable() { + return table; + } +} diff --git a/src/main/java/de/marhali/easyi18n/ui/panel/TestPanel.form b/src/main/java/de/marhali/easyi18n/ui/panel/TestPanel.form new file mode 100644 index 0000000..55d85b9 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/ui/panel/TestPanel.form @@ -0,0 +1,130 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/main/java/de/marhali/easyi18n/ui/panel/TestPanel.java b/src/main/java/de/marhali/easyi18n/ui/panel/TestPanel.java new file mode 100644 index 0000000..97d75c8 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/ui/panel/TestPanel.java @@ -0,0 +1,12 @@ +package de.marhali.easyi18n.ui.panel; + +import javax.swing.*; + +public class TestPanel { + private JPanel panel1; + private JTextField textField1; + private JTextField textField2; + private JTextField textField3; + private JTextField textField4; + private JTextField textField5; +} diff --git a/src/main/java/de/marhali/easyi18n/ui/panel/TreeRenderer.java b/src/main/java/de/marhali/easyi18n/ui/panel/TreeRenderer.java new file mode 100644 index 0000000..4b26dd0 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/ui/panel/TreeRenderer.java @@ -0,0 +1,29 @@ +package de.marhali.easyi18n.ui.panel; + +import com.intellij.ide.util.treeView.NodeRenderer; +import com.intellij.navigation.ItemPresentation; +import com.intellij.openapi.util.NlsSafe; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.TreeCellRenderer; +import java.awt.*; + +public class TreeRenderer extends NodeRenderer { + + @Override + public void customizeCellRenderer(@NotNull JTree tree, @NlsSafe Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { + super.customizeCellRenderer(tree, value, selected, expanded, leaf, row, hasFocus); + } + + @Override + protected @Nullable ItemPresentation getPresentation(Object node) { + if(node instanceof ItemPresentation) { + return (ItemPresentation) node; + } else { + return super.getPresentation(node); + } + } +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/ui/panel/TreeView.form b/src/main/java/de/marhali/easyi18n/ui/panel/TreeView.form new file mode 100644 index 0000000..d93a66e --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/ui/panel/TreeView.form @@ -0,0 +1,29 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/main/java/de/marhali/easyi18n/ui/panel/TreeView.java b/src/main/java/de/marhali/easyi18n/ui/panel/TreeView.java new file mode 100644 index 0000000..701d752 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/ui/panel/TreeView.java @@ -0,0 +1,132 @@ +package de.marhali.easyi18n.ui.panel; + +import com.intellij.ide.projectView.PresentationData; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.DefaultActionGroup; +import com.intellij.openapi.project.Project; +import com.intellij.ui.treeStructure.Tree; + +import de.marhali.easyi18n.data.DataStore; +import de.marhali.easyi18n.data.LocalizedNode; +import de.marhali.easyi18n.model.DataSynchronizer; +import de.marhali.easyi18n.data.Translations; +import de.marhali.easyi18n.model.KeyedTranslation; +import de.marhali.easyi18n.model.TranslationDelete; +import de.marhali.easyi18n.model.tree.TreeModelTranslator; +import de.marhali.easyi18n.ui.action.CollapseTreeViewAction; +import de.marhali.easyi18n.ui.action.ExpandTreeViewAction; +import de.marhali.easyi18n.ui.dialog.EditDialog; +import de.marhali.easyi18n.ui.listener.DeleteKeyListener; +import de.marhali.easyi18n.ui.listener.PopupClickListener; +import de.marhali.easyi18n.util.TreeUtil; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreePath; +import java.awt.event.MouseEvent; + +public class TreeView implements DataSynchronizer { + + private final Project project; + + private JPanel rootPanel; + private JPanel toolBarPanel; + private JPanel containerPanel; + + private Tree tree; + + public TreeView(Project project) { + this.project = project; + + tree = new Tree(); + tree.setCellRenderer(new TreeRenderer()); + tree.setRootVisible(false); + tree.getEmptyText().setText("Empty"); + tree.addMouseListener(new PopupClickListener(this::handlePopup)); + tree.addKeyListener(new DeleteKeyListener(handleDeleteKey())); + + containerPanel.add(tree); + placeActions(); + } + + private void placeActions() { + DefaultActionGroup group = new DefaultActionGroup("TranslationsGroup", false); + + ExpandTreeViewAction expand = new ExpandTreeViewAction(expandAll()); + CollapseTreeViewAction collapse = new CollapseTreeViewAction(collapseAll()); + + group.add(collapse); + group.add(expand); + + JComponent actionToolbar = ActionManager.getInstance() + .createActionToolbar("TranslationsActions", group, false).getComponent(); + + toolBarPanel.add(actionToolbar); + } + + @Override + public void synchronize(@NotNull Translations translations, @Nullable String searchQuery) { + tree.setModel(new TreeModelTranslator(project, translations, searchQuery)); + } + + private void handlePopup(MouseEvent e) { + TreePath path = tree.getPathForLocation(e.getX(), e.getY()); + + if(path != null) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent(); + + if(node.getUserObject() instanceof PresentationData) { + String fullPath = TreeUtil.getFullPath(path); + LocalizedNode localizedNode = DataStore.getInstance(project).getTranslations().getNode(fullPath); + + if(localizedNode != null) { + new EditDialog(project,new KeyedTranslation(fullPath, localizedNode.getValue())).showAndHandle(); + } + } + } + } + + private Runnable handleDeleteKey() { + return () -> { + TreePath[] paths = tree.getSelectionPaths(); + + if (paths == null) { + return; + } + + for (TreePath path : tree.getSelectionPaths()) { + String fullPath = TreeUtil.getFullPath(path); + + DataStore.getInstance(project).processUpdate( + new TranslationDelete(new KeyedTranslation(fullPath, null))); + } + }; + } + + private Runnable expandAll() { + return () -> { + for(int i = 0; i < tree.getRowCount(); i++) { + tree.expandRow(i); + } + }; + } + + private Runnable collapseAll() { + return () -> { + for(int i = 0; i < tree.getRowCount(); i++) { + tree.collapseRow(i); + } + }; + } + + public JPanel getRootPanel() { + return rootPanel; + } + + public Tree getTree() { + return tree; + } +} diff --git a/src/main/java/de/marhali/easyi18n/ui/table/CustomTableModel.java b/src/main/java/de/marhali/easyi18n/ui/table/CustomTableModel.java new file mode 100644 index 0000000..2c0a991 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/ui/table/CustomTableModel.java @@ -0,0 +1,65 @@ +package de.marhali.easyi18n.ui.table; + +import org.jetbrains.annotations.Nls; + +import javax.swing.event.TableModelListener; +import javax.swing.table.TableModel; + +public class CustomTableModel implements TableModel { + + + @Override + public int getRowCount() { + return 2; + } + + @Override + public int getColumnCount() { + return 3; + } + + @Nls + @Override + public String getColumnName(int columnIndex) { + switch (columnIndex) { + case 0: + return "key"; + case 1: + return "de"; + case 2: + return "en"; + } + + return null; + } + + @Override + public Class getColumnClass(int columnIndex) { + return String.class; + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return false; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + return columnIndex == 0 ? "key" : "val"; + } + + @Override + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + + } + + @Override + public void addTableModelListener(TableModelListener l) { + + } + + @Override + public void removeTableModelListener(TableModelListener l) { + + } +} diff --git a/src/main/java/de/marhali/easyi18n/util/IOUtil.java b/src/main/java/de/marhali/easyi18n/util/IOUtil.java new file mode 100644 index 0000000..0ad9162 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/util/IOUtil.java @@ -0,0 +1,39 @@ +package de.marhali.easyi18n.util; + +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import de.marhali.easyi18n.io.translator.JsonTranslatorIO; +import de.marhali.easyi18n.io.translator.TranslatorIO; + +import java.io.File; +import java.util.Arrays; +import java.util.Optional; + +public class IOUtil { + + public static TranslatorIO determineFormat(String directoryPath) { + VirtualFile directory = LocalFileSystem.getInstance().findFileByIoFile(new File(directoryPath)); + + if(directory == null || directory.getChildren() == null) { + throw new IllegalArgumentException("Specified folder is invalid (" + directoryPath + ")"); + } + + Optional any = Arrays.stream(directory.getChildren()).findAny(); + + if(!any.isPresent()) { + throw new IllegalStateException("Could not determine format"); + } + + switch (any.get().getFileType().getDefaultExtension().toLowerCase()) { + case "json": + return new JsonTranslatorIO(); + + case "properties": + throw new UnsupportedOperationException(); + + default: + throw new UnsupportedOperationException("Unsupported format: " + + any.get().getFileType().getDefaultExtension()); + } + } +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/util/MapUtil.java b/src/main/java/de/marhali/easyi18n/util/MapUtil.java new file mode 100644 index 0000000..9c89fc8 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/util/MapUtil.java @@ -0,0 +1,23 @@ +package de.marhali.easyi18n.util; + +import de.marhali.easyi18n.data.LocalizedNode; + +import java.util.List; +import java.util.TreeMap; + +/** + * Map utilities. + * @author marhali + */ +public class MapUtil { + + public static TreeMap convertToTreeMap(List list) { + TreeMap map = new TreeMap<>(); + + for(LocalizedNode item : list) { + map.put(item.getKey(), item); + } + + return map; + } +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/util/TranslationsUtil.java b/src/main/java/de/marhali/easyi18n/util/TranslationsUtil.java new file mode 100644 index 0000000..6dcca0b --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/util/TranslationsUtil.java @@ -0,0 +1,33 @@ +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; + +public class TranslationsUtil { + + public static @NotNull List getSections(@NotNull String path) { + if(!path.contains(".")) { + return new ArrayList<>(Collections.singletonList(path)); + } + + return new ArrayList<>(Arrays.asList(path.split("\\."))); + } + + public static @NotNull String sectionsToFullPath(@NotNull List sections) { + StringBuilder builder = new StringBuilder(); + + for (String section : sections) { + if(builder.length() > 0) { + builder.append("."); + } + + builder.append(section); + } + + return builder.toString(); + } +} \ 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 new file mode 100644 index 0000000..d0b35f2 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/util/TreeUtil.java @@ -0,0 +1,35 @@ +package de.marhali.easyi18n.util; + +import com.intellij.ide.projectView.PresentationData; +import de.marhali.easyi18n.data.LocalizedNode; +import de.marhali.easyi18n.model.tree.TreeModelTranslator; + +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreePath; + +public class TreeUtil { + + public static String getFullPath(TreePath path) { + StringBuilder builder = new StringBuilder(); + + + for (Object obj : path.getPath()) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) obj; + Object value = node.getUserObject(); + String section = value instanceof PresentationData ? + ((PresentationData) value).getPresentableText() : String.valueOf(value); + + if(section == null || section.equals(LocalizedNode.ROOT_KEY)) { // Skip root node + continue; + } + + if(builder.length() != 0) { + builder.append("."); + } + + builder.append(section); + } + + return builder.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/util/UiUtil.java b/src/main/java/de/marhali/easyi18n/util/UiUtil.java new file mode 100644 index 0000000..5fdad39 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/util/UiUtil.java @@ -0,0 +1,28 @@ +package de.marhali.easyi18n.util; + +import java.util.Map; + +/** + * User interface utilities. + * @author marhali + */ +public class UiUtil { + + public static String generateHtmlTooltip(Map messages) { + StringBuilder builder = new StringBuilder(); + + builder.append(""); + + for(Map.Entry entry : messages.entrySet()) { + builder.append(""); + builder.append(entry.getKey()).append(":"); + builder.append(" "); + builder.append(entry.getValue()); + builder.append("
"); + } + + builder.append(""); + + return builder.toString(); + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/marhali/intelliji18n/MyBundle.kt b/src/main/kotlin/com/github/marhali/intelliji18n/MyBundle.kt deleted file mode 100644 index d53a1ed..0000000 --- a/src/main/kotlin/com/github/marhali/intelliji18n/MyBundle.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.github.marhali.intelliji18n - -import com.intellij.AbstractBundle -import org.jetbrains.annotations.NonNls -import org.jetbrains.annotations.PropertyKey - -@NonNls -private const val BUNDLE = "messages.MyBundle" - -object MyBundle : AbstractBundle(BUNDLE) { - - @Suppress("SpreadOperator") - @JvmStatic - fun message(@PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any) = - getMessage(key, *params) - - @Suppress("SpreadOperator") - @JvmStatic - fun messagePointer(@PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any) = - getLazyMessage(key, *params) -} diff --git a/src/main/kotlin/com/github/marhali/intelliji18n/listeners/MyProjectManagerListener.kt b/src/main/kotlin/com/github/marhali/intelliji18n/listeners/MyProjectManagerListener.kt deleted file mode 100644 index 1dd57af..0000000 --- a/src/main/kotlin/com/github/marhali/intelliji18n/listeners/MyProjectManagerListener.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.github.marhali.intelliji18n.listeners - -import com.github.marhali.intelliji18n.services.MyProjectService -import com.intellij.openapi.components.service -import com.intellij.openapi.project.Project -import com.intellij.openapi.project.ProjectManagerListener - -internal class MyProjectManagerListener : ProjectManagerListener { - - override fun projectOpened(project: Project) { - project.service() - } -} diff --git a/src/main/kotlin/com/github/marhali/intelliji18n/services/MyApplicationService.kt b/src/main/kotlin/com/github/marhali/intelliji18n/services/MyApplicationService.kt deleted file mode 100644 index f7df029..0000000 --- a/src/main/kotlin/com/github/marhali/intelliji18n/services/MyApplicationService.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.github.marhali.intelliji18n.services - -import com.github.marhali.intelliji18n.MyBundle - -class MyApplicationService { - - init { - println(MyBundle.message("applicationService")) - } -} diff --git a/src/main/kotlin/com/github/marhali/intelliji18n/services/MyProjectService.kt b/src/main/kotlin/com/github/marhali/intelliji18n/services/MyProjectService.kt deleted file mode 100644 index 467a1ae..0000000 --- a/src/main/kotlin/com/github/marhali/intelliji18n/services/MyProjectService.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.github.marhali.intelliji18n.services - -import com.github.marhali.intelliji18n.MyBundle -import com.intellij.openapi.project.Project - -class MyProjectService(project: Project) { - - init { - println(MyBundle.message("projectService", project.name)) - } -} diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index a2ad852..cffda90 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -1,19 +1,14 @@ - com.github.marhali.intelliji18n - intellij-i18n + de.marhali.easyi18n + easy-i18n marhali - com.intellij.modules.platform + com.intellij.modules.lang - - + + - - - -