package fr.adrienbrault.idea.symfony2plugin.translation; import com.intellij.lang.annotation.Annotation; import com.intellij.lang.annotation.AnnotationHolder; import com.intellij.lang.annotation.Annotator; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.jetbrains.php.lang.psi.elements.MethodReference; import com.jetbrains.php.lang.psi.elements.ParameterList; import com.jetbrains.php.lang.psi.elements.StringLiteralExpression; import fr.adrienbrault.idea.symfony2plugin.Settings; import fr.adrienbrault.idea.symfony2plugin.Symfony2InterfacesUtil; import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent; import fr.adrienbrault.idea.symfony2plugin.translation.dict.TranslationUtil; import fr.adrienbrault.idea.symfony2plugin.util.ParameterBag; import fr.adrienbrault.idea.symfony2plugin.util.PsiElementUtils; import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.yaml.psi.YAMLFile; import java.util.List; /** * @author Daniel Espendiller <daniel@espendiller.net> */ public class PhpTranslationAnnotator implements Annotator { @Override public void annotate(@NotNull final PsiElement psiElement, @NotNull AnnotationHolder holder) { if (!Symfony2ProjectComponent.isEnabled(psiElement) || !Settings.getInstance(psiElement.getProject()).phpAnnotateTranslation || !(psiElement instanceof StringLiteralExpression) || !(psiElement.getContext() instanceof ParameterList) ) { return; } ParameterList parameterList = (ParameterList) psiElement.getContext(); if (parameterList == null || !(parameterList.getContext() instanceof MethodReference)) { return; } MethodReference method = (MethodReference) parameterList.getContext(); Symfony2InterfacesUtil interfacesUtil = new Symfony2InterfacesUtil(); if (!interfacesUtil.isTranslatorCall(method)) { return; } int domainParameter = 2; if(method.getName().equals("transChoice")) { domainParameter = 3; } ParameterBag currentIndex = PsiElementUtils.getCurrentParameterIndex(psiElement); if(currentIndex == null) { return; } if(currentIndex.getIndex() == domainParameter) { annotateTranslationDomain((StringLiteralExpression) psiElement, holder); return; } if(currentIndex.getIndex() == 0) { PsiElement domainElement = PsiElementUtils.getMethodParameterPsiElementAt(parameterList, domainParameter); // only support string values if(domainElement instanceof StringLiteralExpression) { String domain = PsiElementUtils.getMethodParameterAt(parameterList, domainParameter); if(domain == null) { domain = "messages"; } annotateTranslationKey((StringLiteralExpression) psiElement, domain, holder); } else if (domainElement == null) { annotateTranslationKey((StringLiteralExpression) psiElement, "messages", holder); } } } private void annotateTranslationKey(StringLiteralExpression psiElement, String domainName, @NotNull AnnotationHolder holder) { String keyName = psiElement.getContents(); // should not annotate "foo$bar" // @TODO: regular expression to only notice translation keys and not possible text values if(keyName.contains("$")) { return; } // dont annotate non goto available keys if(TranslationUtil.hasTranslationKey(psiElement.getProject(), keyName, domainName)) { return; } // search for possible domain targets and provide translation key creation fix if(StringUtils.isNotBlank(keyName) && !TranslationUtil.hasTranslationKey(psiElement.getProject(), keyName, domainName)) { Annotation annotationHolder = holder.createWarningAnnotation(psiElement, "Missing Translation"); List<PsiFile> psiElements = TranslationUtil.getDomainPsiFiles(psiElement.getProject(), domainName); for(PsiElement psiFile: psiElements) { if(psiFile instanceof YAMLFile) { annotationHolder.registerFix(new TranslationKeyIntentionAction((YAMLFile) psiFile, keyName)); } } } } private void annotateTranslationDomain(StringLiteralExpression psiElement, @NotNull AnnotationHolder holder) { String contents = psiElement.getContents(); if(StringUtils.isBlank(contents) || TranslationUtil.hasDomain(psiElement.getProject(), contents)) { return; } holder.createWarningAnnotation(psiElement, "Missing Translation Domain"); } }