Skip to content

Commit 8bab245

Browse files
committed
add XLIFF navigation support if extension is defined as XmlFile #479, #712
1 parent 090d5ae commit 8bab245

File tree

2 files changed

+117
-9
lines changed

2 files changed

+117
-9
lines changed

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

+60-9
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
import com.intellij.psi.PsiManager;
1010
import com.intellij.psi.search.GlobalSearchScope;
1111
import com.intellij.psi.util.PsiTreeUtil;
12-
import com.intellij.util.Processor;
12+
import com.intellij.psi.xml.XmlFile;
13+
import com.intellij.psi.xml.XmlTag;
14+
import com.intellij.util.Consumer;
1315
import com.intellij.util.indexing.FileBasedIndexImpl;
1416
import com.jetbrains.php.PhpIndex;
1517
import fr.adrienbrault.idea.symfony2plugin.stubs.SymfonyProcessors;
@@ -43,6 +45,7 @@
4345
import java.io.IOException;
4446
import java.io.InputStream;
4547
import java.util.*;
48+
import java.util.stream.Collectors;
4649

4750
public class TranslationUtil {
4851

@@ -108,7 +111,7 @@ public static PsiElement[] getTranslationPsiElements(final Project project, fina
108111
return true;
109112
};
110113

111-
FileBasedIndexImpl.getInstance().getFilesWithKey(YamlTranslationStubIndex.KEY, new HashSet<>(Arrays.asList(domain)), virtualFile -> {
114+
FileBasedIndexImpl.getInstance().getFilesWithKey(YamlTranslationStubIndex.KEY, new HashSet<>(Collections.singletonList(domain)), virtualFile -> {
112115
// prevent duplicate targets and dont walk same file twice
113116
if(virtualFilesFound.contains(virtualFile)) {
114117
return true;
@@ -117,23 +120,71 @@ public static PsiElement[] getTranslationPsiElements(final Project project, fina
117120
PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile);
118121
if(psiFile instanceof YAMLFile) {
119122
YamlTranslationVistor.collectFileTranslations((YAMLFile) psiFile, translationCollector);
120-
} else if("xlf".equalsIgnoreCase(virtualFile.getExtension()) && psiFile != null) {
123+
} else if(("xlf".equalsIgnoreCase(virtualFile.getExtension()) || "xliff".equalsIgnoreCase(virtualFile.getExtension())) && psiFile instanceof XmlFile) {
124+
// fine: xlf registered as XML file. try to find source value
125+
psiFoundElements.addAll(getTargetForXlfAsXmlFile((XmlFile) psiFile, translationKey));
126+
} else if(("xlf".equalsIgnoreCase(virtualFile.getExtension()) || "xliff".equalsIgnoreCase(virtualFile.getExtension()) && psiFile != null)) {
121127
// xlf are plain text because not supported by jetbrains
122128
// for now we can only set file target
123-
for(Set<String> string: FileBasedIndexImpl.getInstance().getValues(YamlTranslationStubIndex.KEY, domain, GlobalSearchScope.filesScope(project, Arrays.asList(virtualFile)))) {
124-
if(string.contains(translationKey)) {
125-
psiFoundElements.add(psiFile);
126-
}
127-
}
129+
psiFoundElements.addAll(
130+
FileBasedIndexImpl.getInstance().getValues(YamlTranslationStubIndex.KEY, domain, GlobalSearchScope.filesScope(project, Collections.singletonList(virtualFile)))
131+
.stream().filter(string -> string.contains(translationKey)).map(string -> psiFile).collect(Collectors.toList())
132+
);
128133
}
129134

130135
return true;
131136
}, GlobalSearchScope.allScope(project));
132137

133-
134138
return psiFoundElements.toArray(new PsiElement[psiFoundElements.size()]);
135139
}
136140

141+
/**
142+
* Find targets for xlf files if registered as XML
143+
144+
* 1.2 xliff -> file -> body -> trans-unit -> source
145+
* 2.0 xliff -> file -> group -> unit -> segment -> source
146+
*/
147+
@NotNull
148+
public static Collection<PsiElement> getTargetForXlfAsXmlFile(@NotNull XmlFile xmlFile, @NotNull String key) {
149+
XmlTag rootTag = xmlFile.getRootTag();
150+
if(rootTag == null) {
151+
return Collections.emptyList();
152+
}
153+
154+
Collection<PsiElement> psiElements = new ArrayList<>();
155+
156+
// find source key
157+
Consumer<XmlTag> consumer = xmlTag -> {
158+
XmlTag source = xmlTag.findFirstSubTag("source");
159+
if (source != null) {
160+
String text = source.getValue().getText();
161+
if (key.equalsIgnoreCase(text)) {
162+
psiElements.add(source);
163+
}
164+
}
165+
};
166+
167+
for (XmlTag file : rootTag.findSubTags("file")) {
168+
// version="1.2"
169+
for (XmlTag body : file.findSubTags("body")) {
170+
for (XmlTag transUnit : body.findSubTags("trans-unit")) {
171+
consumer.consume(transUnit);
172+
}
173+
}
174+
175+
// version="2.0"
176+
for (XmlTag group : file.findSubTags("group")) {
177+
for (XmlTag unit : group.findSubTags("unit")) {
178+
for (XmlTag segment : unit.findSubTags("segment")) {
179+
consumer.consume(segment);
180+
}
181+
}
182+
}
183+
}
184+
185+
return psiElements;
186+
}
187+
137188
public static boolean hasDomain(Project project, String domainName) {
138189
return TranslationIndex.getInstance(project).getTranslationMap().getDomainList().contains(domainName) ||
139190
FileBasedIndexImpl.getInstance().getValues(

tests/fr/adrienbrault/idea/symfony2plugin/tests/translation/dict/TranslationUtilTest.java

+57
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,20 @@
11
package fr.adrienbrault.idea.symfony2plugin.tests.translation.dict;
22

3+
import com.intellij.ide.highlighter.XmlFileType;
4+
import com.intellij.lang.xml.XMLLanguage;
5+
import com.intellij.openapi.util.Condition;
6+
import com.intellij.psi.PsiElement;
7+
import com.intellij.psi.PsiFile;
8+
import com.intellij.psi.PsiFileFactory;
9+
import com.intellij.psi.xml.XmlFile;
10+
import com.intellij.psi.xml.XmlTag;
11+
import com.intellij.util.containers.ContainerUtil;
12+
import com.intellij.xml.XmlFileTypeFactory;
313
import fr.adrienbrault.idea.symfony2plugin.tests.SymfonyLightCodeInsightFixtureTestCase;
414
import fr.adrienbrault.idea.symfony2plugin.translation.dict.TranslationUtil;
515

616
import java.io.File;
17+
import java.util.Collection;
718

819
/**
920
* @author Daniel Espendiller <daniel@espendiller.net>
@@ -37,4 +48,50 @@ public void testGetTranslationPsiElements() {
3748

3849
assertTrue(TranslationUtil.getTranslationPsiElements(getProject(), "foo_yaml.symfony.great", "car").length > 0);
3950
}
51+
52+
public void testGetTargetForXlfAsXmlFileInVersion12() {
53+
PsiFile fileFromText = PsiFileFactory.getInstance(getProject()).createFileFromText(XMLLanguage.INSTANCE, "" +
54+
"<?xml version=\"1.0\"?>\n" +
55+
"<xliff version=\"1.2\" xmlns=\"urn:oasis:names:tc:xliff:document:1.2\">\n" +
56+
" <file source-language=\"en\" datatype=\"plaintext\" original=\"file.ext\">\n" +
57+
" <body>\n" +
58+
" <trans-unit id=\"1\">\n" +
59+
" <source>This value should be false.</source>\n" +
60+
" </trans-unit>\n" +
61+
" </body>\n" +
62+
" </file>\n" +
63+
"</xliff>\n"
64+
);
65+
66+
Collection<PsiElement> files = TranslationUtil.getTargetForXlfAsXmlFile((XmlFile) fileFromText, "This value should be false.");
67+
68+
assertNotNull(ContainerUtil.find(files, psiElement ->
69+
psiElement instanceof XmlTag && "This value should be false.".equals(((XmlTag) psiElement).getValue().getText()))
70+
);
71+
}
72+
73+
public void testGetTargetForXlfAsXmlFileInVersion20() {
74+
PsiFile fileFromText = PsiFileFactory.getInstance(getProject()).createFileFromText(XMLLanguage.INSTANCE, "" +
75+
"<?xml version=\"1.0\"?>\n" +
76+
"<xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\"\n" +
77+
" version=\"2.0\" srcLang=\"en-US\" trgLang=\"ja-JP\">\n" +
78+
" <file id=\"f1\" original=\"Graphic Example.psd\">\n" +
79+
" <skeleton href=\"Graphic Example.psd.skl\"/>\n" +
80+
" <group id=\"1\">\n" +
81+
" <unit id=\"1\">\n" +
82+
" <segment>\n" +
83+
" <source>foo</source>\n" +
84+
" </segment>\n" +
85+
" </unit>\n" +
86+
" </group>\n" +
87+
" </file>\n" +
88+
"</xliff>"
89+
);
90+
91+
Collection<PsiElement> files = TranslationUtil.getTargetForXlfAsXmlFile((XmlFile) fileFromText, "foo");
92+
93+
assertNotNull(ContainerUtil.find(files, psiElement ->
94+
psiElement instanceof XmlTag && "foo".equals(((XmlTag) psiElement).getValue().getText()))
95+
);
96+
}
4097
}

0 commit comments

Comments
 (0)