mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
i18n: show dialog with a table in batch mode under registry key: i18n.for.idea.project
all properties would be put in the same properties file; resourceBundle name should correspond to the class name with static method `message` GitOrigin-RevId: ce1eed2e875533f1c1a2bc26f34083c4e088b381
This commit is contained in:
committed by
intellij-monorepo-bot
parent
93077b9da8
commit
0ef0e3f7c1
@@ -76,6 +76,7 @@
|
||||
<experimentalFeature id="property.value.inplace.editing" percentOfUsers="100">
|
||||
<description>Edit property value at usage location, where it's displayed in folding placeholder</description>
|
||||
</experimentalFeature>
|
||||
<registryKey key="i18n.for.idea.project" defaultValue="false" description="Batch i18n"/>
|
||||
</extensions>
|
||||
<actions>
|
||||
<action id="I18nize" class="com.intellij.codeInspection.i18n.I18nizeAction">
|
||||
|
||||
@@ -17,6 +17,7 @@ import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.InvalidDataException;
|
||||
import com.intellij.openapi.util.WriteExternalException;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
@@ -519,27 +520,33 @@ public class I18nInspection extends AbstractBaseUastLocalInspectionTool implemen
|
||||
|
||||
List<LocalQuickFix> fixes = new ArrayList<>();
|
||||
|
||||
if (myOnTheFly && sourcePsi instanceof PsiLiteralExpression) {
|
||||
if (I18nizeConcatenationQuickFix.getEnclosingLiteralConcatenation(sourcePsi) != null) {
|
||||
fixes.add(new I18nizeConcatenationQuickFix());
|
||||
}
|
||||
fixes.add(new I18nizeQuickFix());
|
||||
if (sourcePsi instanceof PsiLiteralExpression) {
|
||||
if (myOnTheFly) {
|
||||
if (I18nizeConcatenationQuickFix.getEnclosingLiteralConcatenation(sourcePsi) != null) {
|
||||
fixes.add(new I18nizeConcatenationQuickFix());
|
||||
}
|
||||
fixes.add(new I18nizeQuickFix());
|
||||
|
||||
if (!isNotConstantFieldInitializer((PsiExpression)sourcePsi)) {
|
||||
fixes.add(createIntroduceConstantFix());
|
||||
}
|
||||
if (!isNotConstantFieldInitializer((PsiExpression)sourcePsi)) {
|
||||
fixes.add(createIntroduceConstantFix());
|
||||
}
|
||||
|
||||
if (PsiUtil.isLanguageLevel5OrHigher(sourcePsi)) {
|
||||
final JavaPsiFacade facade = JavaPsiFacade.getInstance(myManager.getProject());
|
||||
for (PsiModifierListOwner element : nonNlsTargets) {
|
||||
if (!AnnotationUtil.isAnnotated(element, AnnotationUtil.NLS, CHECK_HIERARCHY | CHECK_EXTERNAL)) {
|
||||
if (!element.getManager().isInProject(element) ||
|
||||
facade.findClass(AnnotationUtil.NON_NLS, element.getResolveScope()) != null) {
|
||||
fixes.add(new NonNlsAnnotationProvider().createFix(element));
|
||||
if (PsiUtil.isLanguageLevel5OrHigher(sourcePsi)) {
|
||||
final JavaPsiFacade facade = JavaPsiFacade.getInstance(myManager.getProject());
|
||||
for (PsiModifierListOwner element : nonNlsTargets) {
|
||||
if (!AnnotationUtil.isAnnotated(element, AnnotationUtil.NLS, CHECK_HIERARCHY | CHECK_EXTERNAL)) {
|
||||
if (!element.getManager().isInProject(element) ||
|
||||
facade.findClass(AnnotationUtil.NON_NLS, element.getResolveScope()) != null) {
|
||||
fixes.add(new NonNlsAnnotationProvider().createFix(element));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Registry.is("i18n.for.idea.project") &&
|
||||
I18nizeConcatenationQuickFix.getEnclosingLiteralConcatenation(sourcePsi) == null) {
|
||||
fixes.add(new I18nizeBatchQuickFix());
|
||||
}
|
||||
}
|
||||
|
||||
LocalQuickFix[] farr = fixes.toArray(LocalQuickFix.EMPTY_ARRAY);
|
||||
|
||||
@@ -0,0 +1,239 @@
|
||||
// Copyright 2000-2017 JetBrains s.r.o.
|
||||
// Use of this source code is governed by the Apache 2.0 license that can be
|
||||
// found in the LICENSE file.
|
||||
package com.intellij.codeInspection.i18n;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightBundle;
|
||||
import com.intellij.codeInspection.BatchQuickFix;
|
||||
import com.intellij.codeInspection.CommonProblemDescriptor;
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.ide.fileTemplates.FileTemplate;
|
||||
import com.intellij.ide.fileTemplates.FileTemplateManager;
|
||||
import com.intellij.ide.fileTemplates.JavaTemplateUtil;
|
||||
import com.intellij.ide.util.PropertiesComponent;
|
||||
import com.intellij.lang.properties.PropertiesImplUtil;
|
||||
import com.intellij.lang.properties.psi.PropertiesFile;
|
||||
import com.intellij.lang.properties.references.I18nUtil;
|
||||
import com.intellij.lang.properties.references.I18nizeQuickFixDialog;
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.ComboBox;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.ui.LabeledComponent;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.ui.table.JBTable;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.ui.ItemRemovable;
|
||||
import gnu.trove.THashMap;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class I18nizeBatchQuickFix extends I18nizeQuickFix implements BatchQuickFix<CommonProblemDescriptor> {
|
||||
private static final Logger LOG = Logger.getInstance(I18nizeBatchQuickFix.class);
|
||||
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project,
|
||||
@NotNull CommonProblemDescriptor[] descriptors,
|
||||
@NotNull List<PsiElement> psiElementsToIgnore,
|
||||
@Nullable Runnable refreshViews) {
|
||||
List<ReplacementBean> keyValuePairs = ContainerUtil.mapNotNull(descriptors, descriptor -> {
|
||||
PsiElement psiElement = ((ProblemDescriptor)descriptor).getPsiElement();
|
||||
if (psiElement instanceof PsiLiteralExpression &&
|
||||
I18nizeConcatenationQuickFix.getEnclosingLiteralConcatenation(psiElement) == null) {
|
||||
Object val = ((PsiLiteralExpression)psiElement).getValue();
|
||||
if (val instanceof String) {
|
||||
String value = StringUtil.escapeStringCharacters((String)val);
|
||||
String key = I18nizeQuickFixDialog.suggestUniquePropertyKey(value, null, null);
|
||||
return new ReplacementBean(key, value, (PsiLiteralExpression)psiElement);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
if (keyValuePairs.isEmpty()) return;
|
||||
|
||||
I18NBatchDialog dialog = new I18NBatchDialog(project, keyValuePairs);
|
||||
if (dialog.showAndGet()) {
|
||||
PropertiesFile propertiesFile = dialog.getPropertiesFile();
|
||||
PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
|
||||
FileTemplate template = FileTemplateManager.getInstance(project).getCodeTemplate(JavaTemplateUtil.TEMPLATE_I18NIZED_EXPRESSION);
|
||||
List<PsiFile> files = ContainerUtil.mapNotNull(keyValuePairs, bean -> bean.getExpression().getContainingFile());
|
||||
if (files.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
files.add(propertiesFile.getContainingFile());
|
||||
|
||||
WriteCommandAction.runWriteCommandAction(project, getFamilyName(), null, () -> {
|
||||
String bundleName = propertiesFile.getVirtualFile().getNameWithoutExtension();
|
||||
for (ReplacementBean bean : keyValuePairs) {
|
||||
JavaI18nUtil.DEFAULT_PROPERTY_CREATION_HANDLER
|
||||
.createProperty(project, Collections.singletonList(propertiesFile), bean.getKey(), bean.getValue(), PsiExpression.EMPTY_ARRAY);
|
||||
PsiElement literalExpression = bean.getExpression();
|
||||
String i18NText = getI18NText(bean.getKey(), bean.getValue(), bundleName, template);
|
||||
PsiExpression expression = factory.createExpressionFromText(i18NText, literalExpression);
|
||||
literalExpression.replace(expression);
|
||||
}
|
||||
}, files.toArray(PsiFile.EMPTY_ARRAY));
|
||||
}
|
||||
}
|
||||
|
||||
private static String getI18NText(String key, String value, String bundleName, FileTemplate template) {
|
||||
Map<String, String> attributes = new THashMap<>();
|
||||
attributes.put(JavaI18nizeQuickFixDialog.PROPERTY_KEY_OPTION_KEY, StringUtil.escapeStringCharacters(key));
|
||||
attributes.put(JavaI18nizeQuickFixDialog.RESOURCE_BUNDLE_OPTION_KEY, bundleName);
|
||||
attributes.put(JavaI18nizeQuickFixDialog.PROPERTY_VALUE_ATTR, StringUtil.escapeStringCharacters(value));
|
||||
|
||||
String text = null;
|
||||
try {
|
||||
text = template.getText(attributes);
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
private static class I18NBatchDialog extends DialogWrapper {
|
||||
private static final @NonNls String LAST_USED_PROPERTIES_FILE = "LAST_USED_PROPERTIES_FILE";
|
||||
|
||||
@NotNull private final Project myProject;
|
||||
private final List<ReplacementBean> myKeyValuePairs;
|
||||
private JComboBox<String> myPropertiesFile;
|
||||
|
||||
protected I18NBatchDialog(@NotNull Project project, List<ReplacementBean> keyValuePairs) {
|
||||
super(project, true);
|
||||
myProject = project;
|
||||
myKeyValuePairs = keyValuePairs;
|
||||
setTitle(CodeInsightBundle.message("i18nize.dialog.title"));
|
||||
init();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected JComponent createNorthPanel() {
|
||||
List<String> files = I18nUtil.defaultSuggestPropertiesFiles(myProject);
|
||||
myPropertiesFile = new ComboBox<>(ArrayUtil.toStringArray(files));
|
||||
new ComboboxSpeedSearch(myPropertiesFile);
|
||||
if (!files.isEmpty()) {
|
||||
myPropertiesFile.setSelectedItem(ObjectUtils.notNull(PropertiesComponent.getInstance(myProject).getValue(LAST_USED_PROPERTIES_FILE),
|
||||
files.get(0)));
|
||||
}
|
||||
LabeledComponent<JComboBox<String>> component = new LabeledComponent<>();
|
||||
component.setText("Property file:");
|
||||
component.setComponent(myPropertiesFile);
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
protected PropertiesFile getPropertiesFile() {
|
||||
Object selectedItem = myPropertiesFile.getSelectedItem();
|
||||
if (selectedItem == null) return null;
|
||||
String path = FileUtil.toSystemIndependentName((String)selectedItem);
|
||||
VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByPath(path);
|
||||
return virtualFile != null
|
||||
? PropertiesImplUtil.getPropertiesFile(PsiManager.getInstance(myProject).findFile(virtualFile))
|
||||
: null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected JComponent createCenterPanel() {
|
||||
JBTable table = new JBTable(new MyKeyValueModel());
|
||||
return ToolbarDecorator.createDecorator(table).setRemoveAction(new AnActionButtonRunnable() {
|
||||
@Override
|
||||
public void run(AnActionButton button) {
|
||||
TableUtil.removeSelectedItems(table);
|
||||
table.repaint();
|
||||
}
|
||||
}).createPanel();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doOKAction() {
|
||||
PropertiesComponent.getInstance(myProject).setValue(LAST_USED_PROPERTIES_FILE, (String)myPropertiesFile.getSelectedItem());
|
||||
super.doOKAction();
|
||||
}
|
||||
|
||||
private class MyKeyValueModel extends AbstractTableModel implements ItemRemovable {
|
||||
@Override
|
||||
public int getRowCount() {
|
||||
return myKeyValuePairs.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName(int column) {
|
||||
return column == 0 ? "Key" : "Value";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCellEditable(int rowIndex, int columnIndex) {
|
||||
return columnIndex == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValueAt(int rowIndex, int columnIndex) {
|
||||
ReplacementBean pair = myKeyValuePairs.get(rowIndex);
|
||||
return columnIndex == 0 ? pair.getKey() : pair.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
|
||||
if (columnIndex == 0) {
|
||||
ReplacementBean bean = myKeyValuePairs.get(rowIndex);
|
||||
myKeyValuePairs.set(rowIndex, new ReplacementBean((String)aValue, bean.getValue(), bean.getExpression()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRow(int idx) {
|
||||
myKeyValuePairs.remove(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class ReplacementBean {
|
||||
private final String myKey;
|
||||
private final String myValue;
|
||||
private final PsiLiteralExpression myExpression;
|
||||
|
||||
private ReplacementBean(String key, String value, PsiLiteralExpression expression) {
|
||||
myKey = key;
|
||||
myValue = value;
|
||||
myExpression = expression;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return myKey;
|
||||
}
|
||||
|
||||
private String getValue() {
|
||||
return myValue;
|
||||
}
|
||||
|
||||
private PsiLiteralExpression getExpression() {
|
||||
return myExpression;
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -56,7 +56,7 @@ public class JavaI18nizeQuickFixDialog extends I18nizeQuickFixDialog {
|
||||
private final boolean myShowPreview;
|
||||
|
||||
@NonNls public static final String PROPERTY_KEY_OPTION_KEY = "PROPERTY_KEY";
|
||||
@NonNls private static final String RESOURCE_BUNDLE_OPTION_KEY = "RESOURCE_BUNDLE";
|
||||
@NonNls public static final String RESOURCE_BUNDLE_OPTION_KEY = "RESOURCE_BUNDLE";
|
||||
@NonNls public static final String PROPERTY_VALUE_ATTR = "PROPERTY_VALUE";
|
||||
|
||||
public JavaI18nizeQuickFixDialog(@NotNull Project project,
|
||||
|
||||
+9
-8
@@ -209,11 +209,13 @@ public class I18nizeQuickFixDialog extends DialogWrapper implements I18nizeQuick
|
||||
if (myCustomization.suggestedName != null) {
|
||||
return myCustomization.suggestedName;
|
||||
}
|
||||
return suggestUniquePropertyKey(value, defaultSuggestPropertyKey(value), getPropertiesFile());
|
||||
}
|
||||
|
||||
public static String suggestUniquePropertyKey(String value, String defaultKey, PropertiesFile propertiesFile) {
|
||||
// suggest property key not existing in this file
|
||||
String key = defaultSuggestPropertyKey(value);
|
||||
value = PATTERN.matcher(Normalizer.normalize(value, Normalizer.Form.NFD)).replaceAll("");
|
||||
if (key == null) {
|
||||
if (defaultKey == null) {
|
||||
final StringBuilder result = new StringBuilder();
|
||||
boolean insertDotBeforeNextWord = false;
|
||||
for (int i = 0; i < value.length(); i++) {
|
||||
@@ -241,21 +243,20 @@ public class I18nizeQuickFixDialog extends DialogWrapper implements I18nizeQuick
|
||||
}
|
||||
}
|
||||
}
|
||||
key = result.toString();
|
||||
defaultKey = result.toString();
|
||||
}
|
||||
|
||||
PropertiesFile propertiesFile = getPropertiesFile();
|
||||
if (propertiesFile != null) {
|
||||
if (propertiesFile.findPropertyByKey(key) == null) return key;
|
||||
if (propertiesFile.findPropertyByKey(defaultKey) == null) return defaultKey;
|
||||
|
||||
int suffix = 1;
|
||||
while (propertiesFile.findPropertyByKey(key + suffix) != null) {
|
||||
while (propertiesFile.findPropertyByKey(defaultKey + suffix) != null) {
|
||||
suffix++;
|
||||
}
|
||||
return key + suffix;
|
||||
return defaultKey + suffix;
|
||||
}
|
||||
else {
|
||||
return key;
|
||||
return defaultKey;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user