From 352dc7c47c7511ad95552e9eb9f4eb84e78cead2 Mon Sep 17 00:00:00 2001 From: JPilson Date: Sat, 9 Dec 2023 14:43:40 +0100 Subject: [PATCH 1/7] feat(Add Selection): add LocalizeItAction for localizing selected text This commit introduces a new action, `LocalizeItAction`, into the easyi18n toolset, which allows users to automatically apply localization to a selected string in the text editor. The action is now accessible from the editor's context menu. This provides a more efficient way to localize selected strings compared to manually adding them. --- .../easyi18n/action/LocalizeItAction.java | 43 +++++++++++++++++++ src/main/resources/META-INF/plugin.xml | 7 +++ 2 files changed, 50 insertions(+) create mode 100644 src/main/java/de/marhali/easyi18n/action/LocalizeItAction.java diff --git a/src/main/java/de/marhali/easyi18n/action/LocalizeItAction.java b/src/main/java/de/marhali/easyi18n/action/LocalizeItAction.java new file mode 100644 index 0000000..7591bc6 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/action/LocalizeItAction.java @@ -0,0 +1,43 @@ +package de.marhali.easyi18n.action; + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import de.marhali.easyi18n.dialog.AddDialog; +import de.marhali.easyi18n.model.KeyPath; +import org.jetbrains.annotations.NotNull; + +/** + * The LocalizeItAction class represents an IntelliJ IDEA action that localizes selected text. + * + *

When this action is performed, it retrieves the selected text from the editor, checks if it is not empty, + * and then displays a dialog to add the selected text as a localized string key to the project. + * + *

If the selected text is empty or the project is null, the action does nothing. + * + *

This class extends the AnAction class provided by IntelliJ IDEA. + */ +class LocalizeItAction extends AnAction { + + @Override + public void actionPerformed(@NotNull AnActionEvent anActionEvent) { + DataContext dataContext = anActionEvent.getDataContext(); + Editor editor = CommonDataKeys.EDITOR.getData(dataContext); + if (editor == null) + return; + String text = editor.getSelectionModel().getSelectedText(); + if (text == null || text.isEmpty()) + return; + + Project project = anActionEvent.getProject(); + if (project == null) { + throw new RuntimeException("Project is null!"); + } + + AddDialog dialog = new AddDialog(project, new KeyPath(text), text); + dialog.showAndHandle(); + } +} \ No newline at end of file diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 45f9611..1553229 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -22,6 +22,13 @@ > + + + From 7038e4205579235c3aa8b3587b2530964b5dd3da Mon Sep 17 00:00:00 2001 From: JPilson Date: Sat, 9 Dec 2023 15:01:47 +0100 Subject: [PATCH 2/7] feat(Localize Selected): add LocalizeItAction for localizing selected text This commit introduces a new action, `LocalizeItAction`, into the easyi18n toolset, which allows users to automatically apply localization to a selected string in the text editor. The action is now accessible from the editor's context menu. This provides a more efficient way to localize selected strings compared to manually adding them. --- .../easyi18n/action/LocalizeItAction.java | 43 +++++++++++++++++++ src/main/resources/META-INF/plugin.xml | 7 +++ 2 files changed, 50 insertions(+) create mode 100644 src/main/java/de/marhali/easyi18n/action/LocalizeItAction.java diff --git a/src/main/java/de/marhali/easyi18n/action/LocalizeItAction.java b/src/main/java/de/marhali/easyi18n/action/LocalizeItAction.java new file mode 100644 index 0000000..7591bc6 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/action/LocalizeItAction.java @@ -0,0 +1,43 @@ +package de.marhali.easyi18n.action; + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import de.marhali.easyi18n.dialog.AddDialog; +import de.marhali.easyi18n.model.KeyPath; +import org.jetbrains.annotations.NotNull; + +/** + * The LocalizeItAction class represents an IntelliJ IDEA action that localizes selected text. + * + *

When this action is performed, it retrieves the selected text from the editor, checks if it is not empty, + * and then displays a dialog to add the selected text as a localized string key to the project. + * + *

If the selected text is empty or the project is null, the action does nothing. + * + *

This class extends the AnAction class provided by IntelliJ IDEA. + */ +class LocalizeItAction extends AnAction { + + @Override + public void actionPerformed(@NotNull AnActionEvent anActionEvent) { + DataContext dataContext = anActionEvent.getDataContext(); + Editor editor = CommonDataKeys.EDITOR.getData(dataContext); + if (editor == null) + return; + String text = editor.getSelectionModel().getSelectedText(); + if (text == null || text.isEmpty()) + return; + + Project project = anActionEvent.getProject(); + if (project == null) { + throw new RuntimeException("Project is null!"); + } + + AddDialog dialog = new AddDialog(project, new KeyPath(text), text); + dialog.showAndHandle(); + } +} \ No newline at end of file diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 45f9611..1553229 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -22,6 +22,13 @@ > + + + From a709db810e8cb39048579f1e05f3dbdc5173f556 Mon Sep 17 00:00:00 2001 From: JPilson Date: Sat, 16 Dec 2023 17:50:29 +0100 Subject: [PATCH 3/7] Add i18n flavor template setting A new setting, `flavorTemplate` is introduced to specify how strings are replaced with i18n representation. This includes code modifications for handling this new feature and also updates in the messages.properties file for the associated UI text. The feature is especially useful for customizing how localization strings are generated in different project setups. --- .../easyi18n/settings/ProjectSettings.java | 1 + .../settings/ProjectSettingsComponent.java | 11 ++++++++++- .../settings/ProjectSettingsComponentState.java | 5 +++++ .../easyi18n/settings/ProjectSettingsState.java | 16 ++++++++++++++-- .../settings/presets/ReactI18NextPreset.java | 5 +++++ .../easyi18n/settings/presets/VueI18nPreset.java | 5 +++++ src/main/resources/messages.properties | 2 ++ 7 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/marhali/easyi18n/settings/ProjectSettings.java b/src/main/java/de/marhali/easyi18n/settings/ProjectSettings.java index 5da91a5..019408a 100644 --- a/src/main/java/de/marhali/easyi18n/settings/ProjectSettings.java +++ b/src/main/java/de/marhali/easyi18n/settings/ProjectSettings.java @@ -33,4 +33,5 @@ public interface ProjectSettings { // Experimental Configuration boolean isAlwaysFold(); + String getFlavorTemplate(); } diff --git a/src/main/java/de/marhali/easyi18n/settings/ProjectSettingsComponent.java b/src/main/java/de/marhali/easyi18n/settings/ProjectSettingsComponent.java index 9018437..4f8fbbb 100644 --- a/src/main/java/de/marhali/easyi18n/settings/ProjectSettingsComponent.java +++ b/src/main/java/de/marhali/easyi18n/settings/ProjectSettingsComponent.java @@ -26,6 +26,7 @@ /** * Configuration panel with all possible options for this plugin. + * * @author marhali */ public class ProjectSettingsComponent extends ProjectSettingsComponentState { @@ -64,10 +65,12 @@ public ProjectSettingsComponent(Project project) { .addVerticalGap(24) .addComponent(new TitledSeparator(bundle.getString("settings.experimental.title"))) .addComponent(constructAlwaysFoldField()) + .addLabeledComponent(bundle.getString("settings.experimental.flavor-template"), constructFlavorTemplate(), 1, false) .addComponentFillVertically(new JPanel(), 0) .getPanel(); } + private JComponent constructPresetField() { preset = new ComboBox<>(Preset.values()); preset.setToolTipText(bundle.getString("settings.preset.tooltip")); @@ -219,9 +222,15 @@ private JComponent constructAlwaysFoldField() { return alwaysFold; } + private JComponent constructFlavorTemplate() { + flavorTemplate = new ExtendableTextField(20); + flavorTemplate.setToolTipText(bundle.getString("settings.experimental.flavor-template-tooltip")); + return flavorTemplate; + } + private ItemListener handleParserChange() { return e -> { - if(e.getStateChange() == ItemEvent.SELECTED) { + if (e.getStateChange() == ItemEvent.SELECTED) { // Automatically suggest file pattern option on parser change ParserStrategyType newStrategy = ParserStrategyType.fromIndex(parserStrategy.getSelectedIndex()); filePattern.setText(newStrategy.getExampleFilePattern()); diff --git a/src/main/java/de/marhali/easyi18n/settings/ProjectSettingsComponentState.java b/src/main/java/de/marhali/easyi18n/settings/ProjectSettingsComponentState.java index 863dd44..e3cb792 100644 --- a/src/main/java/de/marhali/easyi18n/settings/ProjectSettingsComponentState.java +++ b/src/main/java/de/marhali/easyi18n/settings/ProjectSettingsComponentState.java @@ -40,6 +40,8 @@ public class ProjectSettingsComponentState { // Experimental configuration protected JCheckBox alwaysFold; + protected JTextField flavorTemplate; + protected ProjectSettingsState getState() { // Every field needs to provide its state ProjectSettingsState state = new ProjectSettingsState(); @@ -63,6 +65,7 @@ protected ProjectSettingsState getState() { state.setAssistance(assistance.isSelected()); state.setAlwaysFold(alwaysFold.isSelected()); + state.setFlavorTemplate(flavorTemplate.getText()); return state; } @@ -88,5 +91,7 @@ protected void setState(ProjectSettings state) { assistance.setSelected(state.isAssistance()); alwaysFold.setSelected(state.isAlwaysFold()); + + flavorTemplate.setText(state.getFlavorTemplate()); } } diff --git a/src/main/java/de/marhali/easyi18n/settings/ProjectSettingsState.java b/src/main/java/de/marhali/easyi18n/settings/ProjectSettingsState.java index a8648a2..10a5947 100644 --- a/src/main/java/de/marhali/easyi18n/settings/ProjectSettingsState.java +++ b/src/main/java/de/marhali/easyi18n/settings/ProjectSettingsState.java @@ -39,6 +39,7 @@ public class ProjectSettingsState implements ProjectSettings { // Experimental configuration @Property private Boolean alwaysFold; + @Property private String flavorTemplate; public ProjectSettingsState() { this(new DefaultPreset()); @@ -65,6 +66,7 @@ public ProjectSettingsState(ProjectSettings defaults) { this.assistance = defaults.isAssistance(); this.alwaysFold = defaults.isAlwaysFold(); + this.flavorTemplate = defaults.getFlavorTemplate(); } @Override @@ -143,6 +145,11 @@ public boolean isAlwaysFold() { return alwaysFold; } + @Override + public String getFlavorTemplate() { + return this.flavorTemplate; + } + public void setLocalesDirectory(String localesDirectory) { this.localesDirectory = localesDirectory; } @@ -202,6 +209,9 @@ public void setAssistance(Boolean assistance) { public void setAlwaysFold(Boolean alwaysFold) { this.alwaysFold = alwaysFold; } + public void setFlavorTemplate(String flavorTemplate){ + this.flavorTemplate = flavorTemplate; + } @Override public boolean equals(Object o) { @@ -222,7 +232,8 @@ public boolean equals(Object o) { && Objects.equals(previewLocale, that.previewLocale) && Objects.equals(nestedKeys, that.nestedKeys) && Objects.equals(assistance, that.assistance) - && Objects.equals(alwaysFold, that.alwaysFold); + && Objects.equals(alwaysFold, that.alwaysFold) + && Objects.equals(flavorTemplate,that.flavorTemplate); } @Override @@ -230,7 +241,7 @@ public int hashCode() { return Objects.hash( localesDirectory, folderStrategy, parserStrategy, filePattern, includeSubDirs, sorting, namespaceDelimiter, sectionDelimiter, contextDelimiter, pluralDelimiter, - defaultNamespace, previewLocale, nestedKeys, assistance, alwaysFold + defaultNamespace, previewLocale, nestedKeys, assistance, alwaysFold,flavorTemplate ); } @@ -252,6 +263,7 @@ public String toString() { ", nestedKeys=" + nestedKeys + ", assistance=" + assistance + ", alwaysFold=" + alwaysFold + + ", flavorTemplate=" + flavorTemplate + '}'; } } diff --git a/src/main/java/de/marhali/easyi18n/settings/presets/ReactI18NextPreset.java b/src/main/java/de/marhali/easyi18n/settings/presets/ReactI18NextPreset.java index ef536d3..26c16b7 100644 --- a/src/main/java/de/marhali/easyi18n/settings/presets/ReactI18NextPreset.java +++ b/src/main/java/de/marhali/easyi18n/settings/presets/ReactI18NextPreset.java @@ -86,4 +86,9 @@ public boolean isAssistance() { public boolean isAlwaysFold() { return false; } + + @Override + public String getFlavorTemplate() { + return "$i18n.t"; + } } diff --git a/src/main/java/de/marhali/easyi18n/settings/presets/VueI18nPreset.java b/src/main/java/de/marhali/easyi18n/settings/presets/VueI18nPreset.java index 55ddfbe..491edf8 100644 --- a/src/main/java/de/marhali/easyi18n/settings/presets/VueI18nPreset.java +++ b/src/main/java/de/marhali/easyi18n/settings/presets/VueI18nPreset.java @@ -85,4 +85,9 @@ public boolean isAssistance() { public boolean isAlwaysFold() { return false; } + + @Override + public String getFlavorTemplate() { + return "$i18n.t"; + } } diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index 69ac416..f9a8831 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -60,6 +60,8 @@ settings.editor.assistance.tooltip=Activates editor support to reference, auto-c settings.experimental.title=Experimental Configuration settings.experimental.always-fold.title=Always fold translation keys settings.experimental.always-fold.tooltip=Forces the editor to always display the value behind a translation key. The value cannot be unfolded when this function is active. +settings.experimental.flavor-template =I18n flavor template +settings.experimental.flavor-template-tooltip = Specify How to replace strings with i18n representation. error.io=An error occurred while processing translation files. \n\ Config: {0} => {1} ({2}) \n\ Path: {3} \n\ From c56812c888cf85be86371394ba5f1d48ded1023e Mon Sep 17 00:00:00 2001 From: JPilson Date: Sat, 16 Dec 2023 17:51:29 +0100 Subject: [PATCH 4/7] Implement selectable text replacement with i18n keys A new feature is introduced to replace the selected text in editor with Internationalization (i18n) keys, improving the coding workflow for developers handling string localization. The i18n keys are generated based on the customized settings or default flavor template. Further, a function to retrieve the key field from the `TranslationDialog` is added and a new utility class `DocumentUtil` for checking document file types has been added. --- .../easyi18n/action/LocalizeItAction.java | 37 +++++++++++++++--- .../de/marhali/easyi18n/dialog/AddDialog.java | 15 ++++++++ .../easyi18n/dialog/TranslationDialog.java | 4 ++ .../settings/presets/DefaultPreset.java | 5 +++ .../marhali/easyi18n/util/DocumentUtil.java | 38 +++++++++++++++++++ 5 files changed, 94 insertions(+), 5 deletions(-) create mode 100644 src/main/java/de/marhali/easyi18n/util/DocumentUtil.java diff --git a/src/main/java/de/marhali/easyi18n/action/LocalizeItAction.java b/src/main/java/de/marhali/easyi18n/action/LocalizeItAction.java index 7591bc6..4d7edc6 100644 --- a/src/main/java/de/marhali/easyi18n/action/LocalizeItAction.java +++ b/src/main/java/de/marhali/easyi18n/action/LocalizeItAction.java @@ -4,10 +4,15 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import de.marhali.easyi18n.dialog.AddDialog; import de.marhali.easyi18n.model.KeyPath; +import de.marhali.easyi18n.settings.ProjectSettingsService; +import de.marhali.easyi18n.util.DocumentUtil; import org.jetbrains.annotations.NotNull; /** @@ -26,18 +31,40 @@ class LocalizeItAction extends AnAction { public void actionPerformed(@NotNull AnActionEvent anActionEvent) { DataContext dataContext = anActionEvent.getDataContext(); Editor editor = CommonDataKeys.EDITOR.getData(dataContext); - if (editor == null) - return; + if (editor == null) return; String text = editor.getSelectionModel().getSelectedText(); - if (text == null || text.isEmpty()) - return; + if (text == null || text.isEmpty()) return; + + + if ((text.startsWith("\"") && text.endsWith("\"")) || (text.startsWith("'") && text.endsWith("'"))) { + text = text.substring(1); + text = text.substring(0, text.length() - 1); + + } Project project = anActionEvent.getProject(); if (project == null) { throw new RuntimeException("Project is null!"); } - AddDialog dialog = new AddDialog(project, new KeyPath(text), text); + AddDialog dialog = new AddDialog(project, new KeyPath(text), text, (key) -> replaceSelectedText(project, editor, key)); dialog.showAndHandle(); + + + } + + private void replaceSelectedText(Project project, @NotNull Editor editor, @NotNull String key) { + int selectionStart = editor.getSelectionModel().getSelectionStart(); + int selectionEnd = editor.getSelectionModel().getSelectionEnd(); + String flavorTemplate = ProjectSettingsService.get(project).getState().getFlavorTemplate(); + DocumentUtil documentUtil = new DocumentUtil(editor.getDocument()); + String replacement = buildReplacement(flavorTemplate, key, documentUtil); + WriteCommandAction.runWriteCommandAction(editor.getProject(), () -> documentUtil.getDocument().replaceString(selectionStart, selectionEnd, replacement)); + } + + private String buildReplacement(String flavorTemplate, String key, DocumentUtil documentUtil) { + if (documentUtil.isVue() || documentUtil.isJsOrTs()) return flavorTemplate + "('" + key + "')"; + + return flavorTemplate + "(\"" + key + "\")"; } } \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/dialog/AddDialog.java b/src/main/java/de/marhali/easyi18n/dialog/AddDialog.java index b561943..349b4ce 100644 --- a/src/main/java/de/marhali/easyi18n/dialog/AddDialog.java +++ b/src/main/java/de/marhali/easyi18n/dialog/AddDialog.java @@ -13,6 +13,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.function.Consumer; + /** * Dialog to create a new translation with all associated locale values. * Supports optional prefill technique for translation key or locale value. @@ -20,6 +22,8 @@ */ public class AddDialog extends TranslationDialog { + private Consumer onCreated; + /** * Constructs a new create dialog with prefilled fields * @param project Opened project @@ -35,6 +39,16 @@ public AddDialog(@NotNull Project project, @Nullable KeyPath prefillKey, @Nullab setTitle(bundle.getString("action.add")); } + public AddDialog(@NotNull Project project, @Nullable KeyPath prefillKey, @Nullable String prefillLocale,Consumer onCreated) { + super(project, new Translation(prefillKey != null ? prefillKey : new KeyPath(), + prefillLocale != null + ? new TranslationValue(ProjectSettingsService.get(project).getState().getPreviewLocale(), prefillLocale) + : null) + ); + + this.onCreated = onCreated; + setTitle(bundle.getString("action.add")); + } /** * Constructs a new create dialog without prefilled fields. @@ -47,6 +61,7 @@ public AddDialog(@NotNull Project project) { @Override protected @Nullable TranslationUpdate handleExit(int exitCode) { if(exitCode == DialogWrapper.OK_EXIT_CODE) { + if(onCreated != null) onCreated.accept(this.getKeyField().getText()); return new TranslationCreate(getState()); } return null; diff --git a/src/main/java/de/marhali/easyi18n/dialog/TranslationDialog.java b/src/main/java/de/marhali/easyi18n/dialog/TranslationDialog.java index 51307cd..dac4102 100644 --- a/src/main/java/de/marhali/easyi18n/dialog/TranslationDialog.java +++ b/src/main/java/de/marhali/easyi18n/dialog/TranslationDialog.java @@ -37,6 +37,10 @@ abstract class TranslationDialog extends DialogWrapper { protected final @NotNull KeyPathConverter converter; protected final @NotNull Translation origin; + public JTextField getKeyField() { + return keyField; + } + protected final JTextField keyField; protected final Map localeValueFields; diff --git a/src/main/java/de/marhali/easyi18n/settings/presets/DefaultPreset.java b/src/main/java/de/marhali/easyi18n/settings/presets/DefaultPreset.java index 0495db1..383a5d3 100644 --- a/src/main/java/de/marhali/easyi18n/settings/presets/DefaultPreset.java +++ b/src/main/java/de/marhali/easyi18n/settings/presets/DefaultPreset.java @@ -86,4 +86,9 @@ public boolean isAssistance() { public boolean isAlwaysFold() { return false; } + + @Override + public String getFlavorTemplate() { + return "$i18n.t"; + } } diff --git a/src/main/java/de/marhali/easyi18n/util/DocumentUtil.java b/src/main/java/de/marhali/easyi18n/util/DocumentUtil.java new file mode 100644 index 0000000..d965536 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/util/DocumentUtil.java @@ -0,0 +1,38 @@ +package de.marhali.easyi18n.util; + +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.vfs.VirtualFile; + + +public class DocumentUtil { + protected Document document; + FileType fileType; + + public Document getDocument() { + return document; + } + + public void setDocument(Document document) { + this.document = document; + FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance(); + VirtualFile virtualFile = fileDocumentManager.getFile(document); + if (virtualFile != null) { + fileType = virtualFile.getFileType(); + } + } + + public DocumentUtil(Document document) { + setDocument(document); + } + + public boolean isJsOrTs() { + return (fileType.getDefaultExtension().contains("js") || fileType.getDescription().contains("ts")); + } + + public boolean isVue() { + return fileType.getDefaultExtension().contains("vue"); + } + +} From 5b420a7bccbca88fa5751131847f2c9fbca3b660 Mon Sep 17 00:00:00 2001 From: JPilson Date: Sat, 16 Dec 2023 17:58:01 +0100 Subject: [PATCH 5/7] Add flavorTemplate for i18n string replacement and refactor LocalizeItAction The `flavorTemplate` has been introduced in `ProjectSettingsState` to allow developers to customize the i18n string replacement format. In addition, the `LocalizeItAction` class has been simplified by refactoring commented details into JavaDocs and adding methods to replace selected text and build replacement strings. A new utility class, `DocumentUtil`, checks the document type during string replacement. --- .../easyi18n/action/LocalizeItAction.java | 27 ++++++++++++------- .../settings/ProjectSettingsState.java | 8 ++++++ 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/main/java/de/marhali/easyi18n/action/LocalizeItAction.java b/src/main/java/de/marhali/easyi18n/action/LocalizeItAction.java index 4d7edc6..5a07875 100644 --- a/src/main/java/de/marhali/easyi18n/action/LocalizeItAction.java +++ b/src/main/java/de/marhali/easyi18n/action/LocalizeItAction.java @@ -4,9 +4,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.WriteCommandAction; -import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import de.marhali.easyi18n.dialog.AddDialog; @@ -16,14 +14,7 @@ import org.jetbrains.annotations.NotNull; /** - * The LocalizeItAction class represents an IntelliJ IDEA action that localizes selected text. - * - *

When this action is performed, it retrieves the selected text from the editor, checks if it is not empty, - * and then displays a dialog to add the selected text as a localized string key to the project. - * - *

If the selected text is empty or the project is null, the action does nothing. - * - *

This class extends the AnAction class provided by IntelliJ IDEA. + * Represents an action to localize text in the editor. */ class LocalizeItAction extends AnAction { @@ -53,6 +44,14 @@ public void actionPerformed(@NotNull AnActionEvent anActionEvent) { } + + /** + * Replaces the selected text in the editor with a new text generated from the provided key. + * + * @param project the project where the editor belongs + * @param editor the editor where the text is selected + * @param key the key used to generate the replacement text + */ private void replaceSelectedText(Project project, @NotNull Editor editor, @NotNull String key) { int selectionStart = editor.getSelectionModel().getSelectionStart(); int selectionEnd = editor.getSelectionModel().getSelectionEnd(); @@ -62,6 +61,14 @@ private void replaceSelectedText(Project project, @NotNull Editor editor, @NotNu WriteCommandAction.runWriteCommandAction(editor.getProject(), () -> documentUtil.getDocument().replaceString(selectionStart, selectionEnd, replacement)); } + /** + * Builds a replacement string based on the provided flavor template, key, and document util. + * + * @param flavorTemplate the flavor template string + * @param key the key used to generate the replacement text + * @param documentUtil the document util object used to determine the document type + * @return the built replacement string + */ private String buildReplacement(String flavorTemplate, String key, DocumentUtil documentUtil) { if (documentUtil.isVue() || documentUtil.isJsOrTs()) return flavorTemplate + "('" + key + "')"; diff --git a/src/main/java/de/marhali/easyi18n/settings/ProjectSettingsState.java b/src/main/java/de/marhali/easyi18n/settings/ProjectSettingsState.java index 10a5947..ada1380 100644 --- a/src/main/java/de/marhali/easyi18n/settings/ProjectSettingsState.java +++ b/src/main/java/de/marhali/easyi18n/settings/ProjectSettingsState.java @@ -39,6 +39,14 @@ public class ProjectSettingsState implements ProjectSettings { // Experimental configuration @Property private Boolean alwaysFold; + + /** + * The `flavorTemplate` specifies the format used for replacing strings with their i18n (internationalization) counterparts. + * For example: + * In many situations, the default representation for i18n follows the `$i18n.t('key')` pattern. However, this can vary depending on + * the specific framework or developers' preferences for handling i18n. The ability to dynamically change this template adds flexibility and customization + * to cater to different i18n handling methods. + */ @Property private String flavorTemplate; public ProjectSettingsState() { From 71e1106423be9802459fea4f08956b53c3907a90 Mon Sep 17 00:00:00 2001 From: marhali Date: Wed, 10 Apr 2024 00:25:31 +0200 Subject: [PATCH 6/7] small refactoring --- CHANGELOG.md | 1 + .../easyi18n/action/LocalizeItAction.java | 20 ++++++++++++------- .../de/marhali/easyi18n/dialog/AddDialog.java | 6 +++++- .../easyi18n/dialog/TranslationDialog.java | 8 ++++---- .../settings/ProjectSettingsComponent.java | 2 -- .../ProjectSettingsComponentState.java | 1 - .../settings/ProjectSettingsState.java | 1 + .../marhali/easyi18n/util/DocumentUtil.java | 12 +++++------ src/main/resources/messages.properties | 2 +- 9 files changed, 30 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea35775..3722ad9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ ### Added - Support for IntelliJ Platform version 2024.1 +- "Localize It" action to extract translations based on current selection. Thanks to @JPilson ### Changed diff --git a/src/main/java/de/marhali/easyi18n/action/LocalizeItAction.java b/src/main/java/de/marhali/easyi18n/action/LocalizeItAction.java index 5a07875..c7d6656 100644 --- a/src/main/java/de/marhali/easyi18n/action/LocalizeItAction.java +++ b/src/main/java/de/marhali/easyi18n/action/LocalizeItAction.java @@ -7,10 +7,12 @@ import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; + import de.marhali.easyi18n.dialog.AddDialog; import de.marhali.easyi18n.model.KeyPath; import de.marhali.easyi18n.settings.ProjectSettingsService; import de.marhali.easyi18n.util.DocumentUtil; + import org.jetbrains.annotations.NotNull; /** @@ -22,29 +24,33 @@ class LocalizeItAction extends AnAction { public void actionPerformed(@NotNull AnActionEvent anActionEvent) { DataContext dataContext = anActionEvent.getDataContext(); Editor editor = CommonDataKeys.EDITOR.getData(dataContext); - if (editor == null) return; - String text = editor.getSelectionModel().getSelectedText(); - if (text == null || text.isEmpty()) return; + if (editor == null) { + return; + } + + String text = editor.getSelectionModel().getSelectedText(); + if (text == null || text.isEmpty()) { + return; + } if ((text.startsWith("\"") && text.endsWith("\"")) || (text.startsWith("'") && text.endsWith("'"))) { text = text.substring(1); text = text.substring(0, text.length() - 1); } + Project project = anActionEvent.getProject(); + if (project == null) { throw new RuntimeException("Project is null!"); } AddDialog dialog = new AddDialog(project, new KeyPath(text), text, (key) -> replaceSelectedText(project, editor, key)); dialog.showAndHandle(); - - } - /** * Replaces the selected text in the editor with a new text generated from the provided key. * @@ -74,4 +80,4 @@ private String buildReplacement(String flavorTemplate, String key, DocumentUtil return flavorTemplate + "(\"" + key + "\")"; } -} \ No newline at end of file +} diff --git a/src/main/java/de/marhali/easyi18n/dialog/AddDialog.java b/src/main/java/de/marhali/easyi18n/dialog/AddDialog.java index 349b4ce..2746003 100644 --- a/src/main/java/de/marhali/easyi18n/dialog/AddDialog.java +++ b/src/main/java/de/marhali/easyi18n/dialog/AddDialog.java @@ -61,9 +61,13 @@ public AddDialog(@NotNull Project project) { @Override protected @Nullable TranslationUpdate handleExit(int exitCode) { if(exitCode == DialogWrapper.OK_EXIT_CODE) { - if(onCreated != null) onCreated.accept(this.getKeyField().getText()); + if(onCreated != null) { + onCreated.accept(this.getKeyField().getText()); + } + return new TranslationCreate(getState()); } + return null; } } diff --git a/src/main/java/de/marhali/easyi18n/dialog/TranslationDialog.java b/src/main/java/de/marhali/easyi18n/dialog/TranslationDialog.java index dac4102..db4a088 100644 --- a/src/main/java/de/marhali/easyi18n/dialog/TranslationDialog.java +++ b/src/main/java/de/marhali/easyi18n/dialog/TranslationDialog.java @@ -37,10 +37,6 @@ abstract class TranslationDialog extends DialogWrapper { protected final @NotNull KeyPathConverter converter; protected final @NotNull Translation origin; - public JTextField getKeyField() { - return keyField; - } - protected final JTextField keyField; protected final Map localeValueFields; @@ -72,6 +68,10 @@ protected TranslationDialog(@NotNull Project project, @NotNull Translation origi } } + public JTextField getKeyField() { + return keyField; + } + /** * Registers a callback that is called on dialog close with the final state. * If the user aborts the dialog no callback is called. diff --git a/src/main/java/de/marhali/easyi18n/settings/ProjectSettingsComponent.java b/src/main/java/de/marhali/easyi18n/settings/ProjectSettingsComponent.java index 4f8fbbb..2ed36e8 100644 --- a/src/main/java/de/marhali/easyi18n/settings/ProjectSettingsComponent.java +++ b/src/main/java/de/marhali/easyi18n/settings/ProjectSettingsComponent.java @@ -26,7 +26,6 @@ /** * Configuration panel with all possible options for this plugin. - * * @author marhali */ public class ProjectSettingsComponent extends ProjectSettingsComponentState { @@ -70,7 +69,6 @@ public ProjectSettingsComponent(Project project) { .getPanel(); } - private JComponent constructPresetField() { preset = new ComboBox<>(Preset.values()); preset.setToolTipText(bundle.getString("settings.preset.tooltip")); diff --git a/src/main/java/de/marhali/easyi18n/settings/ProjectSettingsComponentState.java b/src/main/java/de/marhali/easyi18n/settings/ProjectSettingsComponentState.java index e3cb792..0138a5c 100644 --- a/src/main/java/de/marhali/easyi18n/settings/ProjectSettingsComponentState.java +++ b/src/main/java/de/marhali/easyi18n/settings/ProjectSettingsComponentState.java @@ -91,7 +91,6 @@ protected void setState(ProjectSettings state) { assistance.setSelected(state.isAssistance()); alwaysFold.setSelected(state.isAlwaysFold()); - flavorTemplate.setText(state.getFlavorTemplate()); } } diff --git a/src/main/java/de/marhali/easyi18n/settings/ProjectSettingsState.java b/src/main/java/de/marhali/easyi18n/settings/ProjectSettingsState.java index ada1380..4b9c064 100644 --- a/src/main/java/de/marhali/easyi18n/settings/ProjectSettingsState.java +++ b/src/main/java/de/marhali/easyi18n/settings/ProjectSettingsState.java @@ -217,6 +217,7 @@ public void setAssistance(Boolean assistance) { public void setAlwaysFold(Boolean alwaysFold) { this.alwaysFold = alwaysFold; } + public void setFlavorTemplate(String flavorTemplate){ this.flavorTemplate = flavorTemplate; } diff --git a/src/main/java/de/marhali/easyi18n/util/DocumentUtil.java b/src/main/java/de/marhali/easyi18n/util/DocumentUtil.java index d965536..bc13dac 100644 --- a/src/main/java/de/marhali/easyi18n/util/DocumentUtil.java +++ b/src/main/java/de/marhali/easyi18n/util/DocumentUtil.java @@ -5,10 +5,13 @@ import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.vfs.VirtualFile; - public class DocumentUtil { protected Document document; - FileType fileType; + private FileType fileType; + + public DocumentUtil(Document document) { + setDocument(document); + } public Document getDocument() { return document; @@ -23,10 +26,6 @@ public void setDocument(Document document) { } } - public DocumentUtil(Document document) { - setDocument(document); - } - public boolean isJsOrTs() { return (fileType.getDefaultExtension().contains("js") || fileType.getDescription().contains("ts")); } @@ -34,5 +33,4 @@ public boolean isJsOrTs() { public boolean isVue() { return fileType.getDefaultExtension().contains("vue"); } - } diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index f9a8831..463b1bb 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -61,7 +61,7 @@ settings.experimental.title=Experimental Configuration settings.experimental.always-fold.title=Always fold translation keys settings.experimental.always-fold.tooltip=Forces the editor to always display the value behind a translation key. The value cannot be unfolded when this function is active. settings.experimental.flavor-template =I18n flavor template -settings.experimental.flavor-template-tooltip = Specify How to replace strings with i18n representation. +settings.experimental.flavor-template-tooltip = Specify how to replace strings with i18n representation. error.io=An error occurred while processing translation files. \n\ Config: {0} => {1} ({2}) \n\ Path: {3} \n\ From cc5dbb74d2cd0c728e90883baeb08ea7da562297 Mon Sep 17 00:00:00 2001 From: marhali Date: Wed, 10 Apr 2024 00:35:16 +0200 Subject: [PATCH 7/7] fix tests --- src/test/java/de/marhali/easyi18n/KeyPathConverterTest.java | 5 +++++ .../de/marhali/easyi18n/mapper/PropertiesMapperTest.java | 5 +++++ .../de/marhali/easyi18n/settings/SettingsTestPreset.java | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/src/test/java/de/marhali/easyi18n/KeyPathConverterTest.java b/src/test/java/de/marhali/easyi18n/KeyPathConverterTest.java index 514e41c..b84d2cb 100644 --- a/src/test/java/de/marhali/easyi18n/KeyPathConverterTest.java +++ b/src/test/java/de/marhali/easyi18n/KeyPathConverterTest.java @@ -163,6 +163,11 @@ public boolean isAlwaysFold() { return false; } + @Override + public String getFlavorTemplate() { + return ""; + } + @Override public boolean isIncludeSubDirs() { return false; diff --git a/src/test/java/de/marhali/easyi18n/mapper/PropertiesMapperTest.java b/src/test/java/de/marhali/easyi18n/mapper/PropertiesMapperTest.java index e7bba6a..71bf2e1 100644 --- a/src/test/java/de/marhali/easyi18n/mapper/PropertiesMapperTest.java +++ b/src/test/java/de/marhali/easyi18n/mapper/PropertiesMapperTest.java @@ -236,6 +236,11 @@ public boolean isAlwaysFold() { return false; } + @Override + public String getFlavorTemplate() { + return ""; + } + @Override public boolean isIncludeSubDirs() { return false; diff --git a/src/test/java/de/marhali/easyi18n/settings/SettingsTestPreset.java b/src/test/java/de/marhali/easyi18n/settings/SettingsTestPreset.java index 2415fe3..ab646ec 100644 --- a/src/test/java/de/marhali/easyi18n/settings/SettingsTestPreset.java +++ b/src/test/java/de/marhali/easyi18n/settings/SettingsTestPreset.java @@ -85,4 +85,9 @@ public boolean isAssistance() { public boolean isAlwaysFold() { return false; } + + @Override + public String getFlavorTemplate() { + return ""; + } }