Skip to content

Commit 2c940a8

Browse files
authored
Merge pull request #1444 from Haehnchen/feature/compiled-translation
refactored the compiled translation target handling based on container debug file
2 parents 41a8f71 + 73debbe commit 2c940a8

File tree

6 files changed

+157
-89
lines changed

6 files changed

+157
-89
lines changed

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

Lines changed: 79 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,23 @@
77
import com.intellij.openapi.vfs.VirtualFile;
88
import com.intellij.psi.PsiElement;
99
import com.intellij.psi.PsiFile;
10+
import com.intellij.psi.search.GlobalSearchScope;
1011
import com.intellij.psi.xml.XmlFile;
1112
import com.intellij.psi.xml.XmlTag;
1213
import com.intellij.util.Consumer;
14+
import com.intellij.util.indexing.FileBasedIndex;
1315
import fr.adrienbrault.idea.symfony2plugin.extension.TranslatorProvider;
1416
import fr.adrienbrault.idea.symfony2plugin.extension.TranslatorProviderDict;
17+
import fr.adrienbrault.idea.symfony2plugin.stubs.indexes.TranslationStubIndex;
1518
import fr.adrienbrault.idea.symfony2plugin.translation.TranslatorLookupElement;
19+
import fr.adrienbrault.idea.symfony2plugin.translation.collector.YamlTranslationVisitor;
1620
import fr.adrienbrault.idea.symfony2plugin.translation.parser.DomainMappings;
1721
import fr.adrienbrault.idea.symfony2plugin.util.MethodMatcher;
1822
import fr.adrienbrault.idea.symfony2plugin.util.PsiElementUtils;
1923
import fr.adrienbrault.idea.symfony2plugin.util.service.ServiceXmlParserFactory;
2024
import org.apache.commons.lang.StringUtils;
2125
import org.jetbrains.annotations.NotNull;
26+
import org.jetbrains.yaml.psi.YAMLFile;
2227
import org.jetbrains.yaml.psi.YAMLScalar;
2328
import org.w3c.dom.*;
2429
import org.xml.sax.SAXException;
@@ -57,10 +62,9 @@ public class TranslationUtil {
5762
"//xliff/file/unit/segment/source"
5863
};
5964

60-
static public VirtualFile[] getDomainFilePsiElements(Project project, String domainName) {
61-
65+
public static Collection<VirtualFile> getDomainFilesFromCompiledContainer(@NotNull Project project, @NotNull String domainName) {
6266
DomainMappings domainMappings = ServiceXmlParserFactory.getInstance(project, DomainMappings.class);
63-
List<VirtualFile> virtualFiles = new ArrayList<>();
67+
Collection<VirtualFile> virtualFiles = new ArrayList<>();
6468

6569
for(DomainFileMap domain: domainMappings.getDomainFileMaps()) {
6670
if(domain.getDomain().equals(domainName)) {
@@ -71,7 +75,78 @@ static public VirtualFile[] getDomainFilePsiElements(Project project, String dom
7175
}
7276
}
7377

74-
return virtualFiles.toArray(new VirtualFile[virtualFiles.size()]);
78+
return virtualFiles;
79+
}
80+
81+
/**
82+
* Get targets for translation based on the domain path inside the compiled container
83+
*
84+
* TODO: completely remove this? support translation paths from service compiler
85+
*/
86+
public static Collection<PsiElement> getTranslationKeyFromCompiledContainerDomain(@NotNull Project project, @NotNull String domain, @NotNull String translationKey) {
87+
Collection<PsiElement> psiFoundElements = new ArrayList<>();
88+
89+
// search for available domain files
90+
for(PsiFile psiFile : PsiElementUtils.convertVirtualFilesToPsiFiles(project, TranslationUtil.getDomainFilesFromCompiledContainer(project, domain))) {
91+
psiFoundElements.addAll(getTranslationKeyTargetInsideFile(psiFile, domain, translationKey));
92+
}
93+
94+
return psiFoundElements;
95+
}
96+
97+
public static boolean hasDomainInsideCompiledContainer(@NotNull Project project, @NotNull String domainName) {
98+
DomainMappings domainMappings = ServiceXmlParserFactory.getInstance(project, DomainMappings.class);
99+
for(DomainFileMap domain: domainMappings.getDomainFileMaps()) {
100+
if(domain.getDomain().equals(domainName)) {
101+
return true;
102+
}
103+
}
104+
105+
return false;
106+
}
107+
108+
static public Collection<String> getDomainsFromContainer(@NotNull Project project) {
109+
DomainMappings domainMappings = ServiceXmlParserFactory.getInstance(project, DomainMappings.class);
110+
111+
return domainMappings.getDomainFileMaps().stream()
112+
.map(DomainFileMap::getDomain)
113+
.collect(Collectors.toSet());
114+
}
115+
116+
/**
117+
* Find a target translation key based on all supported formats
118+
*/
119+
public static Collection<PsiElement> getTranslationKeyTargetInsideFile(@NotNull PsiFile psiFile, @NotNull String domain, @NotNull String translationKey) {
120+
Set<PsiElement> elements = new HashSet<>();
121+
122+
if(psiFile instanceof YAMLFile) {
123+
// collect on yaml keys
124+
YamlTranslationVisitor.collectFileTranslations((YAMLFile) psiFile, (keyName, yamlKeyValue) -> {
125+
if (keyName.equals(translationKey)) {
126+
// multiline "line values" are not resolve properly on psiElements use key as fallback target
127+
PsiElement valuePsiElement = yamlKeyValue.getValue();
128+
elements.add(valuePsiElement != null ? valuePsiElement : yamlKeyValue);
129+
130+
return false;
131+
}
132+
133+
return true;
134+
});
135+
} else if(TranslationUtil.isSupportedXlfFile(psiFile)) {
136+
// fine: xlf registered as XML file. try to find source value
137+
elements.addAll(TranslationUtil.getTargetForXlfAsXmlFile((XmlFile) psiFile, translationKey));
138+
} else if(("xlf".equalsIgnoreCase(psiFile.getVirtualFile().getExtension()) || "xliff".equalsIgnoreCase(psiFile.getVirtualFile().getExtension()))) {
139+
// xlf are plain text because not supported by jetbrains
140+
// for now we can only set file target
141+
Project project = psiFile.getProject();
142+
elements.addAll(FileBasedIndex.getInstance()
143+
.getValues(TranslationStubIndex.KEY, domain, GlobalSearchScope.filesScope(project, Collections.singletonList(psiFile.getVirtualFile()))).stream()
144+
.filter(string -> string.contains(translationKey)).map(string -> psiFile)
145+
.collect(Collectors.toList())
146+
);
147+
}
148+
149+
return elements;
75150
}
76151

77152
public static PsiElement[] getTranslationPsiElements(@NotNull Project project, @NotNull String translationKey, @NotNull String domain) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package fr.adrienbrault.idea.symfony2plugin.translation.provider;
2+
3+
import com.intellij.openapi.project.Project;
4+
import com.intellij.openapi.vfs.VirtualFile;
5+
import com.intellij.psi.PsiElement;
6+
import fr.adrienbrault.idea.symfony2plugin.extension.TranslatorProvider;
7+
import fr.adrienbrault.idea.symfony2plugin.extension.TranslatorProviderDict;
8+
import fr.adrienbrault.idea.symfony2plugin.translation.dict.TranslationUtil;
9+
import org.jetbrains.annotations.NotNull;
10+
11+
import java.util.Collection;
12+
import java.util.Collections;
13+
import java.util.stream.Collectors;
14+
15+
/**
16+
* Extract domain information based on the the compiled debug container inisde the cache folder
17+
*
18+
* * var/cache/...container.xml
19+
*
20+
* @author Daniel Espendiller <daniel@espendiller.net>
21+
*/
22+
public class CompiledContainerTranslatorProvider implements TranslatorProvider {
23+
@Override
24+
public boolean hasTranslationKey(@NotNull Project project, @NotNull String keyName, @NotNull String domainName) {
25+
// we only have the file; content should already be inside our much faster index
26+
return false;
27+
}
28+
29+
@Override
30+
public boolean hasDomain(@NotNull Project project, @NotNull String domainName) {
31+
return TranslationUtil.hasDomainInsideCompiledContainer(project, domainName);
32+
}
33+
34+
@NotNull
35+
@Override
36+
public Collection<TranslatorProviderDict.TranslationDomain> getTranslationDomains(@NotNull Project project) {
37+
return TranslationUtil.getDomainsFromContainer(project).stream()
38+
.map(TranslatorProviderDict.TranslationDomain::new)
39+
.collect(Collectors.toList());
40+
}
41+
42+
@NotNull
43+
@Override
44+
public Collection<PsiElement> getTranslationTargets(@NotNull Project project, @NotNull String translationKey, @NotNull String domain) {
45+
return TranslationUtil.getTranslationKeyFromCompiledContainerDomain(project, domain, translationKey);
46+
}
47+
48+
@NotNull
49+
@Override
50+
public Collection<VirtualFile> getDomainPsiFiles(Project project, @NotNull String domainName) {
51+
return TranslationUtil.getDomainFilesFromCompiledContainer(project, domainName);
52+
}
53+
54+
@NotNull
55+
@Override
56+
public Collection<TranslatorProviderDict.TranslationKey> getTranslationsForDomain(@NotNull Project project, @NotNull String domainName) {
57+
// we only have the file; content should already be inside our much faster index
58+
return Collections.emptyList();
59+
}
60+
}

src/main/java/fr/adrienbrault/idea/symfony2plugin/translation/provider/CompiledTranslatorProvider.java

Lines changed: 8 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,14 @@
33
import com.intellij.openapi.project.Project;
44
import com.intellij.openapi.vfs.VirtualFile;
55
import com.intellij.psi.PsiElement;
6-
import com.intellij.psi.PsiFile;
7-
import com.intellij.psi.search.GlobalSearchScope;
8-
import com.intellij.psi.util.PsiTreeUtil;
9-
import com.intellij.util.indexing.FileBasedIndex;
6+
import fr.adrienbrault.idea.symfony2plugin.extension.TranslatorProvider;
107
import fr.adrienbrault.idea.symfony2plugin.extension.TranslatorProviderDict;
11-
import fr.adrienbrault.idea.symfony2plugin.stubs.indexes.TranslationStubIndex;
128
import fr.adrienbrault.idea.symfony2plugin.translation.TranslationIndex;
13-
import fr.adrienbrault.idea.symfony2plugin.extension.TranslatorProvider;
14-
import fr.adrienbrault.idea.symfony2plugin.translation.dict.TranslationUtil;
15-
import fr.adrienbrault.idea.symfony2plugin.util.PsiElementUtils;
169
import org.jetbrains.annotations.NotNull;
17-
import org.jetbrains.yaml.YAMLFileType;
18-
import org.jetbrains.yaml.YAMLUtil;
19-
import org.jetbrains.yaml.psi.YAMLDocument;
20-
import org.jetbrains.yaml.psi.YAMLFile;
21-
import org.jetbrains.yaml.psi.YAMLKeyValue;
2210

23-
import java.util.*;
11+
import java.util.Collection;
12+
import java.util.Collections;
13+
import java.util.Set;
2414
import java.util.stream.Collectors;
2515

2616
/**
@@ -54,36 +44,15 @@ public Collection<TranslatorProviderDict.TranslationDomain> getTranslationDomain
5444
@NotNull
5545
@Override
5646
public Collection<PsiElement> getTranslationTargets(@NotNull Project project, @NotNull String translationKey, @NotNull String domain) {
57-
Collection<PsiElement> psiFoundElements = new ArrayList<>();
58-
59-
// @TODO: completely remove this? support translation paths from service compiler
60-
// search for available domain files
61-
for(VirtualFile translationVirtualFile : TranslationUtil.getDomainFilePsiElements(project, domain)) {
62-
if(translationVirtualFile.getFileType() != YAMLFileType.YML) {
63-
continue;
64-
}
65-
66-
PsiFile psiFile = PsiElementUtils.virtualFileToPsiFile(project, translationVirtualFile);
67-
if(psiFile instanceof YAMLFile) {
68-
PsiElement yamlDocu = PsiTreeUtil.findChildOfType(psiFile, YAMLDocument.class);
69-
if(yamlDocu != null) {
70-
YAMLKeyValue goToPsi = YAMLUtil.getQualifiedKeyInFile((YAMLFile) psiFile, translationKey.split("\\."));
71-
if(goToPsi != null) {
72-
// multiline are line values are not resolve properly on psiElements use key as fallback target
73-
PsiElement valuePsiElement = goToPsi.getValue();
74-
psiFoundElements.add(valuePsiElement != null ? valuePsiElement : goToPsi);
75-
}
76-
}
77-
}
78-
}
79-
80-
return psiFoundElements;
47+
// targeting cache folder is not helpful for user
48+
return Collections.emptyList();
8149
}
8250

8351
@NotNull
8452
@Override
8553
public Collection<VirtualFile> getDomainPsiFiles(Project project, @NotNull String domainName) {
86-
return Arrays.asList(TranslationUtil.getDomainFilePsiElements(project, domainName));
54+
// targeting cache folder is not helpful for user
55+
return Collections.emptyList();
8756
}
8857

8958
@NotNull

src/main/java/fr/adrienbrault/idea/symfony2plugin/translation/provider/IndexTranslatorProvider.java

Lines changed: 8 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,16 @@
44
import com.intellij.openapi.vfs.VirtualFile;
55
import com.intellij.psi.PsiElement;
66
import com.intellij.psi.PsiFile;
7-
import com.intellij.psi.PsiManager;
87
import com.intellij.psi.search.GlobalSearchScope;
9-
import com.intellij.psi.xml.XmlFile;
108
import com.intellij.util.indexing.FileBasedIndex;
119
import com.jetbrains.php.PhpIndex;
10+
import fr.adrienbrault.idea.symfony2plugin.extension.TranslatorProvider;
1211
import fr.adrienbrault.idea.symfony2plugin.extension.TranslatorProviderDict;
1312
import fr.adrienbrault.idea.symfony2plugin.stubs.SymfonyProcessors;
1413
import fr.adrienbrault.idea.symfony2plugin.stubs.indexes.TranslationStubIndex;
15-
import fr.adrienbrault.idea.symfony2plugin.translation.TranslationIndex;
16-
import fr.adrienbrault.idea.symfony2plugin.extension.TranslatorProvider;
17-
import fr.adrienbrault.idea.symfony2plugin.translation.collector.YamlTranslationCollector;
18-
import fr.adrienbrault.idea.symfony2plugin.translation.collector.YamlTranslationVisitor;
1914
import fr.adrienbrault.idea.symfony2plugin.translation.dict.TranslationUtil;
15+
import fr.adrienbrault.idea.symfony2plugin.util.PsiElementUtils;
2016
import org.jetbrains.annotations.NotNull;
21-
import org.jetbrains.yaml.psi.YAMLFile;
2217

2318
import java.util.*;
2419
import java.util.stream.Collectors;
@@ -64,49 +59,16 @@ public Collection<TranslatorProviderDict.TranslationDomain> getTranslationDomain
6459
public Collection<PsiElement> getTranslationTargets(@NotNull Project project, @NotNull String translationKey, @NotNull String domain) {
6560
Collection<PsiElement> psiFoundElements = new ArrayList<>();
6661

67-
// collect on index
68-
final YamlTranslationCollector translationCollector = (keyName, yamlKeyValue) -> {
69-
if (keyName.equals(translationKey)) {
70-
71-
// multiline "line values" are not resolve properly on psiElements use key as fallback target
72-
PsiElement valuePsiElement = yamlKeyValue.getValue();
73-
psiFoundElements.add(valuePsiElement != null ? valuePsiElement : yamlKeyValue);
74-
75-
return false;
76-
}
77-
78-
return true;
79-
};
80-
62+
Collection<VirtualFile> files = new HashSet<>();
8163
FileBasedIndex.getInstance().getFilesWithKey(TranslationStubIndex.KEY, new HashSet<>(Collections.singletonList(domain)), virtualFile -> {
82-
// prevent duplicate targets and dont walk same file twice
83-
// if(virtualFilesFound.contains(virtualFile)) {
84-
// return true;
85-
// }
86-
87-
PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile);
88-
if(psiFile == null) {
89-
return true;
90-
}
91-
92-
if(psiFile instanceof YAMLFile) {
93-
YamlTranslationVisitor.collectFileTranslations((YAMLFile) psiFile, translationCollector);
94-
} else if(TranslationUtil.isSupportedXlfFile(psiFile)) {
95-
// fine: xlf registered as XML file. try to find source value
96-
psiFoundElements.addAll(TranslationUtil.getTargetForXlfAsXmlFile((XmlFile) psiFile, translationKey));
97-
} else if(("xlf".equalsIgnoreCase(virtualFile.getExtension()) || "xliff".equalsIgnoreCase(virtualFile.getExtension()))) {
98-
// xlf are plain text because not supported by jetbrains
99-
// for now we can only set file target
100-
psiFoundElements.addAll(FileBasedIndex.getInstance()
101-
.getValues(TranslationStubIndex.KEY, domain, GlobalSearchScope.filesScope(project, Collections.singletonList(virtualFile))).stream()
102-
.filter(string -> string.contains(translationKey)).map(string -> psiFile)
103-
.collect(Collectors.toList())
104-
);
105-
}
106-
64+
files.add(virtualFile);
10765
return true;
10866
}, GlobalSearchScope.allScope(project));
10967

68+
for (PsiFile psiFile : PsiElementUtils.convertVirtualFilesToPsiFiles(project, files)) {
69+
psiFoundElements.addAll(TranslationUtil.getTranslationKeyTargetInsideFile(psiFile, domain, translationKey));
70+
}
71+
11072
return psiFoundElements;
11173
}
11274

src/main/resources/META-INF/plugin.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,7 @@
606606

607607
<TranslatorProvider implementation="fr.adrienbrault.idea.symfony2plugin.translation.provider.CompiledTranslatorProvider"/>
608608
<TranslatorProvider implementation="fr.adrienbrault.idea.symfony2plugin.translation.provider.IndexTranslatorProvider"/>
609+
<TranslatorProvider implementation="fr.adrienbrault.idea.symfony2plugin.translation.provider.CompiledContainerTranslatorProvider"/>
609610
</extensions>
610611

611612
<depends>com.jetbrains.twig</depends>

src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/translation/parser/appDevDebugProjectContainer.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,5 +79,6 @@
7979
<argument>FOSUserBundle</argument>
8080
</call>
8181
</service>
82+
8283
</services>
8384
</container>

0 commit comments

Comments
 (0)