entry : results.entrySet()) {
+ builder.append(DocumentationMarkup.SECTION_HEADER_START);
+ builder.append(entry.getKey()).append(":");
+ builder.append(DocumentationMarkup.SECTION_SEPARATOR);
+ builder.append("");
+ builder.append("").append(entry.getValue()).append("");
+ }
+
+ builder.append(DocumentationMarkup.SECTIONS_END);
+ }
+
+ return builder.toString();
+ }
+}
diff --git a/src/main/java/de/marhali/easyi18n/assistance/documentation/CommonDocumentationProvider.java b/src/main/java/de/marhali/easyi18n/assistance/documentation/CommonDocumentationProvider.java
new file mode 100644
index 0000000..5ca0df0
--- /dev/null
+++ b/src/main/java/de/marhali/easyi18n/assistance/documentation/CommonDocumentationProvider.java
@@ -0,0 +1,26 @@
+package de.marhali.easyi18n.assistance.documentation;
+
+import com.intellij.psi.PsiElement;
+import de.marhali.easyi18n.assistance.reference.PsiKeyReference;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Language unspecific documentation provider. Every supported language should register an extension to this EP.
+ * @author marhali
+ */
+public class CommonDocumentationProvider extends AbstractDocumentationProvider {
+
+ @Override
+ public @Nullable
+ @Nls String generateDoc(PsiElement element, @Nullable PsiElement originalElement) {
+ if(!(element instanceof PsiKeyReference.TranslationReference)) {
+ return null;
+ }
+
+ PsiKeyReference.TranslationReference keyReference = (PsiKeyReference.TranslationReference) element;
+ String value = keyReference.getName();
+
+ return generateDoc(element.getProject(), value);
+ }
+}
diff --git a/src/main/java/de/marhali/easyi18n/assistance/folding/AbstractFoldingBuilder.java b/src/main/java/de/marhali/easyi18n/assistance/folding/AbstractFoldingBuilder.java
new file mode 100644
index 0000000..691e30f
--- /dev/null
+++ b/src/main/java/de/marhali/easyi18n/assistance/folding/AbstractFoldingBuilder.java
@@ -0,0 +1,104 @@
+package de.marhali.easyi18n.assistance.folding;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.lang.folding.FoldingBuilderEx;
+import com.intellij.lang.folding.FoldingDescriptor;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiElement;
+
+import de.marhali.easyi18n.DataStore;
+import de.marhali.easyi18n.InstanceManager;
+import de.marhali.easyi18n.assistance.OptionalAssistance;
+import de.marhali.easyi18n.model.TranslationData;
+import de.marhali.easyi18n.model.TranslationValue;
+import de.marhali.easyi18n.settings.ProjectSettings;
+import de.marhali.easyi18n.settings.ProjectSettingsService;
+import de.marhali.easyi18n.util.KeyPathConverter;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Language specific translation key folding with representative locale value.
+ * @author marhali
+ */
+abstract class AbstractFoldingBuilder extends FoldingBuilderEx implements OptionalAssistance {
+ /**
+ * Extract all relevant folding regions for the desired root element.
+ * The implementation does not need to verify if the character literal is a valid translation.
+ * @param root Root element
+ * @return found regions
+ */
+ abstract @NotNull List> extractRegions(@NotNull PsiElement root);
+
+ /**
+ * Extract the text from the given node.
+ * @param node Node
+ * @return extracted text or null if not applicable
+ */
+ abstract @Nullable String extractText(@NotNull ASTNode node);
+
+ @Override
+ public FoldingDescriptor @NotNull [] buildFoldRegions(@NotNull PsiElement root, @NotNull Document document, boolean quick) {
+
+ if(quick || !isAssistance(root.getProject())) {
+ return FoldingDescriptor.EMPTY;
+ }
+
+ List descriptors = new ArrayList<>();
+
+ ProjectSettings settings = ProjectSettingsService.get(root.getProject()).getState();
+ TranslationData data = InstanceManager.get(root.getProject()).store().getData();
+ KeyPathConverter converter = new KeyPathConverter(settings);
+
+ for(Pair region : extractRegions(root)) {
+ if(data.getTranslation(converter.fromString(region.first)) == null) {
+ continue;
+ }
+
+ TextRange range = new TextRange(region.second.getTextRange().getStartOffset() + 1,
+ region.second.getTextRange().getEndOffset() - 1);
+
+ // Some language implementations like [Vue Template] does not support FoldingGroup's
+ FoldingDescriptor descriptor = new FoldingDescriptor(region.second.getNode(), range,
+ null, Set.of(), settings.isAlwaysFold());
+
+ descriptors.add(descriptor);
+ }
+
+ return descriptors.toArray(new FoldingDescriptor[0]);
+ }
+
+ @Override
+ public @Nullable String getPlaceholderText(@NotNull ASTNode node) {
+ String text = extractText(node);
+
+ if(text == null) {
+ return null;
+ }
+
+ Project project = node.getPsi().getProject();
+ DataStore store = InstanceManager.get(project).store();
+ KeyPathConverter converter = new KeyPathConverter(project);
+ TranslationValue localeValues = store.getData().getTranslation(converter.fromString(text));
+
+ if(localeValues == null) {
+ return null;
+ }
+
+ String previewLocale = ProjectSettingsService.get(project).getState().getPreviewLocale();
+ return localeValues.get(previewLocale);
+ }
+
+ @Override
+ public boolean isCollapsedByDefault(@NotNull ASTNode node) {
+ return true;
+ }
+}
diff --git a/src/main/java/de/marhali/easyi18n/assistance/folding/JavaFoldingBuilder.java b/src/main/java/de/marhali/easyi18n/assistance/folding/JavaFoldingBuilder.java
new file mode 100644
index 0000000..e4904a5
--- /dev/null
+++ b/src/main/java/de/marhali/easyi18n/assistance/folding/JavaFoldingBuilder.java
@@ -0,0 +1,32 @@
+package de.marhali.easyi18n.assistance.folding;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.util.Pair;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiLiteralExpression;
+import com.intellij.psi.util.PsiTreeUtil;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Java specific translation key folding.
+ * @author marhali
+ */
+public class JavaFoldingBuilder extends AbstractFoldingBuilder {
+ @Override
+ @NotNull List> extractRegions(@NotNull PsiElement root) {
+ return PsiTreeUtil.findChildrenOfType(root, PsiLiteralExpression.class).stream().map(literalExpression ->
+ Pair.pair(String.valueOf(literalExpression.getValue()), (PsiElement) literalExpression))
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ @Nullable String extractText(@NotNull ASTNode node) {
+ PsiLiteralExpression literalExpression = node.getPsi(PsiLiteralExpression.class);
+ return String.valueOf(literalExpression.getValue());
+ }
+}
diff --git a/src/main/java/de/marhali/easyi18n/assistance/folding/JsFoldingBuilder.java b/src/main/java/de/marhali/easyi18n/assistance/folding/JsFoldingBuilder.java
new file mode 100644
index 0000000..e96b53a
--- /dev/null
+++ b/src/main/java/de/marhali/easyi18n/assistance/folding/JsFoldingBuilder.java
@@ -0,0 +1,32 @@
+package de.marhali.easyi18n.assistance.folding;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.lang.javascript.psi.JSLiteralExpression;
+import com.intellij.openapi.util.Pair;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.util.PsiTreeUtil;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * JavaScript specific translation key folding.
+ * @author marhali
+ */
+public class JsFoldingBuilder extends AbstractFoldingBuilder {
+ @Override
+ @NotNull List> extractRegions(@NotNull PsiElement root) {
+ return PsiTreeUtil.findChildrenOfType(root, JSLiteralExpression.class).stream().map(literalExpression ->
+ Pair.pair(literalExpression.getStringValue(), (PsiElement) literalExpression))
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ @Nullable String extractText(@NotNull ASTNode node) {
+ JSLiteralExpression literalExpression = node.getPsi(JSLiteralExpression.class);
+ return literalExpression.getStringValue();
+ }
+}
diff --git a/src/main/java/de/marhali/easyi18n/assistance/folding/KtFoldingBuilder.java b/src/main/java/de/marhali/easyi18n/assistance/folding/KtFoldingBuilder.java
new file mode 100644
index 0000000..bd95f16
--- /dev/null
+++ b/src/main/java/de/marhali/easyi18n/assistance/folding/KtFoldingBuilder.java
@@ -0,0 +1,45 @@
+package de.marhali.easyi18n.assistance.folding;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.util.Pair;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.util.PsiTreeUtil;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.kotlin.psi.KtStringTemplateEntry;
+import org.jetbrains.kotlin.psi.KtStringTemplateExpression;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Kotlin specific translation-key folding.
+ * @author marhali
+ */
+public class KtFoldingBuilder extends AbstractFoldingBuilder {
+ @Override
+ @NotNull List> extractRegions(@NotNull PsiElement root) {
+ List> regions = new ArrayList<>();
+
+ for (KtStringTemplateExpression templateExpression : PsiTreeUtil.findChildrenOfType(root, KtStringTemplateExpression.class)) {
+ for (KtStringTemplateEntry entry : templateExpression.getEntries()) {
+ regions.add(Pair.pair(entry.getText(), templateExpression));
+ break;
+ }
+ }
+
+ return regions;
+ }
+
+ @Override
+ @Nullable String extractText(@NotNull ASTNode node) {
+ KtStringTemplateExpression templateExpression = node.getPsi(KtStringTemplateExpression.class);
+
+ for (KtStringTemplateEntry entry : templateExpression.getEntries()) {
+ return entry.getText();
+ }
+
+ return null;
+ }
+}
diff --git a/src/main/java/de/marhali/easyi18n/assistance/folding/PhpFoldingBuilder.java b/src/main/java/de/marhali/easyi18n/assistance/folding/PhpFoldingBuilder.java
new file mode 100644
index 0000000..f694b3b
--- /dev/null
+++ b/src/main/java/de/marhali/easyi18n/assistance/folding/PhpFoldingBuilder.java
@@ -0,0 +1,31 @@
+package de.marhali.easyi18n.assistance.folding;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.util.Pair;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Php specific translation key folding.
+ * @author marhali
+ */
+public class PhpFoldingBuilder extends AbstractFoldingBuilder {
+ @Override
+ @NotNull List> extractRegions(@NotNull PsiElement root) {
+ return PsiTreeUtil.findChildrenOfType(root, StringLiteralExpression.class).stream().map(literalExpression ->
+ Pair.pair(literalExpression.getContents(), (PsiElement) literalExpression))
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ @Nullable String extractText(@NotNull ASTNode node) {
+ StringLiteralExpression literalExpression = node.getPsi(StringLiteralExpression.class);
+ return literalExpression.getContents();
+ }
+}
diff --git a/src/main/java/de/marhali/easyi18n/assistance/intention/AbstractTranslationIntention.java b/src/main/java/de/marhali/easyi18n/assistance/intention/AbstractTranslationIntention.java
new file mode 100644
index 0000000..99be4c2
--- /dev/null
+++ b/src/main/java/de/marhali/easyi18n/assistance/intention/AbstractTranslationIntention.java
@@ -0,0 +1,138 @@
+package de.marhali.easyi18n.assistance.intention;
+
+import com.intellij.codeInsight.intention.BaseElementAtCaretIntentionAction;
+import com.intellij.codeInspection.util.IntentionFamilyName;
+import com.intellij.codeInspection.util.IntentionName;
+import com.intellij.openapi.command.WriteCommandAction;
+import com.intellij.openapi.editor.Caret;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiElement;
+import com.intellij.util.IncorrectOperationException;
+
+import de.marhali.easyi18n.InstanceManager;
+import de.marhali.easyi18n.assistance.OptionalAssistance;
+import de.marhali.easyi18n.dialog.AddDialog;
+import de.marhali.easyi18n.dialog.EditDialog;
+import de.marhali.easyi18n.model.KeyPath;
+import de.marhali.easyi18n.model.Translation;
+import de.marhali.easyi18n.model.TranslationData;
+import de.marhali.easyi18n.model.TranslationValue;
+import de.marhali.easyi18n.settings.ProjectSettings;
+import de.marhali.easyi18n.settings.ProjectSettingsService;
+import de.marhali.easyi18n.util.KeyPathConverter;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ResourceBundle;
+
+/**
+ * Intention for translation related use-cases.
+ * Can be used to extract (create) translations or to edit existing ones.
+ * @author marhali
+ */
+abstract class AbstractTranslationIntention extends BaseElementAtCaretIntentionAction implements OptionalAssistance {
+
+ protected static final ResourceBundle bundle = ResourceBundle.getBundle("messages");
+
+ private boolean existingTranslation = false;
+
+ @Override
+ public @IntentionName @NotNull String getText() {
+ return existingTranslation
+ ? bundle.getString("action.edit")
+ : bundle.getString("action.extract");
+ }
+
+ @Override
+ public @NotNull @IntentionFamilyName String getFamilyName() {
+ return "EasyI18n";
+ }
+
+ @Override
+ public boolean startInWriteAction() {
+ return false;
+ }
+
+ /**
+ * This is the only method a language-specific translation intention needs to implement.
+ * The implementation needs to verify element type and extract the relevant key literal or value.
+ * @param element Element at caret
+ * @return extract translation key (not verified!) or null if intention is not applicable for this element
+ */
+ protected abstract @Nullable String extractText(@NotNull PsiElement element);
+
+ @NotNull TextRange convertRange(@NotNull TextRange input) {
+ return new TextRange(input.getStartOffset(), input.getEndOffset());
+ }
+
+ @Override
+ public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
+ if(!isAssistance(project)) {
+ return false;
+ }
+
+ String text = extractText(element);
+
+ if(text != null) {
+ KeyPathConverter converter = new KeyPathConverter(project);
+ existingTranslation = InstanceManager.get(project).store().getData()
+ .getTranslation(converter.fromString(text)) != null;
+ }
+
+ return text != null;
+ }
+
+ @Override
+ public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element)
+ throws IncorrectOperationException {
+
+ ProjectSettings settings = ProjectSettingsService.get(project).getState();
+ KeyPathConverter converter = new KeyPathConverter(settings);
+
+ String text = extractText(element);
+
+ if(text == null) {
+ throw new IncorrectOperationException("Cannot extract translation intention at caret");
+ }
+
+ TranslationData data = InstanceManager.get(project).store().getData();
+ KeyPath path = converter.fromString(text);
+ TranslationValue existingTranslation = data.getTranslation(path);
+
+ // Existing translation - edit dialog
+ if(existingTranslation != null) {
+ new EditDialog(project, new Translation(path, existingTranslation)).showAndHandle();
+ return;
+ }
+
+ // Extract translation by key
+ // We assume that a text is a translation-key if it contains section delimiters and does not end with them
+ if(text.contains(settings.getSectionDelimiter()) && !text.endsWith(settings.getSectionDelimiter())) {
+ new AddDialog(project, path, null).showAndHandle();
+ return;
+ }
+
+ // Extract translation by preview locale value
+ AddDialog dialog = new AddDialog(project, new KeyPath(), text);
+
+ dialog.registerCallback(translationUpdate -> { // Replace text at caret with chosen translation key
+ if(editor != null) {
+ Document doc = editor.getDocument();
+ Caret caret = editor.getCaretModel().getPrimaryCaret();
+ TextRange range = convertRange(element.getTextRange());
+
+ WriteCommandAction.runWriteCommandAction(project, () ->
+ doc.replaceString(range.getStartOffset(), range.getEndOffset(),
+ converter.toString(translationUpdate.getChange().getKey())));
+
+ caret.removeSelection();
+ }
+ });
+
+ dialog.showAndHandle();
+ }
+}
diff --git a/src/main/java/de/marhali/easyi18n/assistance/intention/JavaTranslationIntention.java b/src/main/java/de/marhali/easyi18n/assistance/intention/JavaTranslationIntention.java
new file mode 100644
index 0000000..aed1b98
--- /dev/null
+++ b/src/main/java/de/marhali/easyi18n/assistance/intention/JavaTranslationIntention.java
@@ -0,0 +1,27 @@
+package de.marhali.easyi18n.assistance.intention;
+
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.*;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Java specific translation intention.
+ * @author marhali
+ */
+public class JavaTranslationIntention extends AbstractTranslationIntention {
+ @Override
+ protected @Nullable String extractText(@NotNull PsiElement element) {
+ if(!(element.getParent() instanceof PsiLiteralExpression)) {
+ return null;
+ }
+
+ return String.valueOf(((PsiLiteralExpression) element.getParent()).getValue());
+ }
+
+ @Override
+ @NotNull TextRange convertRange(@NotNull TextRange input) {
+ return new TextRange(input.getStartOffset() + 1, input.getEndOffset() - 1);
+ }
+}
diff --git a/src/main/java/de/marhali/easyi18n/assistance/intention/JsTranslationIntention.java b/src/main/java/de/marhali/easyi18n/assistance/intention/JsTranslationIntention.java
new file mode 100644
index 0000000..da526a5
--- /dev/null
+++ b/src/main/java/de/marhali/easyi18n/assistance/intention/JsTranslationIntention.java
@@ -0,0 +1,28 @@
+package de.marhali.easyi18n.assistance.intention;
+
+import com.intellij.lang.javascript.psi.JSLiteralExpression;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiElement;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * JavaScript specific translation key intention.
+ * @author marhali
+ */
+public class JsTranslationIntention extends AbstractTranslationIntention {
+ @Override
+ protected @Nullable String extractText(@NotNull PsiElement element) {
+ if(!(element.getParent() instanceof JSLiteralExpression)) {
+ return null;
+ }
+
+ return ((JSLiteralExpression) element.getParent()).getStringValue();
+ }
+
+ @Override
+ @NotNull TextRange convertRange(@NotNull TextRange input) {
+ return new TextRange(input.getStartOffset() + 1, input.getEndOffset() - 1);
+ }
+}
diff --git a/src/main/java/de/marhali/easyi18n/assistance/intention/KtTranslationIntention.java b/src/main/java/de/marhali/easyi18n/assistance/intention/KtTranslationIntention.java
new file mode 100644
index 0000000..7ed3f31
--- /dev/null
+++ b/src/main/java/de/marhali/easyi18n/assistance/intention/KtTranslationIntention.java
@@ -0,0 +1,23 @@
+package de.marhali.easyi18n.assistance.intention;
+
+import com.intellij.psi.PsiElement;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.kotlin.psi.KtLiteralStringTemplateEntry;
+
+/**
+ * Kotlin specific translation key intention.
+ * @author marhali
+ */
+public class KtTranslationIntention extends AbstractTranslationIntention {
+ @Override
+ protected @Nullable String extractText(@NotNull PsiElement element) {
+ if(!(element.getParent() instanceof KtLiteralStringTemplateEntry)) {
+ return null;
+ }
+
+ KtLiteralStringTemplateEntry expression = (KtLiteralStringTemplateEntry) element.getParent();
+ return expression.getText();
+ }
+}
diff --git a/src/main/java/de/marhali/easyi18n/assistance/intention/PhpTranslationIntention.java b/src/main/java/de/marhali/easyi18n/assistance/intention/PhpTranslationIntention.java
new file mode 100644
index 0000000..76693a3
--- /dev/null
+++ b/src/main/java/de/marhali/easyi18n/assistance/intention/PhpTranslationIntention.java
@@ -0,0 +1,23 @@
+package de.marhali.easyi18n.assistance.intention;
+
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiElement;
+import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Php specific translation intention
+ * @author marhali
+ */
+public class PhpTranslationIntention extends AbstractTranslationIntention {
+ @Override
+ protected @Nullable String extractText(@NotNull PsiElement element) {
+ if(!(element.getParent() instanceof StringLiteralExpression)) {
+ return null;
+ }
+
+ return ((StringLiteralExpression) element.getParent()).getContents();
+ }
+}
diff --git a/src/main/java/de/marhali/easyi18n/assistance/reference/AbstractKeyReferenceContributor.java b/src/main/java/de/marhali/easyi18n/assistance/reference/AbstractKeyReferenceContributor.java
new file mode 100644
index 0000000..b964a4c
--- /dev/null
+++ b/src/main/java/de/marhali/easyi18n/assistance/reference/AbstractKeyReferenceContributor.java
@@ -0,0 +1,53 @@
+package de.marhali.easyi18n.assistance.reference;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.PsiReferenceContributor;
+import de.marhali.easyi18n.InstanceManager;
+import de.marhali.easyi18n.assistance.OptionalAssistance;
+import de.marhali.easyi18n.model.KeyPath;
+import de.marhali.easyi18n.model.Translation;
+import de.marhali.easyi18n.model.TranslationValue;
+import de.marhali.easyi18n.settings.ProjectSettings;
+import de.marhali.easyi18n.settings.ProjectSettingsService;
+import de.marhali.easyi18n.util.KeyPathConverter;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Language specific translation key reference contributor.
+ * @author marhali
+ */
+abstract class AbstractKeyReferenceContributor extends PsiReferenceContributor implements OptionalAssistance {
+ /**
+ * Searches for relevant translation-key references
+ * @param project Opened project
+ * @param element Targeted element
+ * @param text Designated translation key
+ * @return Matched translation-key reference(s)
+ */
+ protected @NotNull PsiReference[] getReferences(
+ @NotNull Project project, @NotNull PsiElement element, @Nullable String text) {
+
+ if(text == null || text.isEmpty() || !isAssistance(project)) {
+ return PsiReference.EMPTY_ARRAY;
+ }
+
+ ProjectSettings settings = ProjectSettingsService.get(project).getState();
+ KeyPathConverter converter = new KeyPathConverter(settings);
+
+ // TODO: We should provide multiple references if not a leaf node was provided (contextual / plurals support)
+
+ KeyPath path = converter.fromString(text);
+ TranslationValue values = InstanceManager.get(project).store().getData().getTranslation(path);
+
+ if(values == null) { // We only reference valid and existing translations
+ return PsiReference.EMPTY_ARRAY;
+ }
+
+ return new PsiReference[] {
+ new PsiKeyReference(converter, new Translation(path, values), element)
+ };
+ }
+}
diff --git a/src/main/java/de/marhali/easyi18n/assistance/reference/JavaKeyReferenceContributor.java b/src/main/java/de/marhali/easyi18n/assistance/reference/JavaKeyReferenceContributor.java
new file mode 100644
index 0000000..7d80e66
--- /dev/null
+++ b/src/main/java/de/marhali/easyi18n/assistance/reference/JavaKeyReferenceContributor.java
@@ -0,0 +1,41 @@
+package de.marhali.easyi18n.assistance.reference;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.patterns.PlatformPatterns;
+import com.intellij.psi.*;
+
+
+import com.intellij.util.ProcessingContext;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Java specific key reference binding.
+ * @author marhali
+ */
+public class JavaKeyReferenceContributor extends AbstractKeyReferenceContributor {
+
+ @Override
+ public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) {
+ registrar.registerReferenceProvider(
+ PlatformPatterns.psiElement(PsiLiteralExpression.class),
+ getProvider());
+ }
+
+ private PsiReferenceProvider getProvider() {
+ return new PsiReferenceProvider() {
+ @Override
+ public PsiReference @NotNull [] getReferencesByElement(
+ @NotNull PsiElement element, @NotNull ProcessingContext context) {
+
+ Project project = element.getProject();
+ PsiLiteralExpression literalExpression = (PsiLiteralExpression) element;
+ String value = literalExpression.getValue() instanceof String
+ ? (String) literalExpression.getValue()
+ : null;
+
+ return getReferences(project, element, value);
+ }
+ };
+ }
+}
diff --git a/src/main/java/de/marhali/easyi18n/assistance/reference/JsKeyReferenceContributor.java b/src/main/java/de/marhali/easyi18n/assistance/reference/JsKeyReferenceContributor.java
new file mode 100644
index 0000000..6edd656
--- /dev/null
+++ b/src/main/java/de/marhali/easyi18n/assistance/reference/JsKeyReferenceContributor.java
@@ -0,0 +1,39 @@
+package de.marhali.easyi18n.assistance.reference;
+
+import com.intellij.lang.javascript.psi.JSLiteralExpression;
+import com.intellij.openapi.project.Project;
+import com.intellij.patterns.PlatformPatterns;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.PsiReferenceProvider;
+import com.intellij.psi.PsiReferenceRegistrar;
+import com.intellij.util.ProcessingContext;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * JavaScript specific translation-key reference binding.
+ * @author marhali
+ */
+public class JsKeyReferenceContributor extends AbstractKeyReferenceContributor {
+ @Override
+ public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) {
+ registrar.registerReferenceProvider(
+ PlatformPatterns.psiElement(JSLiteralExpression.class),
+ getProvider());
+ }
+
+ private PsiReferenceProvider getProvider() {
+ return new PsiReferenceProvider() {
+ @Override
+ public PsiReference @NotNull [] getReferencesByElement(
+ @NotNull PsiElement element, @NotNull ProcessingContext context) {
+
+ Project project = element.getProject();
+ JSLiteralExpression literalExpression = (JSLiteralExpression) element;
+ String value = literalExpression.getStringValue();
+
+ return getReferences(project, element, value);
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/de/marhali/easyi18n/assistance/reference/KtKeyReferenceContributor.java b/src/main/java/de/marhali/easyi18n/assistance/reference/KtKeyReferenceContributor.java
new file mode 100644
index 0000000..dc1b0e1
--- /dev/null
+++ b/src/main/java/de/marhali/easyi18n/assistance/reference/KtKeyReferenceContributor.java
@@ -0,0 +1,46 @@
+package de.marhali.easyi18n.assistance.reference;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.patterns.PlatformPatterns;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.PsiReferenceProvider;
+import com.intellij.psi.PsiReferenceRegistrar;
+import com.intellij.util.ProcessingContext;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.kotlin.psi.KtLiteralStringTemplateEntry;
+import org.jetbrains.kotlin.psi.KtStringTemplateExpression;
+
+import java.util.Arrays;
+import java.util.Optional;
+
+/**
+ * Kotlin specific translation-key reference binding.
+ * @author marhali
+ */
+public class KtKeyReferenceContributor extends AbstractKeyReferenceContributor {
+ @Override
+ public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) {
+ registrar.registerReferenceProvider(
+ PlatformPatterns.psiElement().inside(KtStringTemplateExpression.class),
+ getProvider());
+ }
+
+ private PsiReferenceProvider getProvider() {
+ return new PsiReferenceProvider() {
+ @Override
+ public PsiReference @NotNull [] getReferencesByElement(
+ @NotNull PsiElement element, @NotNull ProcessingContext context) {
+
+ Optional targetElement = Arrays.stream(element.getChildren()).filter(child ->
+ child instanceof KtLiteralStringTemplateEntry).findAny();
+
+ if(targetElement.isEmpty()) {
+ return PsiReference.EMPTY_ARRAY;
+ }
+
+ return getReferences(element.getProject(), element, targetElement.get().getText());
+ }
+ };
+ }
+}
diff --git a/src/main/java/de/marhali/easyi18n/assistance/reference/PhpKeyReferenceContributor.java b/src/main/java/de/marhali/easyi18n/assistance/reference/PhpKeyReferenceContributor.java
new file mode 100644
index 0000000..0d11599
--- /dev/null
+++ b/src/main/java/de/marhali/easyi18n/assistance/reference/PhpKeyReferenceContributor.java
@@ -0,0 +1,37 @@
+package de.marhali.easyi18n.assistance.reference;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.patterns.PlatformPatterns;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.PsiReferenceProvider;
+import com.intellij.psi.PsiReferenceRegistrar;
+import com.intellij.util.ProcessingContext;
+import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Php specific key reference binding
+ */
+public class PhpKeyReferenceContributor extends AbstractKeyReferenceContributor {
+ @Override
+ public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) {
+ registrar.registerReferenceProvider(
+ PlatformPatterns.psiElement(StringLiteralExpression.class),
+ getProvider());
+ }
+
+ private PsiReferenceProvider getProvider() {
+ return new PsiReferenceProvider() {
+ @Override
+ public PsiReference @NotNull [] getReferencesByElement(
+ @NotNull PsiElement element, @NotNull ProcessingContext context) {
+
+ Project project = element.getProject();
+ StringLiteralExpression literalExpression = (StringLiteralExpression) element;
+ return getReferences(project, element, literalExpression.getContents());
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/de/marhali/easyi18n/assistance/reference/PsiKeyReference.java b/src/main/java/de/marhali/easyi18n/assistance/reference/PsiKeyReference.java
new file mode 100644
index 0000000..58a45e7
--- /dev/null
+++ b/src/main/java/de/marhali/easyi18n/assistance/reference/PsiKeyReference.java
@@ -0,0 +1,72 @@
+package de.marhali.easyi18n.assistance.reference;
+
+import com.intellij.navigation.ItemPresentation;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiReferenceBase;
+import com.intellij.psi.SyntheticElement;
+import com.intellij.psi.impl.FakePsiElement;
+
+import de.marhali.easyi18n.dialog.AddDialog;
+import de.marhali.easyi18n.dialog.EditDialog;
+import de.marhali.easyi18n.model.Translation;
+import de.marhali.easyi18n.util.KeyPathConverter;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * References translation keys inside editor with corresponding {@link EditDialog} / {@link AddDialog}.
+ * @author marhali
+ */
+public class PsiKeyReference extends PsiReferenceBase {
+
+ private final @NotNull Translation translation;
+ private final @NotNull KeyPathConverter converter;
+
+ protected PsiKeyReference(
+ @NotNull KeyPathConverter converter, @NotNull Translation translation, @NotNull PsiElement element) {
+
+ super(element, true);
+ this.translation = translation;
+ this.converter = converter;
+ }
+
+ public @NotNull String getKey() {
+ return converter.toString(translation.getKey());
+ }
+
+ @Override
+ public @Nullable PsiElement resolve() {
+ return new TranslationReference();
+ }
+
+ public class TranslationReference extends FakePsiElement implements SyntheticElement {
+ @Override
+ public PsiElement getParent() {
+ return myElement;
+ }
+
+ @Override
+ public void navigate(boolean requestFocus) {
+ new EditDialog(getProject(), translation).showAndHandle();
+ }
+
+ @Override
+ public String getPresentableText() {
+ return getKey();
+ }
+
+ @Override
+ public String getName() {
+ return getKey();
+ }
+
+ @Override
+ public @Nullable TextRange getTextRange() {
+ TextRange rangeInElement = getRangeInElement();
+ TextRange elementRange = myElement.getTextRange();
+ return elementRange != null ? rangeInElement.shiftRight(elementRange.getStartOffset()) : rangeInElement;
+ }
+ }
+}
\ 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 dd886b0..84164e9 100644
--- a/src/main/java/de/marhali/easyi18n/dialog/AddDialog.java
+++ b/src/main/java/de/marhali/easyi18n/dialog/AddDialog.java
@@ -3,112 +3,65 @@ package de.marhali.easyi18n.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.InstanceManager;
-import de.marhali.easyi18n.model.*;
+import de.marhali.easyi18n.model.action.TranslationCreate;
+import de.marhali.easyi18n.model.KeyPath;
+import de.marhali.easyi18n.model.Translation;
+import de.marhali.easyi18n.model.TranslationValue;
+import de.marhali.easyi18n.model.action.TranslationUpdate;
+import de.marhali.easyi18n.settings.ProjectSettingsService;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
-import javax.swing.border.EtchedBorder;
-import java.awt.*;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.ResourceBundle;
/**
- * Create translation dialog.
+ * Dialog to create a new translation with all associated locale values.
+ * Supports optional prefill technique for translation key or locale value.
* @author marhali
*/
-public class AddDialog {
+public class AddDialog extends TranslationDialog {
- private final @NotNull Project project;
- private final @NotNull KeyPathConverter converter;
-
- private @NotNull KeyPath preKey;
-
- private JBTextField keyTextField;
- private Map valueTextFields;
-
- public AddDialog(@NotNull Project project, @Nullable KeyPath preKey) {
- this(project);
- this.preKey = preKey == null ? new KeyPath() : preKey;
+ /**
+ * Constructs a new create dialog with prefilled fields
+ * @param project Opened project
+ * @param prefillKey Prefill translation key
+ * @param prefillLocale Prefill preview locale value
+ */
+ public AddDialog(@NotNull Project project, @Nullable KeyPath prefillKey, @Nullable String prefillLocale) {
+ super(project, new Translation(prefillKey != null ? prefillKey : new KeyPath(),
+ prefillLocale != null
+ ? new TranslationValue(ProjectSettingsService.get(project).getState().getPreviewLocale(), prefillLocale)
+ : null)
+ );
}
+ /**
+ * Constructs a new create dialog without prefilled fields.
+ * @param project Opened project
+ */
public AddDialog(@NotNull Project project) {
- this.project = project;
- this.converter = new KeyPathConverter(project);
- this.preKey = new KeyPath();
+ this(project, new KeyPath(), "");
}
- public void showAndHandle() {
- int code = prepare().show();
-
- if(code == DialogWrapper.OK_EXIT_CODE) {
- saveTranslation();
- }
- }
-
- private void saveTranslation() {
- Translation translation = new Translation();
-
- valueTextFields.forEach((k, v) -> {
- if(!v.getText().isEmpty()) {
- translation.put(k, v.getText());
- }
- });
-
- KeyedTranslation keyedTranslation = new KeyedTranslation(converter.split(keyTextField.getText()), translation);
- TranslationCreate creation = new TranslationCreate(keyedTranslation);
- InstanceManager.get(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(ResourceBundle.getBundle("messages").getString("translation.key"));
- keyTextField = new JBTextField(this.converter.concat(this.preKey));
- keyLabel.setLabelFor(keyTextField);
- keyPanel.add(keyLabel);
- keyPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0));
- keyPanel.add(keyTextField);
- rootPanel.add(keyPanel);
-
- if(!this.preKey.isEmpty()) { // Add delimiter if pre key is defined
- keyTextField.setText(keyTextField.getText() + KeyPath.DELIMITER);
- }
-
- JPanel valuePanel = new JPanel(new GridLayout(0, 1, 2, 2));
- valueTextFields = new HashMap<>();
-
- for(String locale : InstanceManager.get(project).store().getData().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(),
- ResourceBundle.getBundle("messages").getString("translation.locales")));
- rootPanel.add(valuePane);
+ @Override
+ protected @NotNull DialogBuilder configure(@NotNull JComponent centerPanel) {
DialogBuilder builder = new DialogBuilder();
- builder.setTitle(ResourceBundle.getBundle("messages").getString("action.add"));
+ builder.setTitle(bundle.getString("action.add"));
builder.removeAllActions();
builder.addOkAction();
builder.addCancelAction();
- builder.setCenterPanel(rootPanel);
-
+ builder.setCenterPanel(centerPanel);
return builder;
}
-}
\ No newline at end of file
+
+ @Override
+ protected @Nullable TranslationUpdate handleExit(int exitCode) {
+ if(exitCode == DialogWrapper.OK_EXIT_CODE) {
+ return new TranslationCreate(getState());
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/de/marhali/easyi18n/dialog/EditDialog.java b/src/main/java/de/marhali/easyi18n/dialog/EditDialog.java
index cc47e27..6c9662c 100644
--- a/src/main/java/de/marhali/easyi18n/dialog/EditDialog.java
+++ b/src/main/java/de/marhali/easyi18n/dialog/EditDialog.java
@@ -3,102 +3,53 @@ package de.marhali.easyi18n.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.InstanceManager;
-import de.marhali.easyi18n.model.*;
import de.marhali.easyi18n.dialog.descriptor.DeleteActionDescriptor;
+import de.marhali.easyi18n.model.action.TranslationDelete;
+import de.marhali.easyi18n.model.action.TranslationUpdate;
+import de.marhali.easyi18n.model.Translation;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import javax.swing.*;
-import javax.swing.border.EtchedBorder;
-import java.awt.*;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.ResourceBundle;
/**
- * Edit translation dialog.
+ * Dialog to edit or delete an existing translation.
* @author marhali
*/
-public class EditDialog {
+public class EditDialog extends TranslationDialog {
- private final Project project;
- private final KeyPathConverter converter;
-
- private final KeyedTranslation origin;
-
- private JBTextField keyTextField;
- private Map valueTextFields;
-
- public EditDialog(Project project, KeyedTranslation origin) {
- this.project = project;
- this.converter = new KeyPathConverter(project);
- this.origin = origin;
+ /**
+ * Constructs a new edit dialog with the provided translation
+ * @param project Opened project
+ * @param origin Translation to edit
+ */
+ public EditDialog(@NotNull Project project, @NotNull Translation origin) {
+ super(project, origin);
}
- public void showAndHandle() {
- int code = prepare().show();
-
- if(code == DialogWrapper.OK_EXIT_CODE) { // Edit
- InstanceManager.get(project).processUpdate(new TranslationUpdate(origin, getChanges()));
- } else if(code == DeleteActionDescriptor.EXIT_CODE) { // Delete
- InstanceManager.get(project).processUpdate(new TranslationDelete(origin));
- }
- }
-
- private KeyedTranslation getChanges() {
- Translation translation = new Translation();
-
- valueTextFields.forEach((k, v) -> {
- if(!v.getText().isEmpty()) {
- translation.put(k, v.getText());
- }
- });
-
- return new KeyedTranslation(converter.split(keyTextField.getText()), translation);
- }
-
- 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(ResourceBundle.getBundle("messages").getString("translation.key"));
- keyTextField = new JBTextField(this.converter.concat(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 : InstanceManager.get(project).store().getData().getLocales()) {
- JBLabel localeLabel = new JBLabel(locale);
- JBTextField localeText = new JBTextField(this.origin.getTranslation().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(),
- ResourceBundle.getBundle("messages").getString("translation.locales")));
- rootPanel.add(valuePane);
-
+ @Override
+ protected @NotNull DialogBuilder configure(@NotNull JComponent centerPanel) {
DialogBuilder builder = new DialogBuilder();
- builder.setTitle(ResourceBundle.getBundle("messages").getString("action.edit"));
+ builder.setTitle(bundle.getString("action.edit"));
builder.removeAllActions();
builder.addCancelAction();
builder.addActionDescriptor(new DeleteActionDescriptor());
builder.addOkAction();
- builder.setCenterPanel(rootPanel);
-
+ builder.setCenterPanel(centerPanel);
return builder;
}
+
+ @Override
+ protected @Nullable TranslationUpdate handleExit(int exitCode) {
+ switch (exitCode) {
+ case DialogWrapper.OK_EXIT_CODE:
+ return new TranslationUpdate(origin, getState());
+ case DeleteActionDescriptor.EXIT_CODE:
+ return new TranslationDelete(origin);
+ default:
+ return null;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/main/java/de/marhali/easyi18n/dialog/SettingsDialog.java b/src/main/java/de/marhali/easyi18n/dialog/SettingsDialog.java
deleted file mode 100644
index b45ca2f..0000000
--- a/src/main/java/de/marhali/easyi18n/dialog/SettingsDialog.java
+++ /dev/null
@@ -1,173 +0,0 @@
-package de.marhali.easyi18n.dialog;
-
-import com.intellij.openapi.fileChooser.FileChooserDescriptor;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.ComboBox;
-import com.intellij.openapi.ui.DialogBuilder;
-import com.intellij.openapi.ui.DialogWrapper;
-import com.intellij.openapi.ui.TextFieldWithBrowseButton;
-import com.intellij.ui.components.JBCheckBox;
-import com.intellij.ui.components.JBLabel;
-import com.intellij.ui.components.JBPanel;
-import com.intellij.ui.components.JBTextField;
-
-import de.marhali.easyi18n.InstanceManager;
-import de.marhali.easyi18n.io.parser.ArrayMapper;
-import de.marhali.easyi18n.model.FolderStrategyType;
-import de.marhali.easyi18n.model.SettingsState;
-import de.marhali.easyi18n.io.parser.ParserStrategyType;
-import de.marhali.easyi18n.service.SettingsService;
-
-import javax.swing.*;
-import java.awt.*;
-import java.awt.event.ItemEvent;
-import java.awt.event.ItemListener;
-import java.util.ResourceBundle;
-
-/**
- * Plugin configuration dialog.
- * @author marhali
- */
-public class SettingsDialog {
-
- private final Project project;
-
- private TextFieldWithBrowseButton pathText;
- private ComboBox folderStrategyComboBox;
- private ComboBox parserStrategyComboBox;
- private JBTextField filePatternText;
- private JBTextField previewLocaleText;
- private JBTextField pathPrefixText;
- private JBCheckBox sortKeysCheckbox;
- private JBCheckBox nestedKeysCheckbox;
- private JBCheckBox codeAssistanceCheckbox;
-
- public SettingsDialog(Project project) {
- this.project = project;
- }
-
- public void showAndHandle() {
- SettingsState state = SettingsService.getInstance(project).getState();
-
- if(prepare(state).show() == DialogWrapper.OK_EXIT_CODE) { // Save changes
- state.setLocalesPath(pathText.getText());
- state.setFolderStrategy(FolderStrategyType.fromIndex(folderStrategyComboBox.getSelectedIndex()));
- state.setParserStrategy(ParserStrategyType.fromIndex(parserStrategyComboBox.getSelectedIndex()));
- state.setFilePattern(filePatternText.getText());
- state.setPreviewLocale(previewLocaleText.getText());
- state.setPathPrefix(pathPrefixText.getText());
- state.setSortKeys(sortKeysCheckbox.isSelected());
- state.setNestedKeys(nestedKeysCheckbox.isSelected());
- state.setCodeAssistance(codeAssistanceCheckbox.isSelected());
-
- // Reload instance
- InstanceManager manager = InstanceManager.get(project);
- manager.store().loadFromPersistenceLayer((success) ->
- manager.bus().propagate().onUpdateData(manager.store().getData()));
- }
- }
-
- private DialogBuilder prepare(SettingsState state) {
- ResourceBundle bundle = ResourceBundle.getBundle("messages");
- JPanel rootPanel = new JPanel(new GridLayout(0, 1, 2, 2));
-
- /* path */
- JBLabel pathLabel = new JBLabel(bundle.getString("settings.path.text"));
- pathText = new TextFieldWithBrowseButton(new JTextField(state.getLocalesPath()));
-
- pathLabel.setLabelFor(pathText);
- pathText.addBrowseFolderListener(bundle.getString("settings.path.title"), null, project, new FileChooserDescriptor(
- false, true, false, false, false, false));
-
- rootPanel.add(pathLabel);
- rootPanel.add(pathText);
-
- JBLabel strategyLabel = new JBLabel(bundle.getString("settings.strategy.title"));
- rootPanel.add(strategyLabel);
-
- JPanel strategyPanel = new JBPanel<>(new GridBagLayout());
- rootPanel.add(strategyPanel);
- GridBagConstraints constraints = new GridBagConstraints();
-
- /* folder strategy */
- folderStrategyComboBox = new ComboBox<>(bundle.getString("settings.strategy.folder").split(ArrayMapper.SPLITERATOR_REGEX));
- folderStrategyComboBox.setSelectedIndex(state.getFolderStrategy().toIndex());
- folderStrategyComboBox.setToolTipText(bundle.getString("settings.strategy.folder.tooltip"));
- folderStrategyComboBox.setMinimumAndPreferredWidth(256);
- constraints.fill = GridBagConstraints.HORIZONTAL;
- constraints.gridx = 0;
- constraints.gridy = 0;
- strategyPanel.add(folderStrategyComboBox, constraints);
-
- /* parser strategy */
- parserStrategyComboBox = new ComboBox<>(bundle.getString("settings.strategy.parser").split(ArrayMapper.SPLITERATOR_REGEX));
- parserStrategyComboBox.setSelectedIndex(state.getParserStrategy().toIndex());
- parserStrategyComboBox.setToolTipText(bundle.getString("settings.strategy.parser.tooltip"));
- parserStrategyComboBox.addItemListener(handleParserChange());
- constraints.fill = GridBagConstraints.HORIZONTAL;
- constraints.gridx = 1;
- constraints.gridy = 0;
- strategyPanel.add(parserStrategyComboBox, constraints);
-
- /* file pattern strategy */
- filePatternText = new JBTextField(state.getFilePattern());
- filePatternText.setToolTipText(bundle.getString("settings.strategy.file-pattern.tooltip"));
- constraints.fill = GridBagConstraints.HORIZONTAL;
- constraints.gridx = 2;
- constraints.gridy = 0;
- constraints.weightx = 1;
- strategyPanel.add(filePatternText, constraints);
-
- /* preview locale */
- JBLabel previewLocaleLabel = new JBLabel(bundle.getString("settings.preview"));
- previewLocaleText = new JBTextField(state.getPreviewLocale());
- previewLocaleLabel.setLabelFor(previewLocaleText);
-
- rootPanel.add(previewLocaleLabel);
- rootPanel.add(previewLocaleText);
-
- /* path prefix */
- JBLabel pathPrefixLabel = new JBLabel(bundle.getString("settings.path.prefix"));
- pathPrefixText = new JBTextField(state.getPathPrefix());
-
- rootPanel.add(pathPrefixLabel);
- rootPanel.add(pathPrefixText);
-
- /* sort keys */
- sortKeysCheckbox = new JBCheckBox(bundle.getString("settings.keys.sort"));
- sortKeysCheckbox.setSelected(state.isSortKeys());
-
- rootPanel.add(sortKeysCheckbox);
-
- /* nested keys */
- nestedKeysCheckbox = new JBCheckBox(bundle.getString("settings.keys.nested"));
- nestedKeysCheckbox.setSelected(state.isNestedKeys());
-
- rootPanel.add(nestedKeysCheckbox);
-
- /* code assistance */
- codeAssistanceCheckbox = new JBCheckBox(bundle.getString("settings.editor.assistance"));
- codeAssistanceCheckbox.setSelected(state.isCodeAssistance());
-
- rootPanel.add(codeAssistanceCheckbox);
-
- DialogBuilder builder = new DialogBuilder();
- builder.setTitle(bundle.getString("action.settings"));
- builder.removeAllActions();
- builder.addCancelAction();
- builder.addOkAction();
- builder.setCenterPanel(rootPanel);
-
- return builder;
- }
-
- private ItemListener handleParserChange() {
- return e -> {
- if(e.getStateChange() == ItemEvent.SELECTED) {
- // Automatically suggest file pattern option on parser change
- ParserStrategyType newStrategy = ParserStrategyType.fromIndex(parserStrategyComboBox.getSelectedIndex());
- filePatternText.setText(newStrategy.getExampleFilePattern());
- }
- };
- }
-}
\ No newline at end of file
diff --git a/src/main/java/de/marhali/easyi18n/dialog/TranslationDialog.java b/src/main/java/de/marhali/easyi18n/dialog/TranslationDialog.java
new file mode 100644
index 0000000..306e5ba
--- /dev/null
+++ b/src/main/java/de/marhali/easyi18n/dialog/TranslationDialog.java
@@ -0,0 +1,148 @@
+package de.marhali.easyi18n.dialog;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogBuilder;
+import com.intellij.ui.components.JBScrollPane;
+import com.intellij.ui.components.JBTextField;
+import com.intellij.util.Consumer;
+import com.intellij.util.ui.FormBuilder;
+
+import de.marhali.easyi18n.InstanceManager;
+import de.marhali.easyi18n.model.KeyPath;
+import de.marhali.easyi18n.model.Translation;
+import de.marhali.easyi18n.model.TranslationValue;
+import de.marhali.easyi18n.model.action.TranslationUpdate;
+import de.marhali.easyi18n.settings.ProjectSettings;
+import de.marhali.easyi18n.settings.ProjectSettingsService;
+import de.marhali.easyi18n.util.KeyPathConverter;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import javax.swing.border.EtchedBorder;
+import java.awt.*;
+import java.util.*;
+
+/**
+ * Base for add and edit translation dialogs.
+ * @author marhali
+ */
+abstract class TranslationDialog {
+
+ protected static final ResourceBundle bundle = ResourceBundle.getBundle("messages");
+
+ protected final @NotNull Project project;
+ protected final @NotNull ProjectSettings settings;
+ protected final @NotNull KeyPathConverter converter;
+ protected final @NotNull Translation origin;
+
+ protected final JTextField keyField;
+ protected final Map localeValueFields;
+
+ private final Set> callbacks;
+
+ /**
+ * Constructs a new translation dialog.
+ * @param project Opened project
+ * @param origin Prefill translation
+ */
+ protected TranslationDialog(@NotNull Project project, @NotNull Translation origin) {
+ this.project = project;
+ this.settings = ProjectSettingsService.get(project).getState();
+ this.converter = new KeyPathConverter(settings);
+ this.origin = origin;
+
+ this.callbacks = new HashSet<>();
+
+ // Fields
+ TranslationValue value = origin.getValue();
+
+ this.keyField = new JBTextField(converter.toString(origin.getKey()));
+ this.localeValueFields = new HashMap<>();
+
+ for(String locale : InstanceManager.get(project).store().getData().getLocales()) {
+ localeValueFields.put(locale, new JBTextField(value != null ? value.get(locale) : null));
+ }
+ }
+
+ /**
+ * Registers a callback that is called on dialog close with the final state.
+ * If the user aborts the dialog no callback is called.
+ * @param callback Callback to register
+ */
+ public void registerCallback(Consumer callback) {
+ callbacks.add(callback);
+ }
+
+ /**
+ * Implementation needs to configure the dialog. E.g. title, actions, ...
+ * The implementation needs to set the provided centerPanel as the view panel.
+ * @param centerPanel GUI to set on the dialog builder
+ * @return configured dialog builder
+ */
+ protected abstract @NotNull DialogBuilder configure(@NotNull JComponent centerPanel);
+
+ /**
+ * Implementation needs to handle exit
+ * @param exitCode See {@link com.intellij.openapi.ui.DialogWrapper} for exit codes
+ * @return update conclusion, null if aborted
+ */
+ protected abstract @Nullable TranslationUpdate handleExit(int exitCode);
+
+ /**
+ * Opens the translation modal and applies the appropriate logic on modal close.
+ * Internally, the {@link #handleExit(int)} method will be called to determine finalization logic.
+ */
+ public void showAndHandle() {
+ int exitCode = createDialog().show();
+ TranslationUpdate update = handleExit(exitCode);
+
+ if(update != null) {
+ InstanceManager.get(project).processUpdate(update);
+ callbacks.forEach(callback -> callback.consume(update));
+ }
+ }
+
+ /**
+ * Retrieve current modal state.
+ * @return Translation
+ */
+ protected @NotNull Translation getState() {
+ KeyPath key = converter.fromString(keyField.getText());
+
+ TranslationValue value = new TranslationValue();
+
+ for(Map.Entry entry : localeValueFields.entrySet()) {
+ value.put(entry.getKey(), entry.getValue().getText());
+ }
+
+ return new Translation(key, value);
+ }
+
+ private DialogBuilder createDialog() {
+ JPanel panel = FormBuilder.createFormBuilder()
+ .addLabeledComponent(bundle.getString("translation.key"), keyField, true)
+ .addComponent(createLocalesPanel(), 12)
+ .getPanel();
+
+ panel.setMinimumSize(new Dimension(200, 150));
+
+ return configure(panel);
+ }
+
+ private JComponent createLocalesPanel() {
+ FormBuilder builder = FormBuilder.createFormBuilder();
+
+ for(Map.Entry localeEntry : localeValueFields.entrySet()) {
+ builder.addLabeledComponent(localeEntry.getKey(), localeEntry.getValue(), 6, true);
+ }
+
+ JScrollPane scrollPane = new JBScrollPane(builder.getPanel());
+
+ scrollPane.setBorder(BorderFactory.createTitledBorder(
+ new EtchedBorder(), bundle.getString("translation.locales")));
+
+ return scrollPane;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/de/marhali/easyi18n/editor/KeyAnnotator.java b/src/main/java/de/marhali/easyi18n/editor/KeyAnnotator.java
deleted file mode 100644
index 919a97a..0000000
--- a/src/main/java/de/marhali/easyi18n/editor/KeyAnnotator.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package de.marhali.easyi18n.editor;
-
-import com.intellij.lang.annotation.AnnotationHolder;
-import com.intellij.lang.annotation.HighlightSeverity;
-import com.intellij.openapi.project.Project;
-
-import de.marhali.easyi18n.InstanceManager;
-import de.marhali.easyi18n.model.KeyPath;
-import de.marhali.easyi18n.model.KeyPathConverter;
-import de.marhali.easyi18n.model.SettingsState;
-import de.marhali.easyi18n.model.TranslationNode;
-import de.marhali.easyi18n.service.SettingsService;
-
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Superclass for managing key annotations.
- * @author marhali
- */
-public class KeyAnnotator {
-
- /**
- * Adds annotations for i18n keys with content preview for preferred locale.
- * @param key I18n key extracted by psi element
- * @param project Project instance
- * @param holder Annotation holder
- */
- protected void annotate(@NotNull String key, @NotNull Project project, @NotNull AnnotationHolder holder) {
- // Do not annotate keys if service is disabled
- if(!SettingsService.getInstance(project).getState().isCodeAssistance()) {
- return;
- }
-
- SettingsState state = SettingsService.getInstance(project).getState();
- String pathPrefix = state.getPathPrefix();
- String previewLocale = state.getPreviewLocale();
-
- KeyPathConverter converter = new KeyPathConverter(project);
-
- String searchKey = key.length() >= pathPrefix.length()
- ? key.substring(pathPrefix.length())
- : key;
-
- if(searchKey.startsWith(KeyPath.DELIMITER)) {
- searchKey = searchKey.substring(KeyPath.DELIMITER.length());
- }
-
- TranslationNode node = InstanceManager.get(project).store().getData().getNode(converter.split(searchKey));
-
- if(node == null) { // Unknown translation. Just ignore it
- return;
- }
-
- String tooltip = node.isLeaf() ? "I18n(" + previewLocale + ": " + node.getValue().get(previewLocale) + ")"
- : "I18n ([])";
-
- holder.newAnnotation(HighlightSeverity.INFORMATION, tooltip).create();
- }
-}
\ No newline at end of file
diff --git a/src/main/java/de/marhali/easyi18n/editor/KeyCompletionProvider.java b/src/main/java/de/marhali/easyi18n/editor/KeyCompletionProvider.java
deleted file mode 100644
index c866428..0000000
--- a/src/main/java/de/marhali/easyi18n/editor/KeyCompletionProvider.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package de.marhali.easyi18n.editor;
-
-import com.intellij.codeInsight.completion.*;
-import com.intellij.codeInsight.lookup.*;
-import com.intellij.icons.AllIcons;
-import com.intellij.openapi.project.*;
-import com.intellij.util.*;
-
-import de.marhali.easyi18n.DataStore;
-import de.marhali.easyi18n.InstanceManager;
-import de.marhali.easyi18n.model.KeyPath;
-import de.marhali.easyi18n.model.Translation;
-import de.marhali.easyi18n.service.*;
-
-import org.jetbrains.annotations.*;
-
-import java.util.*;
-
-/**
- * I18n translation key completion provider.
- * @author marhali
- */
-public class KeyCompletionProvider extends CompletionProvider {
-
- @Override
- protected void addCompletions(@NotNull CompletionParameters parameters,
- @NotNull ProcessingContext context, @NotNull CompletionResultSet result) {
-
- Project project = parameters.getOriginalFile().getProject();
-
- // Do not annotate keys if service is disabled
- if(!SettingsService.getInstance(project).getState().isCodeAssistance()) {
- return;
- }
-
- DataStore store = InstanceManager.get(project).store();
-
- String previewLocale = SettingsService.getInstance(project).getState().getPreviewLocale();
- String pathPrefix = SettingsService.getInstance(project).getState().getPathPrefix();
-
- if(pathPrefix.length() > 0 && !pathPrefix.endsWith(KeyPath.DELIMITER)) {
- pathPrefix += KeyPath.DELIMITER;
- }
-
- Set fullKeys = store.getData().getFullKeys();
-
- for(KeyPath currentKey : fullKeys) {
- result.addElement(createElement(
- pathPrefix,
- currentKey,
- previewLocale,
- Objects.requireNonNull(store.getData().getTranslation(currentKey))
- ));
- }
- }
-
- private LookupElement createElement(String prefix, KeyPath path, String locale, Translation translation) {
- return LookupElementBuilder.create(prefix + path.toSimpleString())
- .withIcon(AllIcons.Actions.PreserveCaseHover)
- .appendTailText(" I18n(" + locale + ": " + translation.get(locale) + ")", true);
- }
-}
\ No newline at end of file
diff --git a/src/main/java/de/marhali/easyi18n/editor/KeyReference.java b/src/main/java/de/marhali/easyi18n/editor/KeyReference.java
deleted file mode 100644
index d848bc1..0000000
--- a/src/main/java/de/marhali/easyi18n/editor/KeyReference.java
+++ /dev/null
@@ -1,93 +0,0 @@
-package de.marhali.easyi18n.editor;
-
-import com.intellij.openapi.util.TextRange;
-import com.intellij.psi.*;
-import com.intellij.psi.impl.FakePsiElement;
-
-import de.marhali.easyi18n.InstanceManager;
-import de.marhali.easyi18n.dialog.AddDialog;
-import de.marhali.easyi18n.dialog.EditDialog;
-import de.marhali.easyi18n.model.KeyPath;
-import de.marhali.easyi18n.model.KeyPathConverter;
-import de.marhali.easyi18n.model.KeyedTranslation;
-import de.marhali.easyi18n.model.Translation;
-
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * Go to declaration reference for i18n keys.
- * @author marhali
- */
-public class KeyReference extends PsiReferenceBase {
-
- @Nullable private final String myKey;
-
- public KeyReference(@NotNull final PsiElement element) {
- this(element, (String)null);
- }
-
- public KeyReference(@NotNull final PsiElement element, @Nullable final String myKey) {
- super(element, true);
- this.myKey = myKey;
- }
-
- public KeyReference(@NotNull final PsiElement element, @NotNull TextRange textRange) {
- this(element, textRange, null);
- }
-
- public KeyReference(@NotNull PsiElement element, TextRange textRange, @Nullable String myKey) {
- super(element, textRange, true);
- this.myKey = myKey;
- }
-
- @Override
- public @Nullable PsiElement resolve() {
- return new TranslationKey();
- }
-
- public String getKey() {
- return myKey != null ? myKey : getValue();
- }
-
- class TranslationKey extends FakePsiElement implements SyntheticElement {
- @Override
- public PsiElement getParent() {
- return myElement;
- }
-
- @Override
- public void navigate(boolean requestFocus) {
- KeyPathConverter converter = new KeyPathConverter(getProject());
- KeyPath path = converter.split(getKey());
- Translation translation = InstanceManager.get(getProject()).store().getData().getTranslation(path);
-
- if(translation != null) {
- new EditDialog(getProject(), new KeyedTranslation(path, translation)).showAndHandle();
- } else {
- new AddDialog(getProject(), path).showAndHandle();
- }
- }
-
- @Override
- public String getPresentableText() {
- return getKey();
- }
-
- @Override
- public String getName() {
- return getKey();
- }
-
- @Override
- public @Nullable TextRange getTextRange() {
- final TextRange rangeInElement = getRangeInElement();
- final TextRange elementRange = myElement.getTextRange();
- return elementRange != null ? rangeInElement.shiftRight(elementRange.getStartOffset()) : rangeInElement;
- }
- }
-
- public static boolean isReferencable(String value) {
- return value.matches("^[^\\s:/]+$");
- }
-}
\ No newline at end of file
diff --git a/src/main/java/de/marhali/easyi18n/editor/generic/GenericFoldingBuilder.java b/src/main/java/de/marhali/easyi18n/editor/generic/GenericFoldingBuilder.java
deleted file mode 100644
index cbda752..0000000
--- a/src/main/java/de/marhali/easyi18n/editor/generic/GenericFoldingBuilder.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package de.marhali.easyi18n.editor.generic;
-
-import com.intellij.lang.ASTNode;
-import com.intellij.lang.folding.FoldingBuilderEx;
-import com.intellij.lang.folding.FoldingDescriptor;
-import com.intellij.openapi.editor.Document;
-import com.intellij.openapi.util.TextRange;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiLiteralValue;
-import com.intellij.psi.util.PsiTreeUtil;
-
-import de.marhali.easyi18n.DataStore;
-import de.marhali.easyi18n.InstanceManager;
-import de.marhali.easyi18n.model.KeyPathConverter;
-import de.marhali.easyi18n.model.Translation;
-import de.marhali.easyi18n.service.SettingsService;
-
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-/**
- * Translation key folding with actual value based on i18n instance.
- * @author marhali
- */
-public class GenericFoldingBuilder extends FoldingBuilderEx {
-
- @Override
- public FoldingDescriptor @NotNull [] buildFoldRegions(@NotNull PsiElement root, @NotNull Document document, boolean quick) {
- Collection literalValues = PsiTreeUtil.findChildrenOfType(root, PsiLiteralValue.class);
- List descriptors = new ArrayList<>();
-
- if(!SettingsService.getInstance(root.getProject()).getState().isCodeAssistance()) {
- return FoldingDescriptor.EMPTY;
- }
-
- DataStore store = InstanceManager.get(root.getProject()).store();
- KeyPathConverter converter = new KeyPathConverter(root.getProject());
-
- for(final PsiLiteralValue literalValue : literalValues) {
- String value = literalValue.getValue() instanceof String ? (String) literalValue.getValue() : null;
-
- // Undefined string literal or not a translation
- if(value == null || store.getData().getTranslation(converter.split(value)) == null) {
- continue;
- }
-
- descriptors.add(new FoldingDescriptor(literalValue.getNode(),
- new TextRange(literalValue.getTextRange().getStartOffset() + 1,
- literalValue.getTextRange().getEndOffset() - 1)));
- }
-
- return descriptors.toArray(new FoldingDescriptor[0]);
- }
-
- @Nullable
- @Override
- public String getPlaceholderText(@NotNull ASTNode node) {
- PsiLiteralValue literalValue = node.getPsi(PsiLiteralValue.class);
- String value = literalValue.getValue() instanceof String ? (String) literalValue.getValue() : null;
-
- if(value == null) {
- return null;
- }
-
- DataStore store = InstanceManager.get(literalValue.getProject()).store();
- KeyPathConverter converter = new KeyPathConverter(literalValue.getProject());
-
- Translation translation = store.getData().getTranslation(converter.split(value));
-
- if(translation == null) {
- return null;
- }
-
- String previewLocale = SettingsService.getInstance(literalValue.getProject()).getState().getPreviewLocale();
-
- return translation.get(previewLocale);
- }
-
- @Override
- public boolean isCollapsedByDefault(@NotNull ASTNode node) {
- return true;
- }
-}
\ No newline at end of file
diff --git a/src/main/java/de/marhali/easyi18n/editor/generic/GenericKeyAnnotator.java b/src/main/java/de/marhali/easyi18n/editor/generic/GenericKeyAnnotator.java
deleted file mode 100644
index 8de8149..0000000
--- a/src/main/java/de/marhali/easyi18n/editor/generic/GenericKeyAnnotator.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package de.marhali.easyi18n.editor.generic;
-
-import com.intellij.lang.annotation.AnnotationHolder;
-import com.intellij.lang.annotation.Annotator;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiLiteralValue;
-
-import de.marhali.easyi18n.editor.KeyAnnotator;
-
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Translation key annotator for generic languages which support {@link PsiLiteralValue}.
- * @author marhali
- */
-public class GenericKeyAnnotator extends KeyAnnotator implements Annotator {
-
- @Override
- public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) {
- if(!(element instanceof PsiLiteralValue)) {
- return;
- }
-
- PsiLiteralValue literalValue = (PsiLiteralValue) element;
- String value = literalValue.getValue() instanceof String ? (String) literalValue.getValue() : null;
-
- if(value == null) {
- return;
- }
-
- annotate(value, element.getProject(), holder);
- }
-}
\ No newline at end of file
diff --git a/src/main/java/de/marhali/easyi18n/editor/generic/GenericKeyCompletionContributor.java b/src/main/java/de/marhali/easyi18n/editor/generic/GenericKeyCompletionContributor.java
deleted file mode 100644
index a8ed832..0000000
--- a/src/main/java/de/marhali/easyi18n/editor/generic/GenericKeyCompletionContributor.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package de.marhali.easyi18n.editor.generic;
-
-import com.intellij.codeInsight.completion.CompletionContributor;
-import com.intellij.codeInsight.completion.CompletionType;
-import com.intellij.patterns.*;
-import com.intellij.psi.*;
-import com.intellij.psi.xml.*;
-import de.marhali.easyi18n.editor.KeyCompletionProvider;
-
-/**
- * Translation key completion for generic languages which support {@link PsiLiteralValue}.
- * @author marhali
- */
-public class GenericKeyCompletionContributor extends CompletionContributor {
-
- public GenericKeyCompletionContributor() {
- extend(CompletionType.BASIC, PlatformPatterns.psiElement(PlainTextTokenTypes.PLAIN_TEXT),
- new KeyCompletionProvider());
- extend(CompletionType.BASIC, PlatformPatterns.psiElement().inside(XmlElement.class),
- new KeyCompletionProvider());
- extend(CompletionType.BASIC, PlatformPatterns.psiElement().inside(PsiLiteralValue.class),
- new KeyCompletionProvider());
- }
-}
\ No newline at end of file
diff --git a/src/main/java/de/marhali/easyi18n/editor/generic/GenericKeyReferenceContributor.java b/src/main/java/de/marhali/easyi18n/editor/generic/GenericKeyReferenceContributor.java
deleted file mode 100644
index 5127178..0000000
--- a/src/main/java/de/marhali/easyi18n/editor/generic/GenericKeyReferenceContributor.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package de.marhali.easyi18n.editor.generic;
-
-import com.intellij.patterns.PlatformPatterns;
-import com.intellij.psi.*;
-import com.intellij.util.ProcessingContext;
-
-import de.marhali.easyi18n.InstanceManager;
-import de.marhali.easyi18n.editor.KeyReference;
-import de.marhali.easyi18n.model.KeyPathConverter;
-import de.marhali.easyi18n.service.SettingsService;
-
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Generic translation key reference contributor.
- * @author marhali
- */
-public class GenericKeyReferenceContributor extends PsiReferenceContributor {
- @Override
- public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) {
- registrar.registerReferenceProvider(PlatformPatterns.psiElement(PsiLiteralValue.class), getProvider());
- }
-
- private PsiReferenceProvider getProvider() {
- return new PsiReferenceProvider() {
- @Override
- public PsiReference @NotNull [] getReferencesByElement(
- @NotNull PsiElement element, @NotNull ProcessingContext context) {
-
- PsiLiteralValue literalValue = (PsiLiteralValue) element;
- String value = literalValue.getValue() instanceof String ? (String) literalValue.getValue() : null;
-
- if(value == null) {
- return PsiReference.EMPTY_ARRAY;
- }
-
- // Do not reference keys if service is disabled
- if(!SettingsService.getInstance(element.getProject()).getState().isCodeAssistance()) {
- return PsiReference.EMPTY_ARRAY;
- }
-
- KeyPathConverter converter = new KeyPathConverter(element.getProject());
-
- if(InstanceManager.get(element.getProject()).store().getData().getTranslation(converter.split(value)) == null) {
- if(!KeyReference.isReferencable(value)) { // Creation policy
- return PsiReference.EMPTY_ARRAY;
- }
- }
-
- return new PsiReference[] { new KeyReference(element, value) };
- }
- };
- }
-}
diff --git a/src/main/java/de/marhali/easyi18n/editor/kotlin/KotlinKeyAnnotator.java b/src/main/java/de/marhali/easyi18n/editor/kotlin/KotlinKeyAnnotator.java
deleted file mode 100644
index 4e9cfe3..0000000
--- a/src/main/java/de/marhali/easyi18n/editor/kotlin/KotlinKeyAnnotator.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package de.marhali.easyi18n.editor.kotlin;
-
-import com.intellij.lang.annotation.AnnotationHolder;
-import com.intellij.lang.annotation.Annotator;
-import com.intellij.psi.PsiElement;
-
-import de.marhali.easyi18n.editor.KeyAnnotator;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.kotlin.psi.KtLiteralStringTemplateEntry;
-
-/**
- * Kotlin specific translation key annotator
- * @author marhali
- */
-public class KotlinKeyAnnotator extends KeyAnnotator implements Annotator {
-
- @Override
- public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) {
- if(!(element instanceof KtLiteralStringTemplateEntry)) {
- return;
- }
-
- String value = element.getText();
-
- if(value == null) {
- return;
- }
-
- annotate(value, element.getProject(), holder);
- }
-}
\ No newline at end of file
diff --git a/src/main/java/de/marhali/easyi18n/editor/kotlin/KotlinKeyReferenceContributor.java b/src/main/java/de/marhali/easyi18n/editor/kotlin/KotlinKeyReferenceContributor.java
deleted file mode 100644
index bbb9203..0000000
--- a/src/main/java/de/marhali/easyi18n/editor/kotlin/KotlinKeyReferenceContributor.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package de.marhali.easyi18n.editor.kotlin;
-
-import com.intellij.patterns.PlatformPatterns;
-import com.intellij.psi.*;
-
-import com.intellij.util.ProcessingContext;
-
-import de.marhali.easyi18n.InstanceManager;
-import de.marhali.easyi18n.editor.KeyReference;
-import de.marhali.easyi18n.model.KeyPathConverter;
-import de.marhali.easyi18n.service.SettingsService;
-
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.kotlin.psi.KtLiteralStringTemplateEntry;
-import org.jetbrains.kotlin.psi.KtStringTemplateExpression;
-
-/**
- * Kotlin translation key reference contributor.
- * @author marhali
- */
-public class KotlinKeyReferenceContributor extends PsiReferenceContributor {
-
- @Override
- public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) {
- registrar.registerReferenceProvider(PlatformPatterns.psiElement().inside(KtStringTemplateExpression.class), getProvider());
- }
-
- private PsiReferenceProvider getProvider() {
- return new PsiReferenceProvider() {
- @Override
- public PsiReference @NotNull [] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) {
- String value = null;
-
- for (PsiElement child : element.getChildren()) {
- if(child instanceof KtLiteralStringTemplateEntry) {
- value = child.getText();
- }
- }
-
- if(value == null) {
- return PsiReference.EMPTY_ARRAY;
- }
-
- // Do not reference keys if service is disabled
- if(!SettingsService.getInstance(element.getProject()).getState().isCodeAssistance()) {
- return PsiReference.EMPTY_ARRAY;
- }
-
- KeyPathConverter converter = new KeyPathConverter(element.getProject());
-
- if(InstanceManager.get(element.getProject()).store().getData().getNode(converter.split(value)) == null) {
- return PsiReference.EMPTY_ARRAY;
- }
-
- return new PsiReference[] { new KeyReference(element, value) };
- }
- };
- }
-}
diff --git a/src/main/java/de/marhali/easyi18n/io/IOHandler.java b/src/main/java/de/marhali/easyi18n/io/IOHandler.java
index cebe902..dfdf6ab 100644
--- a/src/main/java/de/marhali/easyi18n/io/IOHandler.java
+++ b/src/main/java/de/marhali/easyi18n/io/IOHandler.java
@@ -9,6 +9,7 @@ import de.marhali.easyi18n.io.parser.ParserStrategy;
import de.marhali.easyi18n.io.parser.ParserStrategyType;
import de.marhali.easyi18n.model.*;
+import de.marhali.easyi18n.settings.ProjectSettings;
import org.jetbrains.annotations.NotNull;
import java.io.File;
@@ -21,23 +22,23 @@ import java.util.List;
*/
public class IOHandler {
- private final @NotNull SettingsState settings;
+ private final @NotNull ProjectSettings settings;
private final @NotNull FolderStrategy folderStrategy;
private final @NotNull ParserStrategyType parserStrategyType;
private final @NotNull ParserStrategy parserStrategy;
- public IOHandler(@NotNull SettingsState settings) throws Exception {
+ public IOHandler(@NotNull ProjectSettings settings) throws Exception {
this.settings = settings;
this.folderStrategy = settings.getFolderStrategy().getStrategy()
- .getDeclaredConstructor(SettingsState.class).newInstance(settings);
+ .getDeclaredConstructor(ProjectSettings.class).newInstance(settings);
this.parserStrategyType = settings.getParserStrategy();
this.parserStrategy = parserStrategyType.getStrategy()
- .getDeclaredConstructor(SettingsState.class).newInstance(settings);
+ .getDeclaredConstructor(ProjectSettings.class).newInstance(settings);
}
/**
@@ -47,7 +48,7 @@ public class IOHandler {
* @throws IOException Could not read translation data
*/
public @NotNull TranslationData read() throws IOException {
- String localesPath = this.settings.getLocalesPath();
+ String localesPath = this.settings.getLocalesDirectory();
if(localesPath == null || localesPath.isEmpty()) {
throw new EmptyLocalesDirException("Locales path must not be empty");
@@ -59,7 +60,7 @@ public class IOHandler {
throw new IllegalArgumentException("Specified locales path is invalid (" + localesPath + ")");
}
- TranslationData data = new TranslationData(this.settings.isSortKeys());
+ TranslationData data = new TranslationData(this.settings.isSorting());
List translationFiles = this.folderStrategy.analyzeFolderStructure(localesDirectory);
for(TranslationFile file : translationFiles) {
@@ -80,7 +81,7 @@ public class IOHandler {
* @throws IOException Write action failed
*/
public void write(@NotNull TranslationData data) throws IOException {
- String localesPath = this.settings.getLocalesPath();
+ String localesPath = this.settings.getLocalesDirectory();
if(localesPath == null || localesPath.isEmpty()) {
throw new EmptyLocalesDirException("Locales path must not be empty");
diff --git a/src/main/java/de/marhali/easyi18n/io/folder/FolderStrategy.java b/src/main/java/de/marhali/easyi18n/io/folder/FolderStrategy.java
index dbdd316..5e95367 100644
--- a/src/main/java/de/marhali/easyi18n/io/folder/FolderStrategy.java
+++ b/src/main/java/de/marhali/easyi18n/io/folder/FolderStrategy.java
@@ -4,10 +4,10 @@ import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import de.marhali.easyi18n.io.parser.ParserStrategyType;
-import de.marhali.easyi18n.model.SettingsState;
import de.marhali.easyi18n.model.TranslationData;
import de.marhali.easyi18n.model.TranslationFile;
+import de.marhali.easyi18n.settings.ProjectSettings;
import org.apache.commons.io.FilenameUtils;
import org.jetbrains.annotations.NotNull;
@@ -22,9 +22,9 @@ import java.util.Objects;
*/
public abstract class FolderStrategy {
- protected final @NotNull SettingsState settings;
+ protected final @NotNull ProjectSettings settings;
- public FolderStrategy(@NotNull SettingsState settings) {
+ public FolderStrategy(@NotNull ProjectSettings settings) {
this.settings = settings;
}
diff --git a/src/main/java/de/marhali/easyi18n/model/FolderStrategyType.java b/src/main/java/de/marhali/easyi18n/io/folder/FolderStrategyType.java
similarity index 52%
rename from src/main/java/de/marhali/easyi18n/model/FolderStrategyType.java
rename to src/main/java/de/marhali/easyi18n/io/folder/FolderStrategyType.java
index 14e81f3..047a563 100644
--- a/src/main/java/de/marhali/easyi18n/model/FolderStrategyType.java
+++ b/src/main/java/de/marhali/easyi18n/io/folder/FolderStrategyType.java
@@ -1,23 +1,24 @@
-package de.marhali.easyi18n.model;
-
-import de.marhali.easyi18n.io.folder.FolderStrategy;
-import de.marhali.easyi18n.io.folder.ModularLocaleFolderStrategy;
-import de.marhali.easyi18n.io.folder.ModularNamespaceFolderStrategy;
-import de.marhali.easyi18n.io.folder.SingleFolderStrategy;
+package de.marhali.easyi18n.io.folder;
/**
* Represents all supported folder strategies.
* @author marhali
*/
public enum FolderStrategyType {
- SINGLE(SingleFolderStrategy.class),
- MODULARIZED_LOCALE(ModularLocaleFolderStrategy.class),
- MODULARIZED_NAMESPACE(ModularNamespaceFolderStrategy.class);
+ SINGLE(SingleFolderStrategy.class, false),
+ MODULARIZED_LOCALE(ModularLocaleFolderStrategy.class, true),
+ MODULARIZED_NAMESPACE(ModularNamespaceFolderStrategy.class, true);
private final Class extends FolderStrategy> strategy;
+ private final boolean namespaceMode;
- FolderStrategyType(Class extends FolderStrategy> strategy) {
+ /**
+ * @param strategy Strategy implementation
+ * @param namespaceMode Does this strategy use namespaces?
+ */
+ FolderStrategyType(Class extends FolderStrategy> strategy, boolean namespaceMode) {
this.strategy = strategy;
+ this.namespaceMode = namespaceMode;
}
public Class extends FolderStrategy> getStrategy() {
@@ -38,6 +39,10 @@ public enum FolderStrategyType {
throw new NullPointerException();
}
+ public boolean isNamespaceMode() {
+ return namespaceMode;
+ }
+
public static FolderStrategyType fromIndex(int index) {
return values()[index];
}
diff --git a/src/main/java/de/marhali/easyi18n/io/folder/ModularLocaleFolderStrategy.java b/src/main/java/de/marhali/easyi18n/io/folder/ModularLocaleFolderStrategy.java
index e626827..651c9ea 100644
--- a/src/main/java/de/marhali/easyi18n/io/folder/ModularLocaleFolderStrategy.java
+++ b/src/main/java/de/marhali/easyi18n/io/folder/ModularLocaleFolderStrategy.java
@@ -3,9 +3,9 @@ package de.marhali.easyi18n.io.folder;
import com.intellij.openapi.vfs.VirtualFile;
import de.marhali.easyi18n.io.parser.ParserStrategyType;
-import de.marhali.easyi18n.model.SettingsState;
import de.marhali.easyi18n.model.TranslationData;
import de.marhali.easyi18n.model.TranslationFile;
+import de.marhali.easyi18n.settings.ProjectSettings;
import org.jetbrains.annotations.NotNull;
@@ -20,7 +20,7 @@ import java.util.List;
*/
public class ModularLocaleFolderStrategy extends FolderStrategy {
- public ModularLocaleFolderStrategy(@NotNull SettingsState settings) {
+ public ModularLocaleFolderStrategy(@NotNull ProjectSettings settings) {
super(settings);
}
diff --git a/src/main/java/de/marhali/easyi18n/io/folder/ModularNamespaceFolderStrategy.java b/src/main/java/de/marhali/easyi18n/io/folder/ModularNamespaceFolderStrategy.java
index 95b6fcd..fe8ffae 100644
--- a/src/main/java/de/marhali/easyi18n/io/folder/ModularNamespaceFolderStrategy.java
+++ b/src/main/java/de/marhali/easyi18n/io/folder/ModularNamespaceFolderStrategy.java
@@ -3,9 +3,9 @@ package de.marhali.easyi18n.io.folder;
import com.intellij.openapi.vfs.VirtualFile;
import de.marhali.easyi18n.io.parser.ParserStrategyType;
-import de.marhali.easyi18n.model.SettingsState;
import de.marhali.easyi18n.model.TranslationData;
import de.marhali.easyi18n.model.TranslationFile;
+import de.marhali.easyi18n.settings.ProjectSettings;
import org.jetbrains.annotations.NotNull;
@@ -20,7 +20,7 @@ import java.util.List;
*/
public class ModularNamespaceFolderStrategy extends FolderStrategy {
- public ModularNamespaceFolderStrategy(@NotNull SettingsState settings) {
+ public ModularNamespaceFolderStrategy(@NotNull ProjectSettings settings) {
super(settings);
}
diff --git a/src/main/java/de/marhali/easyi18n/io/folder/SingleFolderStrategy.java b/src/main/java/de/marhali/easyi18n/io/folder/SingleFolderStrategy.java
index 42260a6..4ac6371 100644
--- a/src/main/java/de/marhali/easyi18n/io/folder/SingleFolderStrategy.java
+++ b/src/main/java/de/marhali/easyi18n/io/folder/SingleFolderStrategy.java
@@ -3,9 +3,9 @@ package de.marhali.easyi18n.io.folder;
import com.intellij.openapi.vfs.VirtualFile;
import de.marhali.easyi18n.io.parser.ParserStrategyType;
-import de.marhali.easyi18n.model.SettingsState;
import de.marhali.easyi18n.model.TranslationData;
import de.marhali.easyi18n.model.TranslationFile;
+import de.marhali.easyi18n.settings.ProjectSettings;
import org.jetbrains.annotations.NotNull;
@@ -22,7 +22,7 @@ import java.util.List;
*/
public class SingleFolderStrategy extends FolderStrategy {
- public SingleFolderStrategy(@NotNull SettingsState settings) {
+ public SingleFolderStrategy(@NotNull ProjectSettings settings) {
super(settings);
}
diff --git a/src/main/java/de/marhali/easyi18n/io/parser/ParserStrategy.java b/src/main/java/de/marhali/easyi18n/io/parser/ParserStrategy.java
index 1678569..b94c0b3 100644
--- a/src/main/java/de/marhali/easyi18n/io/parser/ParserStrategy.java
+++ b/src/main/java/de/marhali/easyi18n/io/parser/ParserStrategy.java
@@ -2,6 +2,8 @@ package de.marhali.easyi18n.io.parser;
import de.marhali.easyi18n.model.*;
+import de.marhali.easyi18n.model.KeyPath;
+import de.marhali.easyi18n.settings.ProjectSettings;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
@@ -12,9 +14,9 @@ import java.util.Objects;
*/
public abstract class ParserStrategy {
- protected final @NotNull SettingsState settings;
+ protected final @NotNull ProjectSettings settings;
- public ParserStrategy(@NotNull SettingsState settings) {
+ public ParserStrategy(@NotNull ProjectSettings settings) {
this.settings = settings;
}
@@ -45,10 +47,10 @@ public abstract class ParserStrategy {
if(file.getNamespace() != null) {
String moduleName = file.getNamespace();
- TranslationNode moduleNode = data.getNode(KeyPath.of(moduleName));
+ TranslationNode moduleNode = data.getNode(new KeyPath(moduleName));
if(moduleNode == null) {
- moduleNode = new TranslationNode(this.settings.isSortKeys());
+ moduleNode = new TranslationNode(this.settings.isSorting());
data.getRootNode().setChildren(moduleName, moduleNode);
}
@@ -68,7 +70,7 @@ public abstract class ParserStrategy {
TranslationNode targetNode = data.getRootNode();
if(file.getNamespace() != null) {
- targetNode = data.getNode(KeyPath.of(file.getNamespace()));
+ targetNode = data.getNode(new KeyPath(file.getNamespace()));
}
return Objects.requireNonNull(targetNode);
diff --git a/src/main/java/de/marhali/easyi18n/io/parser/json/JsonMapper.java b/src/main/java/de/marhali/easyi18n/io/parser/json/JsonMapper.java
index bd4c1bf..328eae7 100644
--- a/src/main/java/de/marhali/easyi18n/io/parser/json/JsonMapper.java
+++ b/src/main/java/de/marhali/easyi18n/io/parser/json/JsonMapper.java
@@ -4,8 +4,8 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
-import de.marhali.easyi18n.model.Translation;
import de.marhali.easyi18n.model.TranslationNode;
+import de.marhali.easyi18n.model.TranslationValue;
import de.marhali.easyi18n.util.StringUtil;
import org.apache.commons.lang.StringEscapeUtils;
@@ -30,7 +30,7 @@ public class JsonMapper {
// Nested element - run recursively
read(locale, value.getAsJsonObject(), childNode);
} else {
- Translation translation = childNode.getValue();
+ TranslationValue translation = childNode.getValue();
String content = entry.getValue().isJsonArray()
? JsonArrayMapper.read(value.getAsJsonArray())
@@ -55,7 +55,7 @@ public class JsonMapper {
json.add(key, childJson);
}
} else {
- Translation translation = childNode.getValue();
+ TranslationValue translation = childNode.getValue();
String content = translation.get(locale);
if(content != null) {
diff --git a/src/main/java/de/marhali/easyi18n/io/parser/json/JsonParserStrategy.java b/src/main/java/de/marhali/easyi18n/io/parser/json/JsonParserStrategy.java
index a765547..f47ac76 100644
--- a/src/main/java/de/marhali/easyi18n/io/parser/json/JsonParserStrategy.java
+++ b/src/main/java/de/marhali/easyi18n/io/parser/json/JsonParserStrategy.java
@@ -3,14 +3,15 @@ package de.marhali.easyi18n.io.parser.json;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
+
import com.intellij.openapi.vfs.VirtualFile;
import de.marhali.easyi18n.io.parser.ParserStrategy;
import de.marhali.easyi18n.model.*;
+import de.marhali.easyi18n.settings.ProjectSettings;
import org.jetbrains.annotations.NotNull;
-import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Objects;
@@ -23,7 +24,7 @@ public class JsonParserStrategy extends ParserStrategy {
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
- public JsonParserStrategy(@NotNull SettingsState settings) {
+ public JsonParserStrategy(@NotNull ProjectSettings settings) {
super(settings);
}
diff --git a/src/main/java/de/marhali/easyi18n/io/parser/json5/Json5Mapper.java b/src/main/java/de/marhali/easyi18n/io/parser/json5/Json5Mapper.java
index 80b36ae..dc6bdfe 100644
--- a/src/main/java/de/marhali/easyi18n/io/parser/json5/Json5Mapper.java
+++ b/src/main/java/de/marhali/easyi18n/io/parser/json5/Json5Mapper.java
@@ -1,12 +1,12 @@
package de.marhali.easyi18n.io.parser.json5;
-import de.marhali.easyi18n.model.Translation;
import de.marhali.easyi18n.model.TranslationNode;
+import de.marhali.easyi18n.model.TranslationValue;
import de.marhali.easyi18n.util.StringUtil;
-
import de.marhali.json5.Json5Element;
import de.marhali.json5.Json5Object;
import de.marhali.json5.Json5Primitive;
+
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.math.NumberUtils;
@@ -28,7 +28,7 @@ public class Json5Mapper {
// Nested element - run recursively
read(locale, value.getAsJson5Object(), childNode);
} else {
- Translation translation = childNode.getValue();
+ TranslationValue translation = childNode.getValue();
String content = value.isJson5Array()
? Json5ArrayMapper.read(value.getAsJson5Array())
@@ -54,7 +54,7 @@ public class Json5Mapper {
}
} else {
- Translation translation = childNode.getValue();
+ TranslationValue translation = childNode.getValue();
String content = translation.get(locale);
if(content != null) {
if(Json5ArrayMapper.isArray(content)) {
diff --git a/src/main/java/de/marhali/easyi18n/io/parser/json5/Json5ParserStrategy.java b/src/main/java/de/marhali/easyi18n/io/parser/json5/Json5ParserStrategy.java
index cb9c64b..97965b9 100644
--- a/src/main/java/de/marhali/easyi18n/io/parser/json5/Json5ParserStrategy.java
+++ b/src/main/java/de/marhali/easyi18n/io/parser/json5/Json5ParserStrategy.java
@@ -3,10 +3,10 @@ package de.marhali.easyi18n.io.parser.json5;
import com.intellij.openapi.vfs.VirtualFile;
import de.marhali.easyi18n.io.parser.ParserStrategy;
-import de.marhali.easyi18n.model.SettingsState;
import de.marhali.easyi18n.model.TranslationData;
import de.marhali.easyi18n.model.TranslationFile;
import de.marhali.easyi18n.model.TranslationNode;
+import de.marhali.easyi18n.settings.ProjectSettings;
import de.marhali.json5.Json5;
import de.marhali.json5.Json5Element;
import de.marhali.json5.Json5Object;
@@ -26,7 +26,7 @@ public class Json5ParserStrategy extends ParserStrategy {
private static final Json5 JSON5 = Json5.builder(builder ->
builder.allowInvalidSurrogate().trailingComma().indentFactor(4).build());
- public Json5ParserStrategy(@NotNull SettingsState settings) {
+ public Json5ParserStrategy(@NotNull ProjectSettings settings) {
super(settings);
}
diff --git a/src/main/java/de/marhali/easyi18n/io/parser/properties/PropertiesMapper.java b/src/main/java/de/marhali/easyi18n/io/parser/properties/PropertiesMapper.java
index 0ae62b2..2cac6ae 100644
--- a/src/main/java/de/marhali/easyi18n/io/parser/properties/PropertiesMapper.java
+++ b/src/main/java/de/marhali/easyi18n/io/parser/properties/PropertiesMapper.java
@@ -1,8 +1,9 @@
package de.marhali.easyi18n.io.parser.properties;
-import de.marhali.easyi18n.model.KeyPath;
-import de.marhali.easyi18n.model.Translation;
import de.marhali.easyi18n.model.TranslationData;
+import de.marhali.easyi18n.model.KeyPath;
+import de.marhali.easyi18n.model.TranslationValue;
+import de.marhali.easyi18n.util.KeyPathConverter;
import de.marhali.easyi18n.util.StringUtil;
import org.apache.commons.lang.StringEscapeUtils;
@@ -16,15 +17,17 @@ import java.util.Map;
*/
public class PropertiesMapper {
- public static void read(String locale, SortableProperties properties, TranslationData data) {
+ public static void read(String locale, SortableProperties properties,
+ TranslationData data, KeyPathConverter converter) {
+
for(Map.Entry