@@ -5,7 +5,6 @@ import com.github.teahousestudios.akaribotdevplugin.services.JsonLookupService
55import com.intellij.lang.ASTNode
66import com.intellij.lang.folding.FoldingBuilderEx
77import com.intellij.lang.folding.FoldingDescriptor
8- import com.intellij.openapi.diagnostic.thisLogger
98import com.intellij.openapi.editor.Document
109import com.intellij.openapi.project.DumbAware
1110import com.intellij.openapi.util.TextRange
@@ -15,25 +14,58 @@ import com.intellij.psi.util.PsiTreeUtil
1514import com.jetbrains.python.psi.PyStringLiteralExpression
1615import java.util.concurrent.ConcurrentHashMap
1716
17+
1818class LocaleStringFoldingBuilder : FoldingBuilderEx (), DumbAware {
1919 private val placeholders = ConcurrentHashMap <ASTNode , String >()
2020
2121 override fun buildFoldRegions (root : PsiElement , document : Document , quick : Boolean ): Array <FoldingDescriptor > {
22+ // clear previous placeholders to avoid memory growth / stale mappings
23+ placeholders.clear()
24+
2225 if (root !is PsiFile || ! root.name.endsWith(" .py" , ignoreCase = true )) return emptyArray()
2326 val project = root.project
2427 val localeData = JsonLookupService .getInstance(project).getLocaleData()
2528 val descriptors = ArrayList <FoldingDescriptor >()
2629
2730 val strings = PsiTreeUtil .findChildrenOfType(root, PyStringLiteralExpression ::class .java)
2831
32+ // regex to find patterns like {I18N:key}
33+ val pattern = Regex (""" \{I18N:([^}]+)}""" )
34+
2935 for (str in strings) {
30- val key = str.stringValue ? : continue
31- val value = localeData[key] ? : continue
32- val node = str.node ? : continue
33- // 折叠整个字符串字面量范围
34- val range = TextRange (str.textRange.startOffset, str.textRange.endOffset)
35- placeholders[node] = " \" $value \" " // 占位显示带引号的值
36- descriptors.add(FoldingDescriptor (node, range))
36+ val original = str.stringValue
37+
38+ // 1) if the whole string is a key in localeData, fold to that value (existing behavior)
39+ val wholeValue = localeData[original]
40+ if (wholeValue != null ) {
41+ val node = str.node ? : continue
42+ val range = TextRange (str.textRange.startOffset, str.textRange.endOffset)
43+ placeholders[node] = " \" $wholeValue \" "
44+ descriptors.add(FoldingDescriptor (node, range))
45+ continue
46+ }
47+
48+ // 2) otherwise, check for occurrences of {I18N:key} inside the string
49+ var replaced = false
50+ val replacedText = pattern.replace(original) { matchResult ->
51+ val key = matchResult.groupValues[1 ]
52+ val value = localeData[key]
53+ if (value != null ) {
54+ replaced = true
55+ value
56+ } else {
57+ // leave original token if not found
58+ matchResult.value
59+ }
60+ }
61+
62+ if (replaced) {
63+ val node = str.node ? : continue
64+ val range = TextRange (str.textRange.startOffset, str.textRange.endOffset)
65+ // show the whole string but with replacements applied; keep the original quoting style by using double quotes in placeholder
66+ placeholders[node] = " \" $replacedText \" "
67+ descriptors.add(FoldingDescriptor (node, range))
68+ }
3769 }
3870
3971 return descriptors.toTypedArray()
0 commit comments