diff --git a/CHANGELOG.md b/CHANGELOG.md index 809e660..13285d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ## [Unreleased] ### Added - Support for YAML locale files. Thanks to @sunarya-thito +- Translation key referencing inside editor - Optional path-prefix for translations ### Changed diff --git a/src/main/java/de/marhali/easyi18n/editor/KeyReference.java b/src/main/java/de/marhali/easyi18n/editor/KeyReference.java new file mode 100644 index 0000000..1a8ea02 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/editor/KeyReference.java @@ -0,0 +1,85 @@ +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.dialog.AddDialog; +import de.marhali.easyi18n.dialog.EditDialog; +import de.marhali.easyi18n.model.KeyedTranslation; +import de.marhali.easyi18n.model.LocalizedNode; +import de.marhali.easyi18n.service.DataStore; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +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) { + LocalizedNode node = DataStore.getInstance(getProject()).getTranslations().getNode(getKey()); + + if(node != null) { + new EditDialog(getProject(), new KeyedTranslation(getKey(), node.getValue())).showAndHandle(); + } else { + new AddDialog(getProject(), getKey()).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/GenericKeyReferenceContributor.java b/src/main/java/de/marhali/easyi18n/editor/generic/GenericKeyReferenceContributor.java new file mode 100644 index 0000000..960f6fb --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/editor/generic/GenericKeyReferenceContributor.java @@ -0,0 +1,51 @@ +package de.marhali.easyi18n.editor.generic; + +import com.intellij.patterns.PlatformPatterns; +import com.intellij.psi.*; +import com.intellij.util.ProcessingContext; + +import de.marhali.easyi18n.editor.KeyReference; +import de.marhali.easyi18n.service.DataStore; +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; + } + + if(DataStore.getInstance(element.getProject()).getTranslations().getNode(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/KotlinKeyReferenceContributor.java b/src/main/java/de/marhali/easyi18n/editor/kotlin/KotlinKeyReferenceContributor.java new file mode 100644 index 0000000..e871fc9 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/editor/kotlin/KotlinKeyReferenceContributor.java @@ -0,0 +1,56 @@ +package de.marhali.easyi18n.editor.kotlin; + +import com.intellij.patterns.PlatformPatterns; +import com.intellij.psi.*; + +import com.intellij.util.ProcessingContext; + +import de.marhali.easyi18n.editor.KeyReference; +import de.marhali.easyi18n.service.DataStore; +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; + } + + if(DataStore.getInstance(element.getProject()).getTranslations().getNode(value) == null) { + return PsiReference.EMPTY_ARRAY; + } + + return new PsiReference[] { new KeyReference(element, value) }; + } + }; + } +} diff --git a/src/main/resources/META-INF/de.marhali.easyi18n-kotlin.xml b/src/main/resources/META-INF/de.marhali.easyi18n-kotlin.xml index 441c647..fe81e94 100644 --- a/src/main/resources/META-INF/de.marhali.easyi18n-kotlin.xml +++ b/src/main/resources/META-INF/de.marhali.easyi18n-kotlin.xml @@ -4,5 +4,8 @@ + + \ No newline at end of file diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index a452e0e..598db67 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -17,5 +17,7 @@ implementationClass="de.marhali.easyi18n.editor.generic.GenericKeyCompletionContributor" /> + + \ No newline at end of file diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index 2fee2ba..2be4dcf 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -16,4 +16,4 @@ settings.path.text=Locales directory settings.path.file-pattern=Translation file pattern settings.path.prefix=Path prefix settings.preview=Preview locale -settings.editor.assistance=I18n key completion and annotation inside editor \ No newline at end of file +settings.editor.assistance=I18n key completion, annotation and reference inside editor \ No newline at end of file