diff --git a/.idea/libraries/icu4j.xml b/.idea/libraries/icu4j.xml
new file mode 100644
index 000000000000..3f51736a0e4e
--- /dev/null
+++ b/.idea/libraries/icu4j.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java
index 41cbb6b87909..37cb1e921c4e 100644
--- a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java
+++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java
@@ -8,6 +8,7 @@ import com.intellij.compiler.progress.CompilerMessagesService;
import com.intellij.compiler.progress.CompilerTask;
import com.intellij.compiler.server.BuildManager;
import com.intellij.compiler.server.DefaultMessageHandler;
+import com.intellij.ide.nls.NlsMessages;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationListener;
import com.intellij.openapi.application.ApplicationManager;
@@ -558,7 +559,7 @@ public final class CompileDriver {
message = JavaCompilerBundle.message("status.all.up.to.date");
}
else {
- String durationString = StringUtil.formatDurationApproximate(duration);
+ String durationString = NlsMessages.formatDurationApproximate(duration);
if (status == ExitStatus.SUCCESS) {
message = warningCount > 0
? JavaCompilerBundle.message("status.compilation.completed.successfully.with.warnings", warningCount, durationString)
diff --git a/java/java-analysis-impl/src/com/intellij/find/findUsages/JavaFindUsagesOptions.java b/java/java-analysis-impl/src/com/intellij/find/findUsages/JavaFindUsagesOptions.java
index 00cee057d2b1..af8ad65de1dc 100644
--- a/java/java-analysis-impl/src/com/intellij/find/findUsages/JavaFindUsagesOptions.java
+++ b/java/java-analysis-impl/src/com/intellij/find/findUsages/JavaFindUsagesOptions.java
@@ -16,9 +16,9 @@
package com.intellij.find.findUsages;
import com.intellij.analysis.AnalysisBundle;
+import com.intellij.ide.nls.NlsMessages;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.search.SearchScope;
import org.jetbrains.annotations.NotNull;
@@ -92,12 +92,11 @@ public abstract class JavaFindUsagesOptions extends PersistentFindUsagesOptions
@NotNull
@Override
public final String generateUsagesString() {
- String separator = " " + AnalysisBundle.message("find.usages.panel.title.separator") + " ";
LinkedHashSet strings = new LinkedHashSet<>();
addUsageTypes(strings);
if (strings.isEmpty()) {
- strings.add(AnalysisBundle.message("find.usages.panel.title.usages"));
+ return AnalysisBundle.message("find.usages.panel.title.usages");
}
- return StringUtil.join(strings, separator);
+ return NlsMessages.formatOrList(strings);
}
}
diff --git a/java/java-impl/src/com/intellij/codeInspection/streamMigration/FuseStreamOperationsInspection.java b/java/java-impl/src/com/intellij/codeInspection/streamMigration/FuseStreamOperationsInspection.java
index 6fe9e929f768..33ac89e1f80b 100644
--- a/java/java-impl/src/com/intellij/codeInspection/streamMigration/FuseStreamOperationsInspection.java
+++ b/java/java-impl/src/com/intellij/codeInspection/streamMigration/FuseStreamOperationsInspection.java
@@ -4,6 +4,7 @@ package com.intellij.codeInspection.streamMigration;
import com.intellij.codeInspection.*;
import com.intellij.codeInspection.streamMigration.CollectMigration.CollectTerminal;
import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel;
+import com.intellij.ide.nls.NlsMessages;
import com.intellij.java.JavaBundle;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
@@ -21,7 +22,6 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.Objects;
-import java.util.function.Function;
import static com.intellij.util.ObjectUtils.tryCast;
@@ -137,9 +137,7 @@ public class FuseStreamOperationsInspection extends AbstractBaseJavaLocalInspect
if (newTerminal == null) return;
PsiElement nameElement = call.getMethodExpression().getReferenceNameElement();
if (nameElement == null) return;
- String fusedSteps = newTerminal.fusedElements()
- .mapLastOrElse(s -> StreamEx.of(", ", s), s -> StreamEx.of(" and ", s))
- .flatMap(Function.identity()).skip(1).joining();
+ String fusedSteps = newTerminal.fusedElements().collect(NlsMessages.joiningAnd());
holder.registerProblem(nameElement,
JavaBundle.message("inspection.fuse.stream.operations.message", fusedSteps),
new FuseStreamOperationsFix(fusedSteps, myStrictMode));
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/fuseStreamOperations/afterSetListSort.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/fuseStreamOperations/afterSetListSort.java
index 910636d4c1b9..28f26b815f85 100644
--- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/fuseStreamOperations/afterSetListSort.java
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/fuseStreamOperations/afterSetListSort.java
@@ -1,4 +1,4 @@
-// "Fuse ArrayList, 'sort' and 'toArray' into the Stream API chain" "true"
+// "Fuse ArrayList, 'sort', and 'toArray' into the Stream API chain" "true"
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/fuseStreamOperations/beforeSetListSort.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/fuseStreamOperations/beforeSetListSort.java
index 5b48320bfdea..5abf7d4dcb82 100644
--- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/fuseStreamOperations/beforeSetListSort.java
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/fuseStreamOperations/beforeSetListSort.java
@@ -1,4 +1,4 @@
-// "Fuse ArrayList, 'sort' and 'toArray' into the Stream API chain" "true"
+// "Fuse ArrayList, 'sort', and 'toArray' into the Stream API chain" "true"
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaAnnotatorChecker.java b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaAnnotatorChecker.java
index 6a1f79315cbb..cee01732d739 100644
--- a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaAnnotatorChecker.java
+++ b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaAnnotatorChecker.java
@@ -2,6 +2,7 @@
package com.jetbrains.jsonSchema.impl;
import com.intellij.codeInspection.util.InspectionMessage;
+import com.intellij.ide.nls.NlsMessages;
import com.intellij.json.JsonBundle;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.NlsSafe;
@@ -564,7 +565,7 @@ public final class JsonSchemaAnnotatorChecker implements JsonValidationHost {
if (commonIssueKind == JsonValidationError.FixableIssueKind.MissingProperty) {
String sets = errors.stream().map(e -> (JsonValidationError.MissingMultiplePropsIssueData)e.getIssueData())
- .map(d -> d.getMessage(false)).collect(Collectors.joining(", or "));
+ .map(d -> d.getMessage(false)).collect(NlsMessages.joiningOr());
return new JsonValidationError(JsonBundle.message(
isOneOf ? "schema.validation.one.of.property.sets.required" : "schema.validation.at.least.one.of.property.sets.required", sets),
isOneOf ? JsonValidationError.FixableIssueKind.MissingOneOfProperty : JsonValidationError.FixableIssueKind.MissingAnyOfProperty,
diff --git a/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaHighlightingTest.java b/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaHighlightingTest.java
index a95bb3621d62..3f48e1bb4ab2 100644
--- a/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaHighlightingTest.java
+++ b/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaHighlightingTest.java
@@ -944,7 +944,7 @@ public class JsonSchemaHighlightingTest extends JsonSchemaHighlightingTestBase {
public void testMissingMultipleAltPropertySets() throws Exception {
@Language("JSON") String schemaText = FileUtil.loadFile(new File(getTestDataPath() + "/avroSchema.json"));
- doTest(schemaText, "{\n" +
+ doTest(schemaText, "{\n" +
" \n" +
"}");
}
diff --git a/lib/annotations/icu4j/com/ibm/icu/text/annotations.xml b/lib/annotations/icu4j/com/ibm/icu/text/annotations.xml
new file mode 100644
index 000000000000..718eb3dc1ebe
--- /dev/null
+++ b/lib/annotations/icu4j/com/ibm/icu/text/annotations.xml
@@ -0,0 +1,8 @@
+
+ -
+
+
+ -
+
+
+
\ No newline at end of file
diff --git a/platform/analysis-api/resources/messages/AnalysisBundle.properties b/platform/analysis-api/resources/messages/AnalysisBundle.properties
index 6f36381a3dbc..db09859f125c 100644
--- a/platform/analysis-api/resources/messages/AnalysisBundle.properties
+++ b/platform/analysis-api/resources/messages/AnalysisBundle.properties
@@ -11,7 +11,6 @@ default.path.evaluator.option=Tells reference provider how evaluate default path
error.cannot.resolve=Cannot resolve
error.cannot.resolve.file.or.dir=Cannot resolve {0} ''{1}''
error.cannot.resolve.default.message=Cannot resolve symbol ''{0}''
-find.usages.panel.title.separator=or
find.usages.panel.title.usages=Usages
forward.dependencies.usage.view.initial.text=Select where to search in left tree and what to search in right tree.
forward.dependencies.usage.view.root.node.text=Usages of the right tree scope selection in the left tree scope selection
diff --git a/platform/analysis-impl/src/com/intellij/find/findUsages/FindUsagesOptions.java b/platform/analysis-impl/src/com/intellij/find/findUsages/FindUsagesOptions.java
index b6e1a5563f73..3bbd1cbb54c9 100644
--- a/platform/analysis-impl/src/com/intellij/find/findUsages/FindUsagesOptions.java
+++ b/platform/analysis-impl/src/com/intellij/find/findUsages/FindUsagesOptions.java
@@ -10,10 +10,7 @@ import com.intellij.psi.search.PredefinedSearchScopeProvider;
import com.intellij.psi.search.ProjectScope;
import com.intellij.psi.search.SearchRequestCollector;
import com.intellij.psi.search.SearchScope;
-import org.jetbrains.annotations.ApiStatus;
-import org.jetbrains.annotations.NonNls;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.*;
import java.util.List;
@@ -94,7 +91,7 @@ public class FindUsagesOptions implements Cloneable {
}
@NotNull
- public String generateUsagesString() {
+ public @Nls String generateUsagesString() {
return AnalysisBundle.message("find.usages.panel.title.usages");
}
}
diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy
index bfa1b9205029..9187d41b47c5 100644
--- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy
+++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy
@@ -302,6 +302,8 @@ class CommunityLibraryLicenses {
new LibraryLicense(name: "Hunspell", libraryName: "com.gitlab.dumonts:hunspell:1.1.1",
license: "Apache 2.0", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0.txt",
url: "https://gitlab.com/dumonts/hunspell-java"),
+ new LibraryLicense(name: "ICU4J", libraryName: "icu4j", license: "Unicode",
+ url: "http://site.icu-project.org/", licenseUrl: "http://www.unicode.org/copyright.html"),
new LibraryLicense(name: "imgscalr", libraryName: "imgscalr", license: "Apache 2.0",
licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0.txt", url: "https://github.com/thebuzzmedia/imgscalr"),
new LibraryLicense(name: "Inconsolata", attachedTo: "intellij.platform.resources", version: "001.010", license: "OFL",
diff --git a/platform/lang-impl/src/com/intellij/build/ExecutionNode.java b/platform/lang-impl/src/com/intellij/build/ExecutionNode.java
index a0bcc54eb547..582265cc7a32 100644
--- a/platform/lang-impl/src/com/intellij/build/ExecutionNode.java
+++ b/platform/lang-impl/src/com/intellij/build/ExecutionNode.java
@@ -3,6 +3,7 @@ package com.intellij.build;
import com.intellij.build.events.*;
import com.intellij.icons.AllIcons;
+import com.intellij.ide.nls.NlsMessages;
import com.intellij.ide.projectView.PresentationData;
import com.intellij.ide.util.treeView.PresentableNodeDescriptor;
import com.intellij.lang.LangBundle;
@@ -15,6 +16,7 @@ import com.intellij.ui.SimpleTextAttributes;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -152,17 +154,17 @@ public class ExecutionNode extends PresentableNodeDescriptor {
// Note: invoked from the EDT.
@Nullable
- public String getDuration() {
+ public @Nls String getDuration() {
if (startTime == endTime) return null;
if (isRunning()) {
long duration = startTime == 0 ? 0 : System.currentTimeMillis() - startTime;
if (duration > 1000) {
duration -= duration % 1000;
}
- return StringUtil.formatDurationApproximate(duration);
+ return NlsMessages.formatDurationApproximate(duration);
}
else {
- return isSkipped(myResult) ? null : StringUtil.formatDuration(endTime - startTime);
+ return isSkipped(myResult) ? null : NlsMessages.formatDuration(endTime - startTime);
}
}
diff --git a/platform/platform-api/intellij.platform.ide.iml b/platform/platform-api/intellij.platform.ide.iml
index 20f1a92dea1b..f15be9a3e396 100644
--- a/platform/platform-api/intellij.platform.ide.iml
+++ b/platform/platform-api/intellij.platform.ide.iml
@@ -46,5 +46,6 @@
+
\ No newline at end of file
diff --git a/platform/platform-api/src/com/intellij/ide/nls/NlsMessages.java b/platform/platform-api/src/com/intellij/ide/nls/NlsMessages.java
new file mode 100644
index 000000000000..718b7463ea6f
--- /dev/null
+++ b/platform/platform-api/src/com/intellij/ide/nls/NlsMessages.java
@@ -0,0 +1,155 @@
+// Copyright 2000-2020 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.ide.nls;
+
+import com.ibm.icu.number.FormattedNumber;
+import com.ibm.icu.number.IntegerWidth;
+import com.ibm.icu.number.LocalizedNumberFormatter;
+import com.ibm.icu.number.NumberFormatter;
+import com.ibm.icu.text.ListFormatter;
+import com.ibm.icu.text.MeasureFormat;
+import com.ibm.icu.util.Measure;
+import com.ibm.icu.util.MeasureUnit;
+import com.intellij.DynamicBundle;
+import gnu.trove.TIntArrayList;
+import gnu.trove.TLongArrayList;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+import java.util.stream.Collector;
+import java.util.stream.Collectors;
+
+/**
+ * Utility methods to produce localized messages
+ */
+public class NlsMessages {
+ private static final MeasureUnit[] TIME_UNITS =
+ {MeasureUnit.MILLISECOND, MeasureUnit.SECOND, MeasureUnit.MINUTE, MeasureUnit.HOUR, MeasureUnit.DAY};
+ private static final long[] TIME_MULTIPLIERS = {1, 1000, 60, 60, 24};
+
+ /**
+ * @param list list of items
+ * @return localized string representation of all items in the list semantically joined via 'AND'
+ */
+ public static @NotNull @Nls String formatAndList(Collection> list) {
+ return ListFormatter.getInstance(DynamicBundle.getLocale(), ListFormatter.Type.AND, ListFormatter.Width.WIDE).format(list);
+ }
+
+ /**
+ * @param list list of items
+ * @return localized string representation of all items in the list semantically joined via 'OR'
+ */
+ public static @NotNull @Nls String formatOrList(Collection> list) {
+ return ListFormatter.getInstance(DynamicBundle.getLocale(), ListFormatter.Type.OR, ListFormatter.Width.WIDE).format(list);
+ }
+
+ /**
+ * @return a collector that collects a stream into the localized string that joins the stream elements into the and-list
+ */
+ public static @NotNull Collector joiningAnd() {
+ return Collectors.collectingAndThen(Collectors.toList(), NlsMessages::formatAndList);
+ }
+
+ /**
+ * @return a collector that collects a stream into the localized string that joins the stream elements into the or-list
+ */
+ public static @NotNull Collector joiningOr() {
+ return Collectors.collectingAndThen(Collectors.toList(), NlsMessages::formatOrList);
+ }
+
+ /**
+ * Formats duration given in milliseconds as a sum of time units with at most two units
+ * (example: {@code formatDuration(123456) = "2 m 3 s"}).
+ */
+ @Contract(pure = true)
+ public static @NotNull @Nls String formatDurationApproximate(long duration) {
+ return formatDuration(duration, 2);
+ }
+
+ /**
+ * Formats duration given in milliseconds as a sum of time units (example: {@code formatDuration(123456, "") = "2m 3s 456ms"}).
+ * The result is localized according to the currently used language pack.
+ */
+ @Contract(pure = true)
+ public static @NotNull @Nls String formatDuration(long duration) {
+ return formatDuration(duration, Integer.MAX_VALUE);
+ }
+
+ @Contract(pure = true)
+ private static @NotNull @Nls String formatDuration(long duration, int maxFragments) {
+ TLongArrayList unitValues = new TLongArrayList();
+ TIntArrayList unitIndices = new TIntArrayList();
+
+ long count = duration;
+ int i = 1;
+ for (; i < TIME_UNITS.length && count > 0; i++) {
+ long multiplier = TIME_MULTIPLIERS[i];
+ if (count < multiplier) break;
+ long remainder = count % multiplier;
+ count /= multiplier;
+ if (remainder != 0 || !unitValues.isEmpty()) {
+ unitValues.insert(0, remainder);
+ unitIndices.insert(0, i - 1);
+ }
+ }
+ unitValues.insert(0, count);
+ unitIndices.insert(0, i - 1);
+
+ if (unitValues.size() > maxFragments) {
+ int lastUnitIndex = unitIndices.get(maxFragments - 1);
+ long lastMultiplier = TIME_MULTIPLIERS[lastUnitIndex];
+ // Round up if needed
+ if (unitValues.get(maxFragments) > lastMultiplier / 2) {
+ long increment = lastMultiplier - unitValues.get(maxFragments);
+ for (int unit = lastUnitIndex - 1; unit > 0; unit--) {
+ increment *= TIME_MULTIPLIERS[unit];
+ }
+ return formatDuration(duration + increment, maxFragments);
+ }
+ }
+
+ MeasureFormat format = MeasureFormat.getInstance(DynamicBundle.getLocale(), MeasureFormat.FormatWidth.SHORT);
+ Measure[] measures = new Measure[Math.min(unitValues.size(), maxFragments)];
+ for (i = 0; i < measures.length; i++) {
+ measures[i] = new Measure(unitValues.get(i), TIME_UNITS[unitIndices.get(i)]);
+ }
+ return format.formatMeasures(measures);
+ }
+
+ private static final int[] PADDED_FORMATS = {3, 2, 2, 2, 1};
+ /**
+ * Formats duration given in milliseconds as a sum of padded time units, except the most significant unit
+ * E.g. 234523598 padded as "2d 03h 11m 04s 004ms" accordingly with zeros except "days" here.
+ * @param millis milliseconds
+ */
+ @Contract(pure = true)
+ public static @NotNull @Nls String formatDurationPadded(long millis) {
+ long millisIn = 1;
+ int i;
+ for (i=1; i < TIME_MULTIPLIERS.length; i++) {
+ long multiplier = TIME_MULTIPLIERS[i];
+ millisIn *= multiplier;
+ if (millis < millisIn) {
+ break;
+ }
+ }
+ long d = millis;
+ LocalizedNumberFormatter formatter = NumberFormatter.withLocale(DynamicBundle.getLocale()).unitWidth(NumberFormatter.UnitWidth.NARROW);
+ List result = new ArrayList<>();
+ for (i-=1; i >= 0; i--) {
+ long multiplier = i==TIME_MULTIPLIERS.length-1 ? 1 : TIME_MULTIPLIERS[i+1];
+ millisIn /= multiplier;
+ long value = d / millisIn;
+ d = d % millisIn;
+ IntegerWidth style = IntegerWidth.zeroFillTo(result.isEmpty() ? 1 : PADDED_FORMATS[i]); // do not pad the most significant unit
+ LocalizedNumberFormatter unitFormatter = formatter.unit(TIME_UNITS[i]).integerWidth(style);
+ result.add(unitFormatter.format(value));
+ }
+ return ListFormatter.getInstance(Locale.getDefault(), ListFormatter.Type.UNITS, ListFormatter.Width.NARROW).format(result);
+ }
+
+}
diff --git a/platform/platform-impl/src/com/intellij/featureStatistics/actions/ShowFeatureUsageStatisticsDialog.java b/platform/platform-impl/src/com/intellij/featureStatistics/actions/ShowFeatureUsageStatisticsDialog.java
index 24240e788e4c..69a8b575042f 100644
--- a/platform/platform-impl/src/com/intellij/featureStatistics/actions/ShowFeatureUsageStatisticsDialog.java
+++ b/platform/platform-impl/src/com/intellij/featureStatistics/actions/ShowFeatureUsageStatisticsDialog.java
@@ -4,6 +4,7 @@ package com.intellij.featureStatistics.actions;
import com.intellij.CommonBundle;
import com.intellij.featureStatistics.*;
import com.intellij.ide.IdeBundle;
+import com.intellij.ide.nls.NlsMessages;
import com.intellij.ide.util.TipUIUtil;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
@@ -12,7 +13,6 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Splitter;
import com.intellij.openapi.ui.VerticalFlowLayout;
-import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.ScrollingUtil;
import com.intellij.ui.TableViewSpeedSearch;
@@ -41,7 +41,7 @@ public final class ShowFeatureUsageStatisticsDialog extends DialogWrapper {
private static final Comparator LAST_USED_COMPARATOR =
(fd1, fd2) -> new Date(fd2.getLastTimeUsed()).compareTo(new Date(fd1.getLastTimeUsed()));
- private static final ColumnInfo DISPLAY_NAME = new ColumnInfo(FeatureStatisticsBundle.message("feature.statistics.column.feature")) {
+ private static final ColumnInfo DISPLAY_NAME = new ColumnInfo<>(FeatureStatisticsBundle.message("feature.statistics.column.feature")) {
@Override
public String valueOf(FeatureDescriptor featureDescriptor) {
return featureDescriptor.getDisplayName();
@@ -52,7 +52,7 @@ public final class ShowFeatureUsageStatisticsDialog extends DialogWrapper {
return DISPLAY_NAME_COMPARATOR;
}
};
- private static final ColumnInfo GROUP_NAME = new ColumnInfo(FeatureStatisticsBundle.message("feature.statistics.column.group")) {
+ private static final ColumnInfo GROUP_NAME = new ColumnInfo<>(FeatureStatisticsBundle.message("feature.statistics.column.group")) {
@Override
public String valueOf(FeatureDescriptor featureDescriptor) {
return getGroupName(featureDescriptor);
@@ -63,7 +63,7 @@ public final class ShowFeatureUsageStatisticsDialog extends DialogWrapper {
return GROUP_NAME_COMPARATOR;
}
};
- private static final ColumnInfo USED_TOTAL = new ColumnInfo(FeatureStatisticsBundle.message("feature.statistics.column.usage.count")) {
+ private static final ColumnInfo USED_TOTAL = new ColumnInfo<>(FeatureStatisticsBundle.message("feature.statistics.column.usage.count")) {
@Override
public String valueOf(FeatureDescriptor featureDescriptor) {
int count = featureDescriptor.getUsageCount();
@@ -75,7 +75,7 @@ public final class ShowFeatureUsageStatisticsDialog extends DialogWrapper {
return USAGE_COUNT_COMPARATOR;
}
};
- private static final ColumnInfo LAST_USED = new ColumnInfo(FeatureStatisticsBundle.message("feature.statistics.column.last.used")) {
+ private static final ColumnInfo LAST_USED = new ColumnInfo<>(FeatureStatisticsBundle.message("feature.statistics.column.last.used")) {
@Override
public String valueOf(FeatureDescriptor featureDescriptor) {
long tm = featureDescriptor.getLastTimeUsed();
@@ -130,7 +130,7 @@ public final class ShowFeatureUsageStatisticsDialog extends DialogWrapper {
features.add(registry.getFeatureDescriptor(id));
}
TableView table = new TableView<>(new ListTableModel<>(COLUMNS, features, 0));
- new TableViewSpeedSearch(table) {
+ new TableViewSpeedSearch<>(table) {
@Override
protected String getItemText(@NotNull FeatureDescriptor element) {
return element.getDisplayName();
@@ -146,10 +146,10 @@ public final class ShowFeatureUsageStatisticsDialog extends DialogWrapper {
final String uptimeS = FeatureStatisticsBundle.message("feature.statistics.application.uptime",
ApplicationNamesInfo.getInstance().getFullProductName(),
- StringUtil.formatDurationApproximate(uptime));
+ NlsMessages.formatDurationApproximate(uptime));
final String idleTimeS = FeatureStatisticsBundle.message("feature.statistics.application.idle.time",
- StringUtil.formatDurationApproximate(idleTime));
+ NlsMessages.formatDurationApproximate(idleTime));
String labelText = uptimeS + ", " + idleTimeS;
CompletionStatistics stats = ((FeatureUsageTrackerImpl)FeatureUsageTracker.getInstance()).getCompletionStatistics();
diff --git a/platform/platform-tests/testSrc/com/intellij/ide/nls/NlsMessagesTest.java b/platform/platform-tests/testSrc/com/intellij/ide/nls/NlsMessagesTest.java
new file mode 100644
index 000000000000..1539892b9979
--- /dev/null
+++ b/platform/platform-tests/testSrc/com/intellij/ide/nls/NlsMessagesTest.java
@@ -0,0 +1,88 @@
+// Copyright 2000-2020 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.ide.nls;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Stream;
+
+import static org.junit.Assert.assertEquals;
+
+public class NlsMessagesTest {
+ @Test
+ public void testFormatAnd() {
+ assertEquals("Java, Kotlin, and Groovy", NlsMessages.formatAndList(Arrays.asList("Java", "Kotlin", "Groovy")));
+ }
+
+ @Test
+ public void testFormatOr() {
+ assertEquals("Java, Kotlin, or Groovy", NlsMessages.formatOrList(Arrays.asList("Java", "Kotlin", "Groovy")));
+ }
+
+ @Test
+ public void testJoiningAnd() {
+ assertEquals("Java, Kotlin, and Groovy", Stream.of("Java", "Kotlin", "Groovy").collect(NlsMessages.joiningAnd()));
+ }
+
+ @Test
+ public void testJoiningOr() {
+ assertEquals("Java, Kotlin, or Groovy", Stream.of("Java", "Kotlin", "Groovy").collect(NlsMessages.joiningOr()));
+ }
+
+ @Test
+ public void testFormatDuration() {
+ assertEquals("0 ms", NlsMessages.formatDuration(0));
+ assertEquals("1 ms", NlsMessages.formatDuration(1));
+ assertEquals("1 sec", NlsMessages.formatDuration(1000));
+ assertEquals("24 days, 20 hr, 31 min, 23 sec, 647 ms", NlsMessages.formatDuration(Integer.MAX_VALUE));
+ assertEquals("82 days, 17 hr, 24 min, 43 sec, 647 ms", NlsMessages.formatDuration(Integer.MAX_VALUE+5000000000L));
+
+ assertEquals("1 min, 0 sec, 100 ms", NlsMessages.formatDuration(60100));
+
+ assertEquals("1 sec, 234 ms", NlsMessages.formatDuration(1234));
+ assertEquals("12 sec, 345 ms", NlsMessages.formatDuration(12345));
+ assertEquals("2 min, 3 sec, 456 ms", NlsMessages.formatDuration(123456));
+ assertEquals("20 min, 34 sec, 567 ms", NlsMessages.formatDuration(1234567));
+ assertEquals("3 hr, 25 min, 45 sec, 678 ms", NlsMessages.formatDuration(12345678));
+ assertEquals("1 day, 10 hr, 17 min, 36 sec, 789 ms", NlsMessages.formatDuration(123456789));
+ assertEquals("14 days, 6 hr, 56 min, 7 sec, 890 ms", NlsMessages.formatDuration(1234567890));
+
+ assertEquals("39 days, 2 hr, 30 min, 6 sec, 101 ms", NlsMessages.formatDuration(3378606101L));
+ }
+
+ @Test
+ public void testFormatDurationApproximate() {
+ assertEquals("0 ms", NlsMessages.formatDurationApproximate(0));
+
+ assertEquals("59 sec, 999 ms", NlsMessages.formatDurationApproximate(60000 - 1));
+ assertEquals("1 min", NlsMessages.formatDurationApproximate(60000));
+ assertEquals("1 min, 0 sec", NlsMessages.formatDurationApproximate(60000 + 1));
+
+ assertEquals("2 min", NlsMessages.formatDurationApproximate(120000 - 1));
+ assertEquals("2 min", NlsMessages.formatDurationApproximate(120000));
+ assertEquals("2 min, 0 sec", NlsMessages.formatDurationApproximate(120000 + 1));
+ assertEquals("2 min, 0 sec", NlsMessages.formatDurationApproximate(120000 + 499));
+ assertEquals("2 min, 0 sec", NlsMessages.formatDurationApproximate(120000 + 500));
+ assertEquals("2 min, 1 sec", NlsMessages.formatDurationApproximate(120000 + 501));
+
+ assertEquals("2 min, 3 sec", NlsMessages.formatDurationApproximate(123000));
+ assertEquals("2 min, 4 sec", NlsMessages.formatDurationApproximate(123789));
+ assertEquals("2 min, 3 sec", NlsMessages.formatDurationApproximate(123456));
+ assertEquals("1 hr, 1 min", NlsMessages.formatDurationApproximate(3659009));
+ assertEquals("2 hr", NlsMessages.formatDurationApproximate(7199000));
+ assertEquals("1 day", NlsMessages.formatDurationApproximate((23 * 60 * 60 + 59 * 60 + 59) * 1000L));
+ assertEquals("391 days, 1 hr", NlsMessages.formatDurationApproximate(33786061001L));
+ }
+
+ @Test
+ public void testFormatDurationPadded() {
+ assertEquals("0ms", NlsMessages.formatDurationPadded(0));
+ assertEquals("1s 000ms", NlsMessages.formatDurationPadded(1000));
+ assertEquals("1s 001ms", NlsMessages.formatDurationPadded(1001));
+ assertEquals("2m 00s 000ms", NlsMessages.formatDurationPadded(TimeUnit.MINUTES.toMillis(2)));
+ assertEquals("2h 00m 00s 000ms", NlsMessages.formatDurationPadded(TimeUnit.HOURS.toMillis(2)));
+ assertEquals("2d 00h 00m 00s 000ms", NlsMessages.formatDurationPadded(TimeUnit.DAYS.toMillis(2)));
+ assertEquals("1,434,852d 16h 13m 50s 987ms", NlsMessages.formatDurationPadded(123971271230987L));
+ }
+}
diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/SMTestProxy.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/SMTestProxy.java
index 03725543be1f..3117705c55a8 100644
--- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/SMTestProxy.java
+++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/SMTestProxy.java
@@ -14,6 +14,7 @@ import com.intellij.execution.testframework.sm.runner.states.*;
import com.intellij.execution.testframework.sm.runner.ui.TestsPresentationUtil;
import com.intellij.execution.testframework.stacktrace.DiffHyperlink;
import com.intellij.ide.DataManager;
+import com.intellij.ide.nls.NlsMessages;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.DumbService;
@@ -417,7 +418,7 @@ public class SMTestProxy extends AbstractTestProxy {
}
private String getDurationPaddedString() {
final Long duration = getDuration();
- return duration != null ? StringUtil.formatDurationPadded(duration.longValue(), "\u2009") : null;
+ return duration != null ? NlsMessages.formatDurationPadded(duration.longValue()) : null;
}
@Override
diff --git a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java
index 40595218b2f3..7e6615d41ef2 100644
--- a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java
+++ b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java
@@ -1438,39 +1438,47 @@ public class StringUtil extends StringUtilRt {
return Formats.formatFileSize(fileSize, unitSeparator);
}
- /** Formats duration given in milliseconds as a sum of time units (example: {@code formatDuration(123456) = "2 m 3 s 456 ms"}). */
+ /**
+ * Formats duration given in milliseconds as a sum of time units (example: {@code formatDuration(123456) = "2 m 3 s 456 ms"}).
+ * This method is intended to be used in non-localized contexts (primarily in log output).
+ * See com.intellij.ide.nls.NlsMessages for localized output.
+ */
@Contract(pure = true)
- public static @NotNull String formatDuration(long duration) {
+ public static @NotNull @NonNls String formatDuration(long duration) {
return Formats.formatDuration(duration);
}
- /** Formats {@link Duration} as a sum of time units (calls {@link #formatDuration(long)} with duration converted to milliseconds) */
+ /**
+ * Formats {@link Duration} as a sum of time units (calls {@link #formatDuration(long)} with duration converted to milliseconds)
+ * This method is intended to be used in non-localized contexts (primarily in log output).
+ * See com.intellij.ide.nls.NlsMessages for localized output.
+ */
@Contract(pure = true)
- public static @NotNull String formatDuration(@NotNull Duration duration) {
+ public static @NotNull @NonNls String formatDuration(@NotNull Duration duration) {
return Formats.formatDuration(duration);
}
/** Formats duration given in milliseconds as a sum of time units (example: {@code formatDuration(123456, "") = "2m 3s 456ms"}). */
@Contract(pure = true)
- public static @NotNull String formatDuration(long duration, @NotNull String unitSeparator) {
+ public static @NotNull @NonNls String formatDuration(long duration, @NotNull String unitSeparator) {
return Formats.formatDuration(duration, unitSeparator);
}
/**
- * Formats duration given in milliseconds as a sum of padded time units, except the most significant unit
- * E.g. 234523598 padded as "2 d 03 h 11 min 04 sec 004 ms" accordingly with zeros except "days" here.
+ * @deprecated use com.intellij.ide.nls.NlsMessages for localized output.
*/
@Contract(pure = true)
- public static @NotNull String formatDurationPadded(long millis, @NotNull String unitSeparator) {
+ @Deprecated
+ public static @NotNull @NonNls String formatDurationPadded(long millis, @NotNull String unitSeparator) {
return Formats.formatDurationPadded(millis, unitSeparator);
}
/**
- * Formats duration given in milliseconds as a sum of time units with at most two units
- * (example: {@code formatDuration(123456) = "2 m 3 s"}).
+ * @deprecated use com.intellij.ide.nls.NlsMessages for localized output.
*/
@Contract(pure = true)
- public static @NotNull String formatDurationApproximate(long duration) {
+ @Deprecated
+ public static @NotNull @NonNls String formatDurationApproximate(long duration) {
return Formats.formatDurationApproximate(duration);
}
diff --git a/platform/util/strings/src/com/intellij/openapi/util/text/Formats.java b/platform/util/strings/src/com/intellij/openapi/util/text/Formats.java
index 5106631b20a2..d7c1306f066f 100644
--- a/platform/util/strings/src/com/intellij/openapi/util/text/Formats.java
+++ b/platform/util/strings/src/com/intellij/openapi/util/text/Formats.java
@@ -85,10 +85,10 @@ public final class Formats {
private static final String[] PADDED_FORMATS = {"%03d", "%02d", "%02d", "%02d", "%d"};
/**
- * Formats duration given in milliseconds as a sum of padded time units, except the most significant unit
- * E.g. 234523598 padded as "2 d 03 h 11 min 04 sec 004 ms" accordingly with zeros except "days" here.
+ * @deprecated use com.intellij.ide.nls.NlsMessages for localized output.
*/
@Contract(pure = true)
+ @Deprecated
public static @NotNull String formatDurationPadded(long millis, @NotNull String unitSeparator) {
StringBuilder result = new StringBuilder();
@@ -115,10 +115,10 @@ public final class Formats {
}
/**
- * Formats duration given in milliseconds as a sum of time units with at most two units
- * (example: {@code formatDuration(123456) = "2 m 3 s"}).
+ * @deprecated use com.intellij.ide.nls.NlsMessages for localized output.
*/
@Contract(pure = true)
+ @Deprecated
public static @NotNull String formatDurationApproximate(long duration) {
return formatDuration(duration, " ", 2);
}