From 707b118184ac551609a4b6cd4282842dde17cb7a Mon Sep 17 00:00:00 2001 From: Steven Ng Date: Mon, 13 Sep 2021 11:54:58 +0100 Subject: [PATCH] Use ICU to format plural strings Test: manual Fix: 199230208 Change-Id: I0b6fe9f8bb134a1479117c832575c63da2a07794 --- res/values/strings.xml | 30 ++++++------- src/com/android/launcher3/BubbleTextView.java | 17 ++++++- .../launcher3/util/PluralMessageFormat.java | 45 +++++++++++++++++++ .../widget/picker/WidgetsListHeader.java | 17 +++---- 4 files changed, 84 insertions(+), 25 deletions(-) create mode 100644 src/com/android/launcher3/util/PluralMessageFormat.java diff --git a/res/values/strings.xml b/res/values/strings.xml index a6105ebe4a..323c5ca554 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -67,17 +67,15 @@ button in a dialog. [CHAR_LIMIT=none] --> %1$s widget added to home screen - - %1$d widget - %1$d widgets - + [CHAR_LIMIT=25][ICU SYNTAX] --> + + {count, plural, =1{# widget} other{# widgets}} + - - %1$d shortcut - %1$d shortcuts - + [CHAR_LIMIT=25][ICU SYNTAX] --> + + {count, plural, =1{# shortcut} other{# shortcuts}} + %1$s, %2$s @@ -212,11 +210,13 @@ Disabled %1$s - - - %1$s, has %2$d notification - %1$s, has %2$d notifications - + + + {count, plural, offset:1 + =1 {{app_name} has # notification} + other {{app_name} has # notifications} + } + diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index 54920e1e17..f6c58c4719 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -32,6 +32,7 @@ import android.graphics.PointF; import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; +import android.icu.text.MessageFormat; import android.text.TextUtils.TruncateAt; import android.util.AttributeSet; import android.util.Property; @@ -68,6 +69,8 @@ import com.android.launcher3.views.ActivityContext; import com.android.launcher3.views.IconLabelDotView; import java.text.NumberFormat; +import java.util.HashMap; +import java.util.Locale; /** * TextView that draws a bubble behind the text. We cannot use a LineBackgroundSpan @@ -695,8 +698,8 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, itemInfo.contentDescription)); } else if (hasDot()) { int count = mDotInfo.getNotificationCount(); - setContentDescription(getContext().getResources().getQuantityString( - R.plurals.dotted_app_label, count, itemInfo.contentDescription, count)); + setContentDescription( + getAppLabelPluralString(itemInfo.contentDescription.toString(), count)); } else { setContentDescription(itemInfo.contentDescription); } @@ -938,4 +941,14 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, setCompoundDrawables(null, newIcon, null, null); } } + + private String getAppLabelPluralString(String appName, int notificationCount) { + MessageFormat icuCountFormat = new MessageFormat( + getResources().getString(R.string.dotted_app_label), + Locale.getDefault()); + HashMap args = new HashMap(); + args.put("app_name", appName); + args.put("count", notificationCount); + return icuCountFormat.format(args); + } } diff --git a/src/com/android/launcher3/util/PluralMessageFormat.java b/src/com/android/launcher3/util/PluralMessageFormat.java new file mode 100644 index 0000000000..5e4ce8d982 --- /dev/null +++ b/src/com/android/launcher3/util/PluralMessageFormat.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.util; + +import android.content.Context; +import android.icu.text.MessageFormat; + +import androidx.annotation.StringRes; + +import java.util.HashMap; +import java.util.Locale; + +/** A helper class to format common ICU plural strings. */ +public class PluralMessageFormat { + + /** + * Returns a plural string from a ICU format message template, which takes "count" as an + * argument. + * + *

An example of ICU format message template provided by {@code stringId}: + * {count, plural, =1{# widget} other{# widgets}} + */ + public static final String getIcuPluralString(Context context, @StringRes int stringId, + int count) { + MessageFormat icuCountFormat = new MessageFormat( + context.getResources().getString(stringId), + Locale.getDefault()); + HashMap args = new HashMap(); + args.put("count", count); + return icuCountFormat.format(args); + } +} diff --git a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java index ef2adbb809..ebd2d1014c 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java +++ b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java @@ -39,6 +39,7 @@ import com.android.launcher3.icons.PlaceHolderIconDrawable; import com.android.launcher3.icons.cache.HandlerRunnable; import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.model.data.PackageItemInfo; +import com.android.launcher3.util.PluralMessageFormat; import com.android.launcher3.views.ActivityContext; import com.android.launcher3.widget.model.WidgetsListHeaderEntry; import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry; @@ -217,18 +218,18 @@ public final class WidgetsListHeader extends LinearLayout implements ItemInfoUpd String subtitle; if (entry.widgetsCount > 0 && entry.shortcutsCount > 0) { - String widgetsCount = resources.getQuantityString(R.plurals.widgets_count, - entry.widgetsCount, entry.widgetsCount); - String shortcutsCount = resources.getQuantityString(R.plurals.shortcuts_count, - entry.shortcutsCount, entry.shortcutsCount); + String widgetsCount = PluralMessageFormat.getIcuPluralString(getContext(), + R.string.widgets_count, entry.widgetsCount); + String shortcutsCount = PluralMessageFormat.getIcuPluralString(getContext(), + R.string.shortcuts_count, entry.shortcutsCount); subtitle = resources.getString(R.string.widgets_and_shortcuts_count, widgetsCount, shortcutsCount); } else if (entry.widgetsCount > 0) { - subtitle = resources.getQuantityString(R.plurals.widgets_count, - entry.widgetsCount, entry.widgetsCount); + subtitle = PluralMessageFormat.getIcuPluralString(getContext(), + R.string.widgets_count, entry.widgetsCount); } else { - subtitle = resources.getQuantityString(R.plurals.shortcuts_count, - entry.shortcutsCount, entry.shortcutsCount); + subtitle = PluralMessageFormat.getIcuPluralString(getContext(), + R.string.shortcuts_count, entry.shortcutsCount); } mSubtitle.setText(subtitle); mSubtitle.setVisibility(VISIBLE);