add translation key referencing inside editor

This commit is contained in:
Marcel Haßlinger 2021-09-22 11:50:11 +02:00
parent 45cae6e7ae
commit 562266f9c0
7 changed files with 199 additions and 1 deletions

View File

@ -5,6 +5,7 @@
## [Unreleased] ## [Unreleased]
### Added ### Added
- Support for YAML locale files. Thanks to @sunarya-thito - Support for YAML locale files. Thanks to @sunarya-thito
- Translation key referencing inside editor
- Optional path-prefix for translations - Optional path-prefix for translations
### Changed ### Changed

View File

@ -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<PsiElement> {
@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:/]+$");
}
}

View File

@ -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) };
}
};
}
}

View File

@ -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) };
}
};
}
}

View File

@ -4,5 +4,8 @@
<completion.contributor language="kotlin" <completion.contributor language="kotlin"
implementationClass="de.marhali.easyi18n.editor.kotlin.KotlinKeyCompletionContributor" /> implementationClass="de.marhali.easyi18n.editor.kotlin.KotlinKeyCompletionContributor" />
<psi.referenceContributor language="kotlin"
implementation="de.marhali.easyi18n.editor.kotlin.KotlinKeyReferenceContributor" />
</extensions> </extensions>
</idea-plugin> </idea-plugin>

View File

@ -17,5 +17,7 @@
implementationClass="de.marhali.easyi18n.editor.generic.GenericKeyCompletionContributor" /> implementationClass="de.marhali.easyi18n.editor.generic.GenericKeyCompletionContributor" />
<annotator language="" implementationClass="de.marhali.easyi18n.editor.generic.GenericKeyAnnotator" /> <annotator language="" implementationClass="de.marhali.easyi18n.editor.generic.GenericKeyAnnotator" />
<psi.referenceContributor implementation="de.marhali.easyi18n.editor.generic.GenericKeyReferenceContributor" />
</extensions> </extensions>
</idea-plugin> </idea-plugin>

View File

@ -16,4 +16,4 @@ settings.path.text=Locales directory
settings.path.file-pattern=Translation file pattern settings.path.file-pattern=Translation file pattern
settings.path.prefix=Path prefix settings.path.prefix=Path prefix
settings.preview=Preview locale settings.preview=Preview locale
settings.editor.assistance=I18n key completion and annotation inside editor settings.editor.assistance=I18n key completion, annotation and reference inside editor