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); }