User: joe Date: 23 Sep 23 21:39 Revision: b13eb2594830de7089508bd1179550fc1427566a Summary: Switch to using the @Translatable annotation instead of a hardcoded list TeamCity URL: https://ci.mcdev.io/viewModification.html?tab=vcsModificationFiles&modId=8764&personal=false Index: src/main/kotlin/translations/TranslationConstants.kt =================================================================== --- src/main/kotlin/translations/TranslationConstants.kt (revision d0bb7ff02ab52edc8d959b296053059c5a3f4c8e) +++ src/main/kotlin/translations/TranslationConstants.kt (revision b13eb2594830de7089508bd1179550fc1427566a) @@ -22,18 +22,9 @@ object TranslationConstants { const val DEFAULT_LOCALE = "en_us" - const val I18N_CLASS = "net.minecraft.client.resources.language.I18n" - const val TRANSLATABLE_COMPONENT = "net.minecraft.network.chat.TranslatableComponent" - const val KEY_MAPPING = "net.minecraft.client.KeyMapping" - const val INPUT_CONSTANTS_KEY = "com.mojang.blaze3d.platform.InputConstants" - const val TEXT_COMPONENT_HELPER = "net.minecraftforge.server.command.TextComponentHelper" - const val CONSTRUCTOR = "" - const val COMMAND_EXCEPTION_CLASS = "net.minecraft.command.CommandException" - const val GET = "m_118938_" - const val EXISTS = "m_118936_" - const val INPUT_CONSTANTS_KEY_GET_KEY = "m_84851_" - const val CREATE_COMPONENT_TRANSLATION = "createComponentTranslation" - const val COMPONENT_CLASS = "net.minecraft.network.chat.Component" - const val COMPONENT_TRANSLATABLE = "translatable" - const val COMPONENT_TRANSLATABLE_WITH_FALLBACK = "translatableWithFallback" + const val TRANSLATABLE_ANNOTATION = "com.demonwav.mcdev.annotations.Translatable" + const val REQUIRED = "required" + const val FOLD_METHOD = "foldMethod" + const val PREFIX = "prefix" + const val SUFFIX = "suffix" } Index: src/main/kotlin/translations/folding.kt =================================================================== --- src/main/kotlin/translations/folding.kt (revision d0bb7ff02ab52edc8d959b296053059c5a3f4c8e) +++ src/main/kotlin/translations/folding.kt (revision b13eb2594830de7089508bd1179550fc1427566a) @@ -99,6 +99,9 @@ } else { foldingElement.textRange } + if (!translation.required && translation.formattingError != null) { + continue + } descriptors.add( FoldingDescriptor( translation.foldingElement.node, Index: src/main/kotlin/translations/identification/TranslationFunction.kt =================================================================== --- src/main/kotlin/translations/identification/TranslationFunction.kt (revision d0bb7ff02ab52edc8d959b296053059c5a3f4c8e) +++ src/main/kotlin/translations/identification/TranslationFunction.kt (revision d0bb7ff02ab52edc8d959b296053059c5a3f4c8e) @@ -1,105 +0,0 @@ -/* - * Minecraft Development for IntelliJ - * - * https://mcdev.io/ - * - * Copyright (C) 2023 minecraft-dev - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation, version 3.0 only. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.demonwav.mcdev.translations.identification - -import com.demonwav.mcdev.platform.mcp.srg.SrgManager -import com.demonwav.mcdev.util.MemberReference -import com.demonwav.mcdev.util.extractVarArgs -import com.demonwav.mcdev.util.findMcpModule -import com.demonwav.mcdev.util.isSameReference -import com.demonwav.mcdev.util.referencedMethod -import com.intellij.psi.PsiCall -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiLiteral -import com.intellij.psi.PsiMethod -import java.util.IllegalFormatException - -class TranslationFunction( - private val memberReference: MemberReference, - val matchedIndex: Int, - val formatting: Boolean, - val foldParameters: FoldingScope = FoldingScope.CALL, - val obfuscatedName: Boolean = false, -) { - private fun getMethod(context: PsiElement): PsiMethod? { - var reference = memberReference - if (obfuscatedName) { - val moduleSrgManager = context.findMcpModule()?.srgManager - val srgManager = moduleSrgManager ?: SrgManager.findAnyInstance(context.project) - srgManager?.srgMapNow?.mapToMcpMethod(memberReference)?.let { - reference = it - } - } - return reference.resolveMember(context.project) as? PsiMethod - } - - fun matches(call: PsiCall, paramIndex: Int): Boolean { - return matches(call.resolveMethod() ?: return false, paramIndex) - } - - fun matches(method: PsiMethod, paramIndex: Int): Boolean { - val referenceMethod = getMethod(method) ?: return false - return method.isSameReference(referenceMethod) && paramIndex == matchedIndex - } - - fun getTranslationKey(call: PsiCall, param: PsiElement): String? { - if (!matches(call, matchedIndex)) { - return null - } - return (param as? PsiLiteral)?.value as? String - } - - fun format(translation: String, call: PsiCall): Pair? { - if (!matches(call, matchedIndex)) { - return null - } - if (!formatting) { - return translation to -1 - } - - val format = NUMBER_FORMATTING_PATTERN.replace(translation, "%$1s") - val paramCount = STRING_FORMATTING_PATTERN.findAll(format).count() - - val method = call.referencedMethod ?: return translation to -1 - val varargs = call.extractVarArgs(method.parameterList.parametersCount - 1, true, true) - val varargStart = if (varargs.size > paramCount) method.parameterList.parametersCount - 1 + paramCount else -1 - return try { - String.format(format, *varargs) to varargStart - } catch (e: IllegalFormatException) { - null - } - } - - override fun toString(): String { - return "$memberReference@$matchedIndex" - } - - companion object { - val NUMBER_FORMATTING_PATTERN = Regex("%(\\d+\\$)?[\\d.]*[df]") - val STRING_FORMATTING_PATTERN = Regex("[^%]?%(?:\\d+\\$)?s") - } - - enum class FoldingScope { - CALL, - PARAMETER, - PARAMETERS, - } -} Index: src/main/kotlin/translations/identification/TranslationIdentifier.kt =================================================================== --- src/main/kotlin/translations/identification/TranslationIdentifier.kt (revision d0bb7ff02ab52edc8d959b296053059c5a3f4c8e) +++ src/main/kotlin/translations/identification/TranslationIdentifier.kt (revision b13eb2594830de7089508bd1179550fc1427566a) @@ -20,14 +20,25 @@ package com.demonwav.mcdev.translations.identification +import com.demonwav.mcdev.translations.TranslationConstants import com.demonwav.mcdev.translations.identification.TranslationInstance.Companion.FormattingError import com.demonwav.mcdev.translations.index.TranslationIndex import com.demonwav.mcdev.translations.index.merge +import com.demonwav.mcdev.util.constantStringValue +import com.demonwav.mcdev.util.constantValue +import com.demonwav.mcdev.util.extractVarArgs +import com.demonwav.mcdev.util.referencedMethod +import com.intellij.codeInspection.dataFlow.CommonDataflow import com.intellij.openapi.project.Project +import com.intellij.psi.CommonClassNames +import com.intellij.psi.PsiCall import com.intellij.psi.PsiCallExpression import com.intellij.psi.PsiElement +import com.intellij.psi.PsiEllipsisType import com.intellij.psi.PsiExpression import com.intellij.psi.PsiExpressionList +import com.intellij.psi.PsiMethod +import java.util.IllegalFormatException import java.util.MissingFormatArgumentException abstract class TranslationIdentifier { @@ -49,57 +60,108 @@ container: PsiElement, referenceElement: PsiElement, ): TranslationInstance? { - if (container is PsiExpressionList && container.parent is PsiCallExpression) { - val call = container.parent as PsiCallExpression + if (container !is PsiExpressionList) { + return null + } + val call = container.parent as? PsiCallExpression ?: return null - val index = container.expressions.indexOf(element) + val index = container.expressions.indexOf(element) - for (function in TranslationInstance.translationFunctions) { - if (function.matches(call, index)) { - val translationKey = function.getTranslationKey(call, referenceElement) ?: continue + val method = call.referencedMethod ?: return null + val parameter = method.parameterList.getParameter(index) ?: return null + val translatableAnnotation = parameter.getAnnotation(TranslationConstants.TRANSLATABLE_ANNOTATION) + ?: return null + + val prefix = + translatableAnnotation.findAttributeValue(TranslationConstants.PREFIX)?.constantStringValue ?: "" + val suffix = + translatableAnnotation.findAttributeValue(TranslationConstants.SUFFIX)?.constantStringValue ?: "" + val required = + translatableAnnotation.findAttributeValue(TranslationConstants.REQUIRED)?.constantValue as? Boolean + ?: true + + val translationKey = CommonDataflow.computeValue(element) as? String ?: return null + - val entries = TranslationIndex.getAllDefaultEntries(project).merge("") + val entries = TranslationIndex.getAllDefaultEntries(project).merge("") - val translation = entries[translationKey]?.text - if (translation != null) { - val foldingElement = when (function.foldParameters) { - TranslationFunction.FoldingScope.CALL -> call - TranslationFunction.FoldingScope.PARAMETER -> element - TranslationFunction.FoldingScope.PARAMETERS -> container + val translation = entries[prefix + translationKey + suffix]?.text + ?: return TranslationInstance( // translation doesn't exist + null, + index, + referenceElement, + TranslationInstance.Key(prefix, translationKey, suffix), + null, + required + ) + + val foldMethod = + translatableAnnotation.findAttributeValue(TranslationConstants.FOLD_METHOD)?.constantValue as? Boolean + ?: false + + val formatting = + (method.parameterList.parameters.last().type as? PsiEllipsisType) + ?.componentType?.equalsToText(CommonClassNames.JAVA_LANG_OBJECT) == true + + val foldingElement = if (foldMethod) { + call + } else if ( + index == 0 && + container.expressionCount > 1 && + method.parameterList.parametersCount == 2 && + formatting + ) { + container + } else { + element - } - try { + } + try { - val (formatted, superfluousParams) = function.format(translation, call) - ?: (translation to -1) + val (formatted, superfluousParams) = if (formatting) { + format(method, translation, call) ?: (translation to -1) + } else { + (translation to -1) + } - return TranslationInstance( - foldingElement, + return TranslationInstance( + foldingElement, - function.matchedIndex, + index, - referenceElement, + referenceElement, - TranslationInstance.Key(translationKey), + TranslationInstance.Key(prefix, translationKey, suffix), - formatted, + formatted, + required, - if (superfluousParams >= 0) FormattingError.SUPERFLUOUS else null, - superfluousParams, - ) - } catch (ignored: MissingFormatArgumentException) { - return TranslationInstance( - foldingElement, + if (superfluousParams >= 0) FormattingError.SUPERFLUOUS else null, + superfluousParams, + ) + } catch (ignored: MissingFormatArgumentException) { + return TranslationInstance( + foldingElement, - function.matchedIndex, + index, - referenceElement, + referenceElement, - TranslationInstance.Key(translationKey), + TranslationInstance.Key(prefix, translationKey, suffix), - translation, + translation, + required, - FormattingError.MISSING, - ) - } + FormattingError.MISSING, + ) + } + } + + private fun format(method: PsiMethod, translation: String, call: PsiCall): Pair? { + val format = NUMBER_FORMATTING_PATTERN.replace(translation, "%$1s") + val paramCount = STRING_FORMATTING_PATTERN.findAll(format).count() + + val varargs = call.extractVarArgs(method.parameterList.parametersCount - 1, true, true) + val varargStart = if (varargs.size > paramCount) { + method.parameterList.parametersCount - 1 + paramCount - } else { + } else { - return TranslationInstance( - null, - function.matchedIndex, - referenceElement, - TranslationInstance.Key(translationKey), - null, - ) + -1 - } + } + return try { + String.format(format, *varargs) to varargStart + } catch (e: MissingFormatArgumentException) { + // rethrow this specific exception to be handled by the caller + throw e + } catch (e: IllegalFormatException) { + null - } - } + } + } - return null + + private val NUMBER_FORMATTING_PATTERN = Regex("%(\\d+\\$)?[\\d.]*[df]") + private val STRING_FORMATTING_PATTERN = Regex("[^%]?%(?:\\d+\\$)?s") - } + } - return null - } +} - } -} Index: src/main/kotlin/translations/identification/TranslationInstance.kt =================================================================== --- src/main/kotlin/translations/identification/TranslationInstance.kt (revision d0bb7ff02ab52edc8d959b296053059c5a3f4c8e) +++ src/main/kotlin/translations/identification/TranslationInstance.kt (revision b13eb2594830de7089508bd1179550fc1427566a) @@ -20,8 +20,6 @@ package com.demonwav.mcdev.translations.identification -import com.demonwav.mcdev.translations.TranslationConstants -import com.demonwav.mcdev.util.MemberReference import com.intellij.psi.PsiElement data class TranslationInstance( @@ -30,6 +28,7 @@ val referenceElement: PsiElement?, val key: Key, val text: String?, + val required: Boolean, val formattingError: FormattingError? = null, val superfluousVarargStart: Int = -1, ) { @@ -44,242 +43,6 @@ MISSING, SUPERFLUOUS } - val translationFunctions = listOf( - TranslationFunction( - MemberReference( - TranslationConstants.GET, - "(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;", - TranslationConstants.I18N_CLASS, - ), - 0, - formatting = true, - obfuscatedName = true, - ), - TranslationFunction( - MemberReference( - TranslationConstants.EXISTS, - "(Ljava/lang/String;)Z", - TranslationConstants.I18N_CLASS, - ), - 0, - formatting = false, - foldParameters = TranslationFunction.FoldingScope.PARAMETERS, - obfuscatedName = true, - ), - TranslationFunction( - MemberReference( - TranslationConstants.CONSTRUCTOR, - "(Ljava/lang/String;)V", - TranslationConstants.TRANSLATABLE_COMPONENT, - ), - 0, - formatting = false, - ), - TranslationFunction( - MemberReference( - TranslationConstants.CONSTRUCTOR, - "(Ljava/lang/String;[Ljava/lang/Object;)V", - TranslationConstants.TRANSLATABLE_COMPONENT, - ), - 0, - formatting = true, - ), - TranslationFunction( - MemberReference( - TranslationConstants.CREATE_COMPONENT_TRANSLATION, - "(Lnet/minecraft/commands/CommandSource;Ljava/lang/String;" + - "[Ljava/lang/Object;)Lnet/minecraft/network/chat/BaseComponent;", - TranslationConstants.TEXT_COMPONENT_HELPER, - ), - 1, - formatting = true, - foldParameters = TranslationFunction.FoldingScope.PARAMETERS, - ), - TranslationFunction( - MemberReference( - TranslationConstants.CONSTRUCTOR, - "(Ljava/lang/String;[Ljava/lang/Object;)V", - TranslationConstants.COMMAND_EXCEPTION_CLASS, - ), - 0, - formatting = true, - foldParameters = TranslationFunction.FoldingScope.PARAMETERS, - ), - TranslationFunction( - MemberReference( - TranslationConstants.CONSTRUCTOR, - "(Ljava/lang/String;ILjava/lang/String;)V", - TranslationConstants.KEY_MAPPING, - ), - 0, - formatting = false, - foldParameters = TranslationFunction.FoldingScope.PARAMETER, - ), - TranslationFunction( - MemberReference( - TranslationConstants.CONSTRUCTOR, - "(Ljava/lang/String;ILjava/lang/String;)V", - TranslationConstants.KEY_MAPPING, - ), - 2, - formatting = false, - foldParameters = TranslationFunction.FoldingScope.PARAMETER, - ), - TranslationFunction( - MemberReference( - TranslationConstants.CONSTRUCTOR, - "(Ljava/lang/String;Lcom/mojang/blaze3d/platform/InputConstants\$Type;ILjava/lang/String;)V", - TranslationConstants.KEY_MAPPING, - ), - 0, - formatting = false, - foldParameters = TranslationFunction.FoldingScope.PARAMETER, - ), - TranslationFunction( - MemberReference( - TranslationConstants.CONSTRUCTOR, - "(Ljava/lang/String;Lcom/mojang/blaze3d/platform/InputConstants\$Type;ILjava/lang/String;)V", - TranslationConstants.KEY_MAPPING, - ), - 3, - formatting = false, - foldParameters = TranslationFunction.FoldingScope.PARAMETER, - ), - TranslationFunction( - MemberReference( - TranslationConstants.CONSTRUCTOR, - "(Ljava/lang/String;Lnet/minecraftforge/client/settings/IKeyConflictContext;" + - "Lcom/mojang/blaze3d/platform/InputConstants\$Type;ILjava/lang/String;)V", - TranslationConstants.KEY_MAPPING, - ), - 0, - formatting = false, - foldParameters = TranslationFunction.FoldingScope.PARAMETER, - ), - TranslationFunction( - MemberReference( - TranslationConstants.CONSTRUCTOR, - "(Ljava/lang/String;Lnet/minecraftforge/client/settings/IKeyConflictContext;" + - "Lcom/mojang/blaze3d/platform/InputConstants\$Type;ILjava/lang/String;)V", - TranslationConstants.KEY_MAPPING, - ), - 4, - formatting = false, - foldParameters = TranslationFunction.FoldingScope.PARAMETER, - ), - TranslationFunction( - MemberReference( - TranslationConstants.CONSTRUCTOR, - "(Ljava/lang/String;Lnet/minecraftforge/client/settings/IKeyConflictContext;" + - "Lcom/mojang/blaze3d/platform/InputConstants\$Key;Ljava/lang/String;)V", - TranslationConstants.KEY_MAPPING, - ), - 0, - formatting = false, - foldParameters = TranslationFunction.FoldingScope.PARAMETER, - ), - TranslationFunction( - MemberReference( - TranslationConstants.CONSTRUCTOR, - "(Ljava/lang/String;Lnet/minecraftforge/client/settings/IKeyConflictContext;" + - "Lcom/mojang/blaze3d/platform/InputConstants\$Key;Ljava/lang/String;)V", - TranslationConstants.KEY_MAPPING, - ), - 3, - formatting = false, - foldParameters = TranslationFunction.FoldingScope.PARAMETER, - ), - TranslationFunction( - MemberReference( - TranslationConstants.CONSTRUCTOR, - "(Ljava/lang/String;Lnet/minecraftforge/client/settings/IKeyConflictContext;" + - "Lnet/minecraftforge/client/settings/KeyModifier;" + - "Lcom/mojang/blaze3d/platform/InputConstants\$Type;ILjava/lang/String;)V", - TranslationConstants.KEY_MAPPING, - ), - 0, - formatting = false, - foldParameters = TranslationFunction.FoldingScope.PARAMETER, - ), - TranslationFunction( - MemberReference( - TranslationConstants.CONSTRUCTOR, - "(Ljava/lang/String;Lnet/minecraftforge/client/settings/IKeyConflictContext;" + - "Lnet/minecraftforge/client/settings/KeyModifier;" + - "Lcom/mojang/blaze3d/platform/InputConstants\$Type;ILjava/lang/String;)V", - TranslationConstants.KEY_MAPPING, - ), - 5, - formatting = false, - foldParameters = TranslationFunction.FoldingScope.PARAMETER, - ), - TranslationFunction( - MemberReference( - TranslationConstants.CONSTRUCTOR, - "(Ljava/lang/String;Lnet/minecraftforge/client/settings/IKeyConflictContext;" + - "Lnet/minecraftforge/client/settings/KeyModifier;" + - "Lcom/mojang/blaze3d/platform/InputConstants\$Key;Ljava/lang/String;)V", - TranslationConstants.KEY_MAPPING, - ), - 0, - formatting = false, - foldParameters = TranslationFunction.FoldingScope.PARAMETER, - ), - TranslationFunction( - MemberReference( - TranslationConstants.CONSTRUCTOR, - "(Ljava/lang/String;Lnet/minecraftforge/client/settings/IKeyConflictContext;" + - "Lnet/minecraftforge/client/settings/KeyModifier;" + - "Lcom/mojang/blaze3d/platform/InputConstants\$Key;Ljava/lang/String;)V", - TranslationConstants.KEY_MAPPING, - ), - 4, - formatting = false, - foldParameters = TranslationFunction.FoldingScope.PARAMETER, - ), - TranslationFunction( - MemberReference( - TranslationConstants.INPUT_CONSTANTS_KEY_GET_KEY, - "(Ljava/lang/String;)Lcom/mojang/blaze3d/platform/InputConstants\$Key;", - TranslationConstants.INPUT_CONSTANTS_KEY, - ), - 0, - formatting = false, - foldParameters = TranslationFunction.FoldingScope.PARAMETER, - obfuscatedName = true, - ), - TranslationFunction( - MemberReference( - TranslationConstants.COMPONENT_TRANSLATABLE, - "(Ljava/lang/String;)Lnet/minecraft/network/chat/MutableComponent;", - TranslationConstants.COMPONENT_CLASS, - ), - 0, - formatting = false, - foldParameters = TranslationFunction.FoldingScope.CALL, - ), - TranslationFunction( - MemberReference( - TranslationConstants.COMPONENT_TRANSLATABLE, - "(Ljava/lang/String;[Ljava/lang/Object;)Lnet/minecraft/network/chat/MutableComponent;", - TranslationConstants.COMPONENT_CLASS, - ), - 0, - formatting = false, - foldParameters = TranslationFunction.FoldingScope.CALL, - ), - TranslationFunction( - MemberReference( - TranslationConstants.COMPONENT_TRANSLATABLE_WITH_FALLBACK, - null, - TranslationConstants.COMPONENT_CLASS, - ), - 0, - formatting = false, - foldParameters = TranslationFunction.FoldingScope.PARAMETER, - ), - ) - fun find(element: PsiElement): TranslationInstance? = TranslationIdentifier.INSTANCES .firstOrNull { it.elementClass().isAssignableFrom(element.javaClass) } Index: src/main/kotlin/translations/inspections/MissingFormatInspection.kt =================================================================== --- src/main/kotlin/translations/inspections/MissingFormatInspection.kt (revision d0bb7ff02ab52edc8d959b296053059c5a3f4c8e) +++ src/main/kotlin/translations/inspections/MissingFormatInspection.kt (revision b13eb2594830de7089508bd1179550fc1427566a) @@ -23,7 +23,6 @@ import com.demonwav.mcdev.translations.identification.TranslationInstance import com.demonwav.mcdev.translations.identification.TranslationInstance.Companion.FormattingError import com.intellij.codeInspection.LocalQuickFix -import com.intellij.codeInspection.ProblemHighlightType import com.intellij.codeInspection.ProblemsHolder import com.intellij.psi.JavaElementVisitor import com.intellij.psi.PsiElementVisitor @@ -47,11 +46,10 @@ private fun visit(expression: PsiExpression, vararg quickFixes: LocalQuickFix) { val result = TranslationInstance.find(expression) - if (result != null && result.formattingError == FormattingError.MISSING) { + if (result != null && result.required && result.formattingError == FormattingError.MISSING) { holder.registerProblem( expression, "There are missing formatting arguments to satisfy '${result.text}'", - ProblemHighlightType.GENERIC_ERROR, *quickFixes, ) } Index: src/main/kotlin/translations/inspections/NoTranslationInspection.kt =================================================================== --- src/main/kotlin/translations/inspections/NoTranslationInspection.kt (revision d0bb7ff02ab52edc8d959b296053059c5a3f4c8e) +++ src/main/kotlin/translations/inspections/NoTranslationInspection.kt (revision b13eb2594830de7089508bd1179550fc1427566a) @@ -24,7 +24,6 @@ import com.demonwav.mcdev.translations.identification.LiteralTranslationIdentifier import com.intellij.codeInspection.LocalQuickFix import com.intellij.codeInspection.ProblemDescriptor -import com.intellij.codeInspection.ProblemHighlightType import com.intellij.codeInspection.ProblemsHolder import com.intellij.notification.Notification import com.intellij.notification.NotificationType @@ -45,11 +44,10 @@ private class Visitor(private val holder: ProblemsHolder) : JavaElementVisitor() { override fun visitLiteralExpression(expression: PsiLiteralExpression) { val result = LiteralTranslationIdentifier().identify(expression) - if (result != null && result.text == null) { + if (result != null && result.required && result.text == null) { holder.registerProblem( expression, "The given translation key does not exist", - ProblemHighlightType.GENERIC_ERROR, CreateTranslationQuickFix, ChangeTranslationQuickFix("Use existing translation"), ) Index: src/main/kotlin/translations/inspections/SuperfluousFormatInspection.kt =================================================================== --- src/main/kotlin/translations/inspections/SuperfluousFormatInspection.kt (revision d0bb7ff02ab52edc8d959b296053059c5a3f4c8e) +++ src/main/kotlin/translations/inspections/SuperfluousFormatInspection.kt (revision b13eb2594830de7089508bd1179550fc1427566a) @@ -25,7 +25,6 @@ import com.demonwav.mcdev.util.runWriteAction import com.intellij.codeInspection.LocalQuickFix import com.intellij.codeInspection.ProblemDescriptor -import com.intellij.codeInspection.ProblemHighlightType import com.intellij.codeInspection.ProblemsHolder import com.intellij.openapi.project.Project import com.intellij.psi.JavaElementVisitor @@ -57,7 +56,7 @@ override fun visitLiteralExpression(expression: PsiLiteralExpression) { val result = TranslationInstance.find(expression) if ( - result != null && result.foldingElement is PsiCall && + result != null && result.required && result.foldingElement is PsiCall && result.formattingError == FormattingError.SUPERFLUOUS ) { registerProblem( @@ -81,7 +80,6 @@ holder.registerProblem( expression, "There are missing formatting arguments to satisfy '${result.text}'", - ProblemHighlightType.GENERIC_ERROR, *quickFixes, ) }