Skip to content

Commit d887b6b

Browse files
committed
#1940 add translation support for TranslatableMessage class
1 parent 7d69d0f commit d887b6b

11 files changed

+272
-36
lines changed

src/main/java/fr/adrienbrault/idea/symfony2plugin/translation/PhpTranslationDomainInspection.java

+14-17
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@
55
import com.intellij.codeInspection.ProblemsHolder;
66
import com.intellij.psi.PsiElement;
77
import com.intellij.psi.PsiElementVisitor;
8-
import com.jetbrains.php.lang.psi.elements.MethodReference;
9-
import com.jetbrains.php.lang.psi.elements.ParameterList;
10-
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
8+
import com.jetbrains.php.lang.psi.elements.*;
119
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
1210
import fr.adrienbrault.idea.symfony2plugin.translation.dict.TranslationUtil;
1311
import fr.adrienbrault.idea.symfony2plugin.translation.inspection.TranslationDomainGuessTypoQuickFix;
@@ -48,23 +46,22 @@ private void invoke(@NotNull ProblemsHolder holder, @NotNull PsiElement psiEleme
4846

4947
ParameterList parameterList = (ParameterList) psiElement.getContext();
5048

49+
int domainParameter = -1;
5150
PsiElement methodReference = parameterList.getContext();
52-
if (!(methodReference instanceof MethodReference)) {
53-
return;
54-
}
55-
56-
if (!PhpElementsUtil.isMethodReferenceInstanceOf((MethodReference) methodReference, TranslationUtil.PHP_TRANSLATION_SIGNATURES)) {
57-
return;
58-
}
59-
60-
int domainParameter = 2;
61-
if("transChoice".equals(((MethodReference) methodReference).getName())) {
62-
domainParameter = 3;
51+
if (methodReference instanceof MethodReference && PhpElementsUtil.isMethodReferenceInstanceOf((MethodReference) methodReference, TranslationUtil.PHP_TRANSLATION_SIGNATURES)) {
52+
domainParameter = 2;
53+
if("transChoice".equals(((MethodReference) methodReference).getName())) {
54+
domainParameter = 3;
55+
}
56+
} else if(methodReference instanceof NewExpression && PhpElementsUtil.isNewExpressionPhpClassWithInstance((NewExpression) methodReference, TranslationUtil.PHP_TRANSLATION_TRANSLATABLE_MESSAGE)) {
57+
domainParameter = 2;
6358
}
6459

65-
ParameterBag currentIndex = PsiElementUtils.getCurrentParameterIndex(psiElement);
66-
if(currentIndex != null && currentIndex.getIndex() == domainParameter) {
67-
annotateTranslationDomain((StringLiteralExpression) psiElement, holder);
60+
if (domainParameter >= 0) {
61+
ParameterBag currentIndex = PsiElementUtils.getCurrentParameterIndex(psiElement);
62+
if(currentIndex != null && currentIndex.getIndex() == domainParameter) {
63+
annotateTranslationDomain((StringLiteralExpression) psiElement, holder);
64+
}
6865
}
6966
}
7067

src/main/java/fr/adrienbrault/idea/symfony2plugin/translation/PhpTranslationKeyInspection.java

+11-8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.intellij.psi.PsiElement;
66
import com.intellij.psi.PsiElementVisitor;
77
import com.jetbrains.php.lang.psi.elements.MethodReference;
8+
import com.jetbrains.php.lang.psi.elements.NewExpression;
89
import com.jetbrains.php.lang.psi.elements.ParameterList;
910
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
1011
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
@@ -46,12 +47,19 @@ private void invoke(@NotNull ProblemsHolder holder, @NotNull PsiElement psiEleme
4647
}
4748

4849
ParameterList parameterList = (ParameterList) psiElement.getContext();
50+
51+
int domainParameter = -1;
4952
PsiElement methodReference = parameterList.getContext();
50-
if (!(methodReference instanceof MethodReference)) {
51-
return;
53+
if (methodReference instanceof MethodReference && PhpElementsUtil.isMethodReferenceInstanceOf((MethodReference) methodReference, TranslationUtil.PHP_TRANSLATION_SIGNATURES)) {
54+
domainParameter = 2;
55+
if("transChoice".equals(((MethodReference) methodReference).getName())) {
56+
domainParameter = 3;
57+
}
58+
} else if(methodReference instanceof NewExpression && PhpElementsUtil.isNewExpressionPhpClassWithInstance((NewExpression) methodReference, TranslationUtil.PHP_TRANSLATION_TRANSLATABLE_MESSAGE)) {
59+
domainParameter = 2;
5260
}
5361

54-
if (!PhpElementsUtil.isMethodReferenceInstanceOf((MethodReference) methodReference, TranslationUtil.PHP_TRANSLATION_SIGNATURES)) {
62+
if (domainParameter < 0) {
5563
return;
5664
}
5765

@@ -60,11 +68,6 @@ private void invoke(@NotNull ProblemsHolder holder, @NotNull PsiElement psiEleme
6068
return;
6169
}
6270

63-
int domainParameter = 2;
64-
if("transChoice".equals(((MethodReference) methodReference).getName())) {
65-
domainParameter = 3;
66-
}
67-
6871
PsiElement domainElement = PsiElementUtils.getMethodParameterPsiElementAt(parameterList, domainParameter);
6972

7073
if(domainElement == null) {

src/main/java/fr/adrienbrault/idea/symfony2plugin/translation/TranslationPlaceholderGotoCompletionRegistrar.java

+71
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
import com.intellij.codeInsight.lookup.LookupElementBuilder;
55
import com.intellij.patterns.PlatformPatterns;
66
import com.intellij.psi.PsiElement;
7+
import com.jetbrains.php.lang.psi.elements.ArrayCreationExpression;
8+
import com.jetbrains.php.lang.psi.elements.NewExpression;
9+
import com.jetbrains.php.lang.psi.elements.ParameterList;
710
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
811
import com.jetbrains.twig.elements.TwigElementTypes;
912
import fr.adrienbrault.idea.symfony2plugin.Symfony2Icons;
@@ -15,6 +18,7 @@
1518
import fr.adrienbrault.idea.symfony2plugin.templating.util.TwigUtil;
1619
import fr.adrienbrault.idea.symfony2plugin.translation.dict.TranslationUtil;
1720
import fr.adrienbrault.idea.symfony2plugin.util.MethodMatcher;
21+
import fr.adrienbrault.idea.symfony2plugin.util.ParameterBag;
1822
import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
1923
import fr.adrienbrault.idea.symfony2plugin.util.PsiElementUtils;
2024
import org.apache.commons.lang.StringUtils;
@@ -54,6 +58,12 @@ public void register(@NotNull GotoCompletionRegistrarParameter registrar) {
5458
PlatformPatterns.psiElement().withParent(StringLiteralExpression.class),
5559
new MyPhpTranslationCompletionContributor("transChoice", 2, 3)
5660
);
61+
62+
// $x->trans('symfony.great', ['%fo<caret>obar%', null], 'symfony')
63+
registrar.register(
64+
PlatformPatterns.psiElement().withParent(StringLiteralExpression.class),
65+
new MyPhpTranslateableMessageCompletionContributor()
66+
);
5767
}
5868

5969
private static class MyTranslationPlaceholderGotoCompletionProvider extends GotoCompletionProvider {
@@ -131,6 +141,67 @@ public GotoCompletionProvider getProvider(@NotNull PsiElement psiElement) {
131141
}
132142
}
133143

144+
/**
145+
* new \Symfony\Component\Translation\TranslatableMessage('symfony.great', ['test' => '%fo<caret>obar%'], 'symfony');
146+
* new \Symfony\Component\Translation\TranslatableMessage('symfony.great', ['%fo<caret>obar%', null], 'symfony');
147+
*/
148+
private static class MyPhpTranslateableMessageCompletionContributor implements GotoCompletionContributor {
149+
@Nullable
150+
@Override
151+
public GotoCompletionProvider getProvider(@NotNull PsiElement psiElement) {
152+
PsiElement context = psiElement.getContext();
153+
if (!(context instanceof StringLiteralExpression)) {
154+
return null;
155+
}
156+
157+
ArrayCreationExpression arrayCreationExpression = PhpElementsUtil.getCompletableArrayCreationElement(context);
158+
if (arrayCreationExpression == null) {
159+
return null;
160+
}
161+
162+
PsiElement parameterList = arrayCreationExpression.getContext();
163+
if (!(parameterList instanceof ParameterList)) {
164+
return null;
165+
}
166+
167+
PsiElement[] parameters = ((ParameterList) parameterList).getParameters();
168+
int placeHolderParameter = 1;
169+
if (parameters.length < placeHolderParameter) {
170+
return null;
171+
}
172+
173+
PsiElement newEx = parameterList.getContext();
174+
if (!(newEx instanceof NewExpression)) {
175+
return null;
176+
}
177+
178+
ParameterBag currentIndex = PsiElementUtils.getCurrentParameterIndex(arrayCreationExpression);
179+
if (currentIndex == null || currentIndex.getIndex() != placeHolderParameter) {
180+
return null;
181+
}
182+
183+
if (!PhpElementsUtil.isNewExpressionPhpClassWithInstance((NewExpression) newEx, TranslationUtil.PHP_TRANSLATION_TRANSLATABLE_MESSAGE)) {
184+
return null;
185+
}
186+
187+
String key = PhpElementsUtil.getStringValue(parameters[0]);
188+
if (key == null) {
189+
return null;
190+
}
191+
192+
String domain = "messages";
193+
int domainParameter = 2;
194+
if (parameters.length > domainParameter) {
195+
domain = PhpElementsUtil.getStringValue(parameters[domainParameter]);
196+
if(domain == null) {
197+
return null;
198+
}
199+
}
200+
201+
return new MyTranslationPlaceholderGotoCompletionProvider(psiElement, key, domain);
202+
}
203+
}
204+
134205
/**
135206
* {{ 'symfony.great'|trans({'fo<caret>f'}, 'symfony')) }}
136207
*/

src/main/java/fr/adrienbrault/idea/symfony2plugin/translation/TranslationReferenceContributor.java

+12-9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.intellij.psi.*;
55
import com.intellij.util.ProcessingContext;
66
import com.jetbrains.php.lang.psi.elements.MethodReference;
7+
import com.jetbrains.php.lang.psi.elements.NewExpression;
78
import com.jetbrains.php.lang.psi.elements.ParameterList;
89
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
910
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
@@ -26,24 +27,26 @@ public void registerReferenceProviders(PsiReferenceRegistrar psiReferenceRegistr
2627
new PsiReferenceProvider() {
2728
@NotNull
2829
@Override
29-
public PsiReference[] getReferencesByElement(@NotNull PsiElement psiElement, @NotNull ProcessingContext processingContext) {
30+
public PsiReference @NotNull [] getReferencesByElement(@NotNull PsiElement psiElement, @NotNull ProcessingContext processingContext) {
3031
if (!Symfony2ProjectComponent.isEnabled(psiElement) || !(psiElement.getContext() instanceof ParameterList)) {
3132
return new PsiReference[0];
3233
}
3334

3435
ParameterList parameterList = (ParameterList) psiElement.getContext();
3536
PsiElement methodReference = parameterList.getContext();
36-
if (!(methodReference instanceof MethodReference)) {
37-
return new PsiReference[0];
38-
}
3937

40-
if (!PhpElementsUtil.isMethodReferenceInstanceOf((MethodReference) methodReference, TranslationUtil.PHP_TRANSLATION_SIGNATURES)) {
41-
return new PsiReference[0];
38+
int domainParameter = -1;
39+
if (methodReference instanceof MethodReference && PhpElementsUtil.isMethodReferenceInstanceOf((MethodReference) methodReference, TranslationUtil.PHP_TRANSLATION_SIGNATURES)) {
40+
domainParameter = 2;
41+
if("transChoice".equals(((MethodReference) methodReference).getName())) {
42+
domainParameter = 3;
43+
}
44+
} else if(methodReference instanceof NewExpression && PhpElementsUtil.isNewExpressionPhpClassWithInstance((NewExpression) methodReference, TranslationUtil.PHP_TRANSLATION_TRANSLATABLE_MESSAGE)) {
45+
domainParameter = 2;
4246
}
4347

44-
int domainParameter = 2;
45-
if("transChoice".equals(((MethodReference) methodReference).getName())) {
46-
domainParameter = 3;
48+
if (domainParameter < 0) {
49+
return new PsiReference[0];
4750
}
4851

4952
ParameterBag currentIndex = PsiElementUtils.getCurrentParameterIndex(psiElement);

src/main/java/fr/adrienbrault/idea/symfony2plugin/translation/dict/TranslationUtil.java

+2
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ public class TranslationUtil {
7373
new MethodMatcher.CallToSignature("\\Symfony\\Bundle\\FrameworkBundle\\Templating\\Helper\\TranslatorHelper", "transChoice")
7474
};
7575

76+
public static final String PHP_TRANSLATION_TRANSLATABLE_MESSAGE = "\\Symfony\\Component\\Translation\\TranslatableMessage";
77+
7678
private static final String[] XLIFF_XPATH = {
7779
"//xliff/file/body/trans-unit/source",
7880
"//xliff/file/group/unit/segment/source",

src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/translation/PhpTranslationDomainInspectionTest.java

+17
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,21 @@ public void testThatPhpTranslationDomainInspectionsAreProvided() {
4949
PhpTranslationDomainInspection.MESSAGE
5050
);
5151
}
52+
53+
public void testThatPhpTranslationDomainInspectionsForTranslatableMessageAreProvided() {
54+
assertLocalInspectionContains("test.php", "<?php\n" +
55+
"new \\Symfony\\Component\\Translation\\TranslatableMessage('foobar', [], 'do<caret>main');",
56+
PhpTranslationDomainInspection.MESSAGE
57+
);
58+
59+
assertLocalInspectionContains("test.php", "<?php\n" +
60+
"new \\Symfony\\Component\\Translation\\TranslatableMessage('foobar', [], 'foo<caret>bar');",
61+
PhpTranslationDomainInspection.MESSAGE
62+
);
63+
64+
assertLocalInspectionNotContains("test.php", "<?php\n" +
65+
"new \\Symfony\\Component\\Translation\\TranslatableMessage('foobar', [], 'sym<caret>fony');",
66+
PhpTranslationDomainInspection.MESSAGE
67+
);
68+
}
5269
}

src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/translation/PhpTranslationKeyInspectionTest.java

+18
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package fr.adrienbrault.idea.symfony2plugin.tests.translation;
22

33
import fr.adrienbrault.idea.symfony2plugin.tests.SymfonyLightCodeInsightFixtureTestCase;
4+
import fr.adrienbrault.idea.symfony2plugin.translation.PhpTranslationDomainInspection;
45
import fr.adrienbrault.idea.symfony2plugin.translation.PhpTranslationKeyInspection;
56

67
/**
@@ -96,4 +97,21 @@ public void testThatPhpTransInspectionsAreNotProvidedForKnownTranslations() {
9697
PhpTranslationKeyInspection.MESSAGE
9798
);
9899
}
100+
101+
public void testThatPhpTranslationKeyInspectionsForTranslatableMessageAreProvided() {
102+
assertLocalInspectionContains("test.php", "<?php\n" +
103+
"new \\Symfony\\Component\\Translation\\TranslatableMessage('symfon<caret>y.great');",
104+
PhpTranslationKeyInspection.MESSAGE
105+
);
106+
107+
assertLocalInspectionNotContains("test.php", "<?php\n" +
108+
"new \\Symfony\\Component\\Translation\\TranslatableMessage('symfon<caret>y.great', [], 'symfony');",
109+
PhpTranslationKeyInspection.MESSAGE
110+
);
111+
112+
assertLocalInspectionNotContains("test.php", "<?php\n" +
113+
"new \\Symfony\\Component\\Translation\\TranslatableMessage('symfon<caret>y.great', 1, [], $x);",
114+
PhpTranslationKeyInspection.MESSAGE
115+
);
116+
}
99117
}

src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/translation/TranslationPlaceholderGotoCompletionRegistrarTest.java

+41
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
public class TranslationPlaceholderGotoCompletionRegistrarTest extends SymfonyLightCodeInsightFixtureTestCase {
1313
public void setUp() throws Exception {
1414
super.setUp();
15+
myFixture.copyFileToProject("messages.de.yml", "Resources/translations/messages.de.yml");
1516
myFixture.copyFileToProject("symfony.de.yml", "Resources/translations/symfony.de.yml");
1617
myFixture.copyFileToProject("TranslationPlaceholderGotoCompletionRegistrar.php");
1718
}
@@ -127,4 +128,44 @@ public void testNavigationForPhpTransChoicePlaceholder() {
127128
PlatformPatterns.psiElement()
128129
);
129130
}
131+
132+
public void testCompletionForPhpTranslatableMessagePlaceholder() {
133+
assertCompletionContains(
134+
PhpFileType.INSTANCE,"<?php\n" +
135+
"new \\Symfony\\Component\\Translation\\TranslatableMessage('symfony.great', ['<caret>'], 'symfony');",
136+
"%foobar%"
137+
);
138+
139+
assertCompletionContains(
140+
PhpFileType.INSTANCE,"<?php\n" +
141+
"new \\Symfony\\Component\\Translation\\TranslatableMessage('symfony.great', ['<caret>', null], 'symfony');",
142+
"%foobar%"
143+
);
144+
145+
assertCompletionContains(
146+
PhpFileType.INSTANCE,"<?php\n" +
147+
"new \\Symfony\\Component\\Translation\\TranslatableMessage('symfony_message', ['<caret>']);",
148+
"%foobar%"
149+
);
150+
151+
assertCompletionContains(
152+
PhpFileType.INSTANCE,"<?php\n" +
153+
"new \\Symfony\\Component\\Translation\\TranslatableMessage('symfony_message', ['<caret>' => 'a']);",
154+
"%foobar%"
155+
);
156+
}
157+
158+
public void testNavigationForPhpTranslatableMessagePlaceholder() {
159+
assertNavigationMatch(
160+
PhpFileType.INSTANCE,"<?php\n" +
161+
"new \\Symfony\\Component\\Translation\\TranslatableMessage('symfony.great', ['%fo<caret>obar%'], 'symfony');",
162+
PlatformPatterns.psiElement()
163+
);
164+
165+
assertNavigationMatch(
166+
PhpFileType.INSTANCE,"<?php\n" +
167+
"new \\Symfony\\Component\\Translation\\TranslatableMessage('symfony.great', ['%fo<caret>obar%', null], 'symfony');",
168+
PlatformPatterns.psiElement()
169+
);
170+
}
130171
}

0 commit comments

Comments
 (0)