From c56812c888cf85be86371394ba5f1d48ded1023e Mon Sep 17 00:00:00 2001 From: JPilson Date: Sat, 16 Dec 2023 17:51:29 +0100 Subject: [PATCH] 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.AnAction; 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 de.marhali.easyi18n.settings.ProjectSettingsService; 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 @@ import org.jetbrains.annotations.Nullable; */ 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 class AddDialog extends TranslationDialog { 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 class AddDialog extends TranslationDialog { @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 class DefaultPreset implements ProjectSettings { 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"); + } + +}