From ed7f39e608d4ff4d42090294017c000ec4460c53 Mon Sep 17 00:00:00 2001 From: Zixuan James Li Date: Wed, 15 Jan 2025 16:34:45 -0500 Subject: [PATCH 01/14] display [nfc]: Mention issue for notification channel name's i18n TODO Signed-off-by: Zixuan James Li --- lib/notifications/display.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/notifications/display.dart b/lib/notifications/display.dart index 8319ee65b1..5d36d09d97 100644 --- a/lib/notifications/display.dart +++ b/lib/notifications/display.dart @@ -204,7 +204,7 @@ class NotificationChannelManager { await _androidHost.createNotificationChannel(NotificationChannel( id: kChannelId, - name: 'Messages', // TODO(i18n) + name: 'Messages', // TODO(#1284) importance: NotificationImportance.high, lightsEnabled: true, soundUrl: defaultSoundUrl, From 419c20ceb3afb6834c98950942b80d0d8a50fced Mon Sep 17 00:00:00 2001 From: Zixuan James Li Date: Wed, 15 Jan 2025 16:57:20 -0500 Subject: [PATCH 02/14] i18n [nfc]: Mention issue for translating styled strings Signed-off-by: Zixuan James Li --- lib/model/compose.dart | 4 ++-- lib/widgets/content.dart | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/model/compose.dart b/lib/model/compose.dart index 13b9d59cf5..a0b633c330 100644 --- a/lib/model/compose.dart +++ b/lib/model/compose.dart @@ -191,7 +191,7 @@ String quoteAndReplyPlaceholder(PerAccountStore store, { SendableNarrow.ofMessage(message, selfUserId: store.selfUserId), nearMessageId: message.id); // See note in [quoteAndReply] about asking `mention` to omit the | part. - return '${userMention(sender!, silent: true)} ${inlineLink('said', url)}: ' // TODO(i18n) ? + return '${userMention(sender!, silent: true)} ${inlineLink('said', url)}: ' // TODO(#1285) '*(loading message ${message.id})*\n'; // TODO(i18n) ? } @@ -215,6 +215,6 @@ String quoteAndReply(PerAccountStore store, { // Could ask `mention` to omit the | part unless the mention is ambiguous… // but that would mean a linear scan through all users, and the extra noise // won't much matter with the already probably-long message link in there too. - return '${userMention(sender!, silent: true)} ${inlineLink('said', url)}:\n' // TODO(i18n) ? + return '${userMention(sender!, silent: true)} ${inlineLink('said', url)}:\n' // TODO(#1285) '${wrapWithBacktickFence(content: rawContent, infoString: 'quote')}'; } diff --git a/lib/widgets/content.dart b/lib/widgets/content.dart index f3b369e876..c2ccd7dbec 100644 --- a/lib/widgets/content.dart +++ b/lib/widgets/content.dart @@ -1570,6 +1570,7 @@ InlineSpan _errorUnimplemented(UnimplementedNode node, {required BuildContext co // because release mode isn't yet about general users but developer demos, // and we want to keep the demos honest. // TODO(#194) think through UX for general release + // TODO(#1285) translate this final htmlNode = node.htmlNode; if (htmlNode is dom.Element) { return TextSpan(children: [ From d1c871b5166d2db6e6c8e2ea949797c4b699aa95 Mon Sep 17 00:00:00 2001 From: Zixuan James Li Date: Thu, 12 Dec 2024 15:02:48 -0500 Subject: [PATCH 03/14] app: Translate the "about" page button on popup menu Signed-off-by: Zixuan James Li --- lib/widgets/app.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/widgets/app.dart b/lib/widgets/app.dart index 75fec7bc8b..9525dffdfe 100644 --- a/lib/widgets/app.dart +++ b/lib/widgets/app.dart @@ -323,6 +323,7 @@ class ChooseAccountPageOverflowButton extends StatelessWidget { @override Widget build(BuildContext context) { + final zulipLocalizations = ZulipLocalizations.of(context); final materialLocalizations = MaterialLocalizations.of(context); return MenuAnchor( menuChildren: [ @@ -330,7 +331,7 @@ class ChooseAccountPageOverflowButton extends StatelessWidget { onPressed: () { Navigator.push(context, AboutZulipPage.buildRoute(context)); }, - child: const Text('About Zulip')), // TODO(i18n) + child: Text(zulipLocalizations.aboutPageTitle)), ], builder: (BuildContext context, MenuController controller, Widget? child) { return IconButton( From 1aa88a4eeee7da62a2f5383aac10f4ce3827c6b9 Mon Sep 17 00:00:00 2001 From: Zixuan James Li Date: Thu, 12 Dec 2024 16:53:45 -0500 Subject: [PATCH 04/14] inbox: Make header titles localizable The comment started with "Strings here left unlocalized" was from #397, which followed an old design: https://www.figma.com/design/1JTNtYo9memgW7vV6d0ygq/Zulip-Mobile?node-id=171-12359&t=ilEg6ymsxO6JLNQ5-0 Since we have now translated these strings, this is no longer true. Signed-off-by: Zixuan James Li --- assets/l10n/app_en.arb | 16 +++++++++++++ lib/generated/l10n/zulip_localizations.dart | 24 +++++++++++++++++++ .../l10n/zulip_localizations_ar.dart | 12 ++++++++++ .../l10n/zulip_localizations_en.dart | 12 ++++++++++ .../l10n/zulip_localizations_ja.dart | 12 ++++++++++ .../l10n/zulip_localizations_nb.dart | 12 ++++++++++ .../l10n/zulip_localizations_pl.dart | 12 ++++++++++ .../l10n/zulip_localizations_ru.dart | 12 ++++++++++ .../l10n/zulip_localizations_sk.dart | 12 ++++++++++ lib/widgets/inbox.dart | 12 ++++++---- lib/widgets/subscription_list.dart | 12 +++++----- 11 files changed, 138 insertions(+), 10 deletions(-) diff --git a/assets/l10n/app_en.arb b/assets/l10n/app_en.arb index 1060027553..0d3ef81aa5 100644 --- a/assets/l10n/app_en.arb +++ b/assets/l10n/app_en.arb @@ -586,6 +586,10 @@ "@recentDmConversationsPageTitle": { "description": "Title for the page with a list of DM conversations." }, + "recentDmConversationsSectionHeader": "Direct messages", + "@recentDmConversationsSectionHeader": { + "description": "Heading for direct messages section on the 'Inbox' message view." + }, "combinedFeedPageTitle": "Combined feed", "@combinedFeedPageTitle": { "description": "Page title for the 'Combined feed' message view." @@ -618,6 +622,18 @@ "numOthers": {"type": "int", "example": "4"} } }, + "pinnedSubscriptionsLabel": "Pinned", + "@pinnedSubscriptionsLabel": { + "description": "Label for the list of pinned subscribed channels." + }, + "unpinnedSubscriptionsLabel": "Unpinned", + "@unpinnedSubscriptionsLabel": { + "description": "Label for the list of unpinned subscribed channels." + }, + "subscriptionListNoChannels": "No channels found", + "@subscriptionListNoChannels": { + "description": "Text to display on subscribed-channels page when there are no subscribed channels." + }, "notifSelfUser": "You", "@notifSelfUser": { "description": "Display name for the user themself, to show after replying in an Android notification" diff --git a/lib/generated/l10n/zulip_localizations.dart b/lib/generated/l10n/zulip_localizations.dart index 501eb577bf..852deaedce 100644 --- a/lib/generated/l10n/zulip_localizations.dart +++ b/lib/generated/l10n/zulip_localizations.dart @@ -891,6 +891,12 @@ abstract class ZulipLocalizations { /// **'Direct messages'** String get recentDmConversationsPageTitle; + /// Heading for direct messages section on the 'Inbox' message view. + /// + /// In en, this message translates to: + /// **'Direct messages'** + String get recentDmConversationsSectionHeader; + /// Page title for the 'Combined feed' message view. /// /// In en, this message translates to: @@ -933,6 +939,24 @@ abstract class ZulipLocalizations { /// **'{senderFullName} to you and {numOthers, plural, =1{1 other} other{{numOthers} others}}'** String notifGroupDmConversationLabel(String senderFullName, int numOthers); + /// Label for the list of pinned subscribed channels. + /// + /// In en, this message translates to: + /// **'Pinned'** + String get pinnedSubscriptionsLabel; + + /// Label for the list of unpinned subscribed channels. + /// + /// In en, this message translates to: + /// **'Unpinned'** + String get unpinnedSubscriptionsLabel; + + /// Text to display on subscribed-channels page when there are no subscribed channels. + /// + /// In en, this message translates to: + /// **'No channels found'** + String get subscriptionListNoChannels; + /// Display name for the user themself, to show after replying in an Android notification /// /// In en, this message translates to: diff --git a/lib/generated/l10n/zulip_localizations_ar.dart b/lib/generated/l10n/zulip_localizations_ar.dart index 721b20ac02..af97ef3e1c 100644 --- a/lib/generated/l10n/zulip_localizations_ar.dart +++ b/lib/generated/l10n/zulip_localizations_ar.dart @@ -463,6 +463,9 @@ class ZulipLocalizationsAr extends ZulipLocalizations { @override String get recentDmConversationsPageTitle => 'Direct messages'; + @override + String get recentDmConversationsSectionHeader => 'Direct messages'; + @override String get combinedFeedPageTitle => 'Combined feed'; @@ -492,6 +495,15 @@ class ZulipLocalizationsAr extends ZulipLocalizations { return '$senderFullName to you and $_temp0'; } + @override + String get pinnedSubscriptionsLabel => 'Pinned'; + + @override + String get unpinnedSubscriptionsLabel => 'Unpinned'; + + @override + String get subscriptionListNoChannels => 'No channels found'; + @override String get notifSelfUser => 'You'; diff --git a/lib/generated/l10n/zulip_localizations_en.dart b/lib/generated/l10n/zulip_localizations_en.dart index 6936cfe736..7335c5e328 100644 --- a/lib/generated/l10n/zulip_localizations_en.dart +++ b/lib/generated/l10n/zulip_localizations_en.dart @@ -463,6 +463,9 @@ class ZulipLocalizationsEn extends ZulipLocalizations { @override String get recentDmConversationsPageTitle => 'Direct messages'; + @override + String get recentDmConversationsSectionHeader => 'Direct messages'; + @override String get combinedFeedPageTitle => 'Combined feed'; @@ -492,6 +495,15 @@ class ZulipLocalizationsEn extends ZulipLocalizations { return '$senderFullName to you and $_temp0'; } + @override + String get pinnedSubscriptionsLabel => 'Pinned'; + + @override + String get unpinnedSubscriptionsLabel => 'Unpinned'; + + @override + String get subscriptionListNoChannels => 'No channels found'; + @override String get notifSelfUser => 'You'; diff --git a/lib/generated/l10n/zulip_localizations_ja.dart b/lib/generated/l10n/zulip_localizations_ja.dart index c431471645..ff11b47323 100644 --- a/lib/generated/l10n/zulip_localizations_ja.dart +++ b/lib/generated/l10n/zulip_localizations_ja.dart @@ -463,6 +463,9 @@ class ZulipLocalizationsJa extends ZulipLocalizations { @override String get recentDmConversationsPageTitle => 'Direct messages'; + @override + String get recentDmConversationsSectionHeader => 'Direct messages'; + @override String get combinedFeedPageTitle => 'Combined feed'; @@ -492,6 +495,15 @@ class ZulipLocalizationsJa extends ZulipLocalizations { return '$senderFullName to you and $_temp0'; } + @override + String get pinnedSubscriptionsLabel => 'Pinned'; + + @override + String get unpinnedSubscriptionsLabel => 'Unpinned'; + + @override + String get subscriptionListNoChannels => 'No channels found'; + @override String get notifSelfUser => 'You'; diff --git a/lib/generated/l10n/zulip_localizations_nb.dart b/lib/generated/l10n/zulip_localizations_nb.dart index fc530fccaa..6bb634fccd 100644 --- a/lib/generated/l10n/zulip_localizations_nb.dart +++ b/lib/generated/l10n/zulip_localizations_nb.dart @@ -463,6 +463,9 @@ class ZulipLocalizationsNb extends ZulipLocalizations { @override String get recentDmConversationsPageTitle => 'Direct messages'; + @override + String get recentDmConversationsSectionHeader => 'Direct messages'; + @override String get combinedFeedPageTitle => 'Combined feed'; @@ -492,6 +495,15 @@ class ZulipLocalizationsNb extends ZulipLocalizations { return '$senderFullName to you and $_temp0'; } + @override + String get pinnedSubscriptionsLabel => 'Pinned'; + + @override + String get unpinnedSubscriptionsLabel => 'Unpinned'; + + @override + String get subscriptionListNoChannels => 'No channels found'; + @override String get notifSelfUser => 'You'; diff --git a/lib/generated/l10n/zulip_localizations_pl.dart b/lib/generated/l10n/zulip_localizations_pl.dart index f817d400a8..98a14c1e97 100644 --- a/lib/generated/l10n/zulip_localizations_pl.dart +++ b/lib/generated/l10n/zulip_localizations_pl.dart @@ -463,6 +463,9 @@ class ZulipLocalizationsPl extends ZulipLocalizations { @override String get recentDmConversationsPageTitle => 'Wiadomości bezpośrednie'; + @override + String get recentDmConversationsSectionHeader => 'Direct messages'; + @override String get combinedFeedPageTitle => 'Mieszany widok'; @@ -492,6 +495,15 @@ class ZulipLocalizationsPl extends ZulipLocalizations { return '$senderFullName do ciebie i $_temp0'; } + @override + String get pinnedSubscriptionsLabel => 'Pinned'; + + @override + String get unpinnedSubscriptionsLabel => 'Unpinned'; + + @override + String get subscriptionListNoChannels => 'No channels found'; + @override String get notifSelfUser => 'Ty'; diff --git a/lib/generated/l10n/zulip_localizations_ru.dart b/lib/generated/l10n/zulip_localizations_ru.dart index f6d8f1e41c..3cfdfde37b 100644 --- a/lib/generated/l10n/zulip_localizations_ru.dart +++ b/lib/generated/l10n/zulip_localizations_ru.dart @@ -463,6 +463,9 @@ class ZulipLocalizationsRu extends ZulipLocalizations { @override String get recentDmConversationsPageTitle => 'Личные сообщения'; + @override + String get recentDmConversationsSectionHeader => 'Direct messages'; + @override String get combinedFeedPageTitle => 'Объединенная лента'; @@ -492,6 +495,15 @@ class ZulipLocalizationsRu extends ZulipLocalizations { return '$senderFullName вам и еще $_temp0'; } + @override + String get pinnedSubscriptionsLabel => 'Pinned'; + + @override + String get unpinnedSubscriptionsLabel => 'Unpinned'; + + @override + String get subscriptionListNoChannels => 'No channels found'; + @override String get notifSelfUser => 'Вы'; diff --git a/lib/generated/l10n/zulip_localizations_sk.dart b/lib/generated/l10n/zulip_localizations_sk.dart index d6e04126d3..faae265da5 100644 --- a/lib/generated/l10n/zulip_localizations_sk.dart +++ b/lib/generated/l10n/zulip_localizations_sk.dart @@ -463,6 +463,9 @@ class ZulipLocalizationsSk extends ZulipLocalizations { @override String get recentDmConversationsPageTitle => 'Priama správa'; + @override + String get recentDmConversationsSectionHeader => 'Direct messages'; + @override String get combinedFeedPageTitle => 'Zlúčený kanál'; @@ -492,6 +495,15 @@ class ZulipLocalizationsSk extends ZulipLocalizations { return '$senderFullName to you and $_temp0'; } + @override + String get pinnedSubscriptionsLabel => 'Pinned'; + + @override + String get unpinnedSubscriptionsLabel => 'Unpinned'; + + @override + String get subscriptionListNoChannels => 'No channels found'; + @override String get notifSelfUser => 'Ty'; diff --git a/lib/widgets/inbox.dart b/lib/widgets/inbox.dart index 598b99beac..5ba771e62b 100644 --- a/lib/widgets/inbox.dart +++ b/lib/widgets/inbox.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import '../api/model/model.dart'; +import '../generated/l10n/zulip_localizations.dart'; import '../model/narrow.dart'; import '../model/recent_dm_conversations.dart'; import '../model/unreads.dart'; @@ -237,7 +238,7 @@ abstract class _HeaderItem extends StatelessWidget { required this.sectionContext, }); - String get title; + String title(ZulipLocalizations zulipLocalizations); IconData get icon; Color collapsedIconColor(BuildContext context); Color uncollapsedIconColor(BuildContext context); @@ -257,6 +258,7 @@ abstract class _HeaderItem extends StatelessWidget { @override Widget build(BuildContext context) { + final zulipLocalizations = ZulipLocalizations.of(context); final designVariables = DesignVariables.of(context); return Material( color: collapsed @@ -291,7 +293,7 @@ abstract class _HeaderItem extends StatelessWidget { ).merge(weightVariableTextStyle(context, wght: 600)), maxLines: 1, overflow: TextOverflow.ellipsis, - title))), + title(zulipLocalizations)))), const SizedBox(width: 12), if (hasMention) const _IconMarker(icon: ZulipIcons.at_sign), Padding(padding: const EdgeInsetsDirectional.only(end: 16), @@ -312,7 +314,8 @@ class _AllDmsHeaderItem extends _HeaderItem { required super.sectionContext, }); - @override String get title => 'Direct messages'; // TODO(i18n) + @override String title(ZulipLocalizations zulipLocalizations) => + zulipLocalizations.recentDmConversationsSectionHeader; @override IconData get icon => ZulipIcons.user; // TODO(design) check if this is the right variable for these @@ -436,7 +439,8 @@ class _StreamHeaderItem extends _HeaderItem { required super.sectionContext, }); - @override String get title => subscription.name; + @override String title(ZulipLocalizations zulipLocalizations) => + subscription.name; @override IconData get icon => iconDataForStream(subscription); @override Color collapsedIconColor(context) => colorSwatchFor(context, subscription).iconOnPlainBackground; diff --git a/lib/widgets/subscription_list.dart b/lib/widgets/subscription_list.dart index 07f9b84c4a..a51e722b51 100644 --- a/lib/widgets/subscription_list.dart +++ b/lib/widgets/subscription_list.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import '../api/model/model.dart'; +import '../generated/l10n/zulip_localizations.dart'; import '../model/narrow.dart'; import '../model/unreads.dart'; import 'icons.dart'; @@ -77,10 +78,8 @@ class _SubscriptionListPageBodyState extends State wit // TODO: Implement collapsible topics - // TODO(i18n): localize strings on page - // Strings here left unlocalized as they likely will not - // exist in the settled design. final store = PerAccountStoreWidget.of(context); + final zulipLocalizations = ZulipLocalizations.of(context); final List pinned = []; final List unpinned = []; @@ -102,11 +101,11 @@ class _SubscriptionListPageBodyState extends State wit if (pinned.isEmpty && unpinned.isEmpty) const _NoSubscriptionsItem(), if (pinned.isNotEmpty) ...[ - const _SubscriptionListHeader(label: "Pinned"), + _SubscriptionListHeader(label: zulipLocalizations.pinnedSubscriptionsLabel), _SubscriptionList(unreadsModel: unreadsModel, subscriptions: pinned), ], if (unpinned.isNotEmpty) ...[ - const _SubscriptionListHeader(label: "Unpinned"), + _SubscriptionListHeader(label: zulipLocalizations.unpinnedSubscriptionsLabel), _SubscriptionList(unreadsModel: unreadsModel, subscriptions: unpinned), ], @@ -124,11 +123,12 @@ class _NoSubscriptionsItem extends StatelessWidget { @override Widget build(BuildContext context) { final designVariables = DesignVariables.of(context); + final zulipLocalizations = ZulipLocalizations.of(context); return SliverToBoxAdapter( child: Padding( padding: const EdgeInsets.all(10), - child: Text("No channels found", + child: Text(zulipLocalizations.subscriptionListNoChannels, textAlign: TextAlign.center, style: TextStyle( color: designVariables.subscriptionListHeaderText, From 449d67093c99269c6ff623913f6d74941560990d Mon Sep 17 00:00:00 2001 From: Zixuan James Li Date: Thu, 12 Dec 2024 17:21:06 -0500 Subject: [PATCH 05/14] profile: Translate strings on _ProfileErrorPage Signed-off-by: Zixuan James Li --- assets/l10n/app_en.arb | 4 ++++ lib/generated/l10n/zulip_localizations.dart | 6 ++++++ lib/generated/l10n/zulip_localizations_ar.dart | 3 +++ lib/generated/l10n/zulip_localizations_en.dart | 3 +++ lib/generated/l10n/zulip_localizations_ja.dart | 3 +++ lib/generated/l10n/zulip_localizations_nb.dart | 3 +++ lib/generated/l10n/zulip_localizations_pl.dart | 3 +++ lib/generated/l10n/zulip_localizations_ru.dart | 3 +++ lib/generated/l10n/zulip_localizations_sk.dart | 3 +++ lib/widgets/profile.dart | 13 +++++++------ 10 files changed, 38 insertions(+), 6 deletions(-) diff --git a/assets/l10n/app_en.arb b/assets/l10n/app_en.arb index 0d3ef81aa5..23574781bb 100644 --- a/assets/l10n/app_en.arb +++ b/assets/l10n/app_en.arb @@ -56,6 +56,10 @@ "@profileButtonSendDirectMessage": { "description": "Label for button in profile screen to navigate to DMs with the shown user." }, + "errorCouldNotShowUserProfile": "Could not show user profile.", + "@errorCouldNotShowUserProfile": { + "description": "Message that appears on the user profile page when the profile cannot be shown." + }, "permissionsNeededTitle": "Permissions needed", "@permissionsNeededTitle": { "description": "Title for dialog asking the user to grant additional permissions." diff --git a/lib/generated/l10n/zulip_localizations.dart b/lib/generated/l10n/zulip_localizations.dart index 852deaedce..5e88add5cc 100644 --- a/lib/generated/l10n/zulip_localizations.dart +++ b/lib/generated/l10n/zulip_localizations.dart @@ -189,6 +189,12 @@ abstract class ZulipLocalizations { /// **'Send direct message'** String get profileButtonSendDirectMessage; + /// Message that appears on the user profile page when the profile cannot be shown. + /// + /// In en, this message translates to: + /// **'Could not show user profile.'** + String get errorCouldNotShowUserProfile; + /// Title for dialog asking the user to grant additional permissions. /// /// In en, this message translates to: diff --git a/lib/generated/l10n/zulip_localizations_ar.dart b/lib/generated/l10n/zulip_localizations_ar.dart index af97ef3e1c..08aa983a63 100644 --- a/lib/generated/l10n/zulip_localizations_ar.dart +++ b/lib/generated/l10n/zulip_localizations_ar.dart @@ -52,6 +52,9 @@ class ZulipLocalizationsAr extends ZulipLocalizations { @override String get profileButtonSendDirectMessage => 'Send direct message'; + @override + String get errorCouldNotShowUserProfile => 'Could not show user profile.'; + @override String get permissionsNeededTitle => 'Permissions needed'; diff --git a/lib/generated/l10n/zulip_localizations_en.dart b/lib/generated/l10n/zulip_localizations_en.dart index 7335c5e328..8eea6261b9 100644 --- a/lib/generated/l10n/zulip_localizations_en.dart +++ b/lib/generated/l10n/zulip_localizations_en.dart @@ -52,6 +52,9 @@ class ZulipLocalizationsEn extends ZulipLocalizations { @override String get profileButtonSendDirectMessage => 'Send direct message'; + @override + String get errorCouldNotShowUserProfile => 'Could not show user profile.'; + @override String get permissionsNeededTitle => 'Permissions needed'; diff --git a/lib/generated/l10n/zulip_localizations_ja.dart b/lib/generated/l10n/zulip_localizations_ja.dart index ff11b47323..16c3e81b85 100644 --- a/lib/generated/l10n/zulip_localizations_ja.dart +++ b/lib/generated/l10n/zulip_localizations_ja.dart @@ -52,6 +52,9 @@ class ZulipLocalizationsJa extends ZulipLocalizations { @override String get profileButtonSendDirectMessage => 'ダイレクトメッセージを送信'; + @override + String get errorCouldNotShowUserProfile => 'Could not show user profile.'; + @override String get permissionsNeededTitle => 'Permissions needed'; diff --git a/lib/generated/l10n/zulip_localizations_nb.dart b/lib/generated/l10n/zulip_localizations_nb.dart index 6bb634fccd..8e22127f0e 100644 --- a/lib/generated/l10n/zulip_localizations_nb.dart +++ b/lib/generated/l10n/zulip_localizations_nb.dart @@ -52,6 +52,9 @@ class ZulipLocalizationsNb extends ZulipLocalizations { @override String get profileButtonSendDirectMessage => 'Send direct message'; + @override + String get errorCouldNotShowUserProfile => 'Could not show user profile.'; + @override String get permissionsNeededTitle => 'Permissions needed'; diff --git a/lib/generated/l10n/zulip_localizations_pl.dart b/lib/generated/l10n/zulip_localizations_pl.dart index 98a14c1e97..aa736ca17b 100644 --- a/lib/generated/l10n/zulip_localizations_pl.dart +++ b/lib/generated/l10n/zulip_localizations_pl.dart @@ -52,6 +52,9 @@ class ZulipLocalizationsPl extends ZulipLocalizations { @override String get profileButtonSendDirectMessage => 'Wyślij wiadomość bezpośrednią'; + @override + String get errorCouldNotShowUserProfile => 'Could not show user profile.'; + @override String get permissionsNeededTitle => 'Wymagane uprawnienia'; diff --git a/lib/generated/l10n/zulip_localizations_ru.dart b/lib/generated/l10n/zulip_localizations_ru.dart index 3cfdfde37b..ec184b355a 100644 --- a/lib/generated/l10n/zulip_localizations_ru.dart +++ b/lib/generated/l10n/zulip_localizations_ru.dart @@ -52,6 +52,9 @@ class ZulipLocalizationsRu extends ZulipLocalizations { @override String get profileButtonSendDirectMessage => 'Отправить личное сообщение'; + @override + String get errorCouldNotShowUserProfile => 'Could not show user profile.'; + @override String get permissionsNeededTitle => 'Требуются разрешения'; diff --git a/lib/generated/l10n/zulip_localizations_sk.dart b/lib/generated/l10n/zulip_localizations_sk.dart index faae265da5..1aa723762a 100644 --- a/lib/generated/l10n/zulip_localizations_sk.dart +++ b/lib/generated/l10n/zulip_localizations_sk.dart @@ -52,6 +52,9 @@ class ZulipLocalizationsSk extends ZulipLocalizations { @override String get profileButtonSendDirectMessage => 'Poslať priamu správu'; + @override + String get errorCouldNotShowUserProfile => 'Could not show user profile.'; + @override String get permissionsNeededTitle => 'Permissions needed'; diff --git a/lib/widgets/profile.dart b/lib/widgets/profile.dart index 57dd76a0ab..e5a7593efc 100644 --- a/lib/widgets/profile.dart +++ b/lib/widgets/profile.dart @@ -121,17 +121,18 @@ class _ProfileErrorPage extends StatelessWidget { @override Widget build(BuildContext context) { + final zulipLocalizations = ZulipLocalizations.of(context); return Scaffold( - appBar: ZulipAppBar(title: const Text('Error')), - body: const SingleChildScrollView( + appBar: ZulipAppBar(title: Text(zulipLocalizations.errorDialogTitle)), + body: SingleChildScrollView( child: Padding( - padding: EdgeInsets.symmetric(horizontal: 16, vertical: 32), + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 32), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon(Icons.error), - SizedBox(width: 4), - Text('Could not show user profile.'), + const Icon(Icons.error), + const SizedBox(width: 4), + Text(zulipLocalizations.errorCouldNotShowUserProfile), ])))); } } From 22e064599b09b7d2c98947463f80da5340989b56 Mon Sep 17 00:00:00 2001 From: Zixuan James Li Date: Thu, 12 Dec 2024 17:30:33 -0500 Subject: [PATCH 06/14] msglist: Localize message list title for "DMs with yourself" Signed-off-by: Zixuan James Li --- assets/l10n/app_en.arb | 4 ++++ lib/generated/l10n/zulip_localizations.dart | 6 ++++++ lib/generated/l10n/zulip_localizations_ar.dart | 3 +++ lib/generated/l10n/zulip_localizations_en.dart | 3 +++ lib/generated/l10n/zulip_localizations_ja.dart | 3 +++ lib/generated/l10n/zulip_localizations_nb.dart | 3 +++ lib/generated/l10n/zulip_localizations_pl.dart | 3 +++ lib/generated/l10n/zulip_localizations_ru.dart | 3 +++ lib/generated/l10n/zulip_localizations_sk.dart | 3 +++ lib/widgets/message_list.dart | 2 +- 10 files changed, 32 insertions(+), 1 deletion(-) diff --git a/assets/l10n/app_en.arb b/assets/l10n/app_en.arb index 23574781bb..0032a57321 100644 --- a/assets/l10n/app_en.arb +++ b/assets/l10n/app_en.arb @@ -344,6 +344,10 @@ "@unknownUserName": { "description": "Name placeholder to use for a user when we don't know their name." }, + "dmsWithYourselfPageTitle": "DMs with yourself", + "@dmsWithYourselfPageTitle": { + "description": "Message list page title for a DM group that only includes yourself." + }, "messageListGroupYouAndOthers": "You and {others}", "@messageListGroupYouAndOthers": { "description": "Message list recipient header for a DM group with others.", diff --git a/lib/generated/l10n/zulip_localizations.dart b/lib/generated/l10n/zulip_localizations.dart index 5e88add5cc..7baf5f3ff6 100644 --- a/lib/generated/l10n/zulip_localizations.dart +++ b/lib/generated/l10n/zulip_localizations.dart @@ -561,6 +561,12 @@ abstract class ZulipLocalizations { /// **'(unknown user)'** String get unknownUserName; + /// Message list page title for a DM group that only includes yourself. + /// + /// In en, this message translates to: + /// **'DMs with yourself'** + String get dmsWithYourselfPageTitle; + /// Message list recipient header for a DM group with others. /// /// In en, this message translates to: diff --git a/lib/generated/l10n/zulip_localizations_ar.dart b/lib/generated/l10n/zulip_localizations_ar.dart index 08aa983a63..743f4e04a7 100644 --- a/lib/generated/l10n/zulip_localizations_ar.dart +++ b/lib/generated/l10n/zulip_localizations_ar.dart @@ -272,6 +272,9 @@ class ZulipLocalizationsAr extends ZulipLocalizations { @override String get unknownUserName => '(unknown user)'; + @override + String get dmsWithYourselfPageTitle => 'DMs with yourself'; + @override String messageListGroupYouAndOthers(String others) { return 'You and $others'; diff --git a/lib/generated/l10n/zulip_localizations_en.dart b/lib/generated/l10n/zulip_localizations_en.dart index 8eea6261b9..883ddd71cf 100644 --- a/lib/generated/l10n/zulip_localizations_en.dart +++ b/lib/generated/l10n/zulip_localizations_en.dart @@ -272,6 +272,9 @@ class ZulipLocalizationsEn extends ZulipLocalizations { @override String get unknownUserName => '(unknown user)'; + @override + String get dmsWithYourselfPageTitle => 'DMs with yourself'; + @override String messageListGroupYouAndOthers(String others) { return 'You and $others'; diff --git a/lib/generated/l10n/zulip_localizations_ja.dart b/lib/generated/l10n/zulip_localizations_ja.dart index 16c3e81b85..4ff8e0e283 100644 --- a/lib/generated/l10n/zulip_localizations_ja.dart +++ b/lib/generated/l10n/zulip_localizations_ja.dart @@ -272,6 +272,9 @@ class ZulipLocalizationsJa extends ZulipLocalizations { @override String get unknownUserName => '(unknown user)'; + @override + String get dmsWithYourselfPageTitle => 'DMs with yourself'; + @override String messageListGroupYouAndOthers(String others) { return 'You and $others'; diff --git a/lib/generated/l10n/zulip_localizations_nb.dart b/lib/generated/l10n/zulip_localizations_nb.dart index 8e22127f0e..ab58f84c90 100644 --- a/lib/generated/l10n/zulip_localizations_nb.dart +++ b/lib/generated/l10n/zulip_localizations_nb.dart @@ -272,6 +272,9 @@ class ZulipLocalizationsNb extends ZulipLocalizations { @override String get unknownUserName => '(unknown user)'; + @override + String get dmsWithYourselfPageTitle => 'DMs with yourself'; + @override String messageListGroupYouAndOthers(String others) { return 'You and $others'; diff --git a/lib/generated/l10n/zulip_localizations_pl.dart b/lib/generated/l10n/zulip_localizations_pl.dart index aa736ca17b..507742a225 100644 --- a/lib/generated/l10n/zulip_localizations_pl.dart +++ b/lib/generated/l10n/zulip_localizations_pl.dart @@ -272,6 +272,9 @@ class ZulipLocalizationsPl extends ZulipLocalizations { @override String get unknownUserName => '(nieznany użytkownik)'; + @override + String get dmsWithYourselfPageTitle => 'DMs with yourself'; + @override String messageListGroupYouAndOthers(String others) { return 'Ty i $others'; diff --git a/lib/generated/l10n/zulip_localizations_ru.dart b/lib/generated/l10n/zulip_localizations_ru.dart index ec184b355a..15942e396f 100644 --- a/lib/generated/l10n/zulip_localizations_ru.dart +++ b/lib/generated/l10n/zulip_localizations_ru.dart @@ -272,6 +272,9 @@ class ZulipLocalizationsRu extends ZulipLocalizations { @override String get unknownUserName => '(неизвестный пользователь)'; + @override + String get dmsWithYourselfPageTitle => 'DMs with yourself'; + @override String messageListGroupYouAndOthers(String others) { return 'Вы и $others'; diff --git a/lib/generated/l10n/zulip_localizations_sk.dart b/lib/generated/l10n/zulip_localizations_sk.dart index 1aa723762a..b367b29bee 100644 --- a/lib/generated/l10n/zulip_localizations_sk.dart +++ b/lib/generated/l10n/zulip_localizations_sk.dart @@ -272,6 +272,9 @@ class ZulipLocalizationsSk extends ZulipLocalizations { @override String get unknownUserName => '(unknown user)'; + @override + String get dmsWithYourselfPageTitle => 'DMs with yourself'; + @override String messageListGroupYouAndOthers(String others) { return 'You and $others'; diff --git a/lib/widgets/message_list.dart b/lib/widgets/message_list.dart index bd85c03c05..8d4d453880 100644 --- a/lib/widgets/message_list.dart +++ b/lib/widgets/message_list.dart @@ -413,7 +413,7 @@ class MessageListAppBarTitle extends StatelessWidget { case DmNarrow(:var otherRecipientIds): final store = PerAccountStoreWidget.of(context); if (otherRecipientIds.isEmpty) { - return const Text("DMs with yourself"); + return Text(zulipLocalizations.dmsWithYourselfPageTitle); } else { final names = otherRecipientIds.map((id) => store.users[id]?.fullName ?? '(unknown user)'); return Text("DMs with ${names.join(", ")}"); // TODO show avatars From 76425ed6a1d0426b97421dc0b703ad83199199ea Mon Sep 17 00:00:00 2001 From: Zixuan James Li Date: Thu, 12 Dec 2024 17:33:34 -0500 Subject: [PATCH 07/14] i18n: Sweep for non-localized '(unknown user)' strings Signed-off-by: Zixuan James Li --- lib/widgets/emoji_reaction.dart | 3 ++- lib/widgets/inbox.dart | 8 ++++++-- lib/widgets/message_list.dart | 3 ++- lib/widgets/profile.dart | 3 ++- lib/widgets/recent_dm_conversations.dart | 8 ++++++-- 5 files changed, 18 insertions(+), 7 deletions(-) diff --git a/lib/widgets/emoji_reaction.dart b/lib/widgets/emoji_reaction.dart index 3d69e3d0d1..491349a40d 100644 --- a/lib/widgets/emoji_reaction.dart +++ b/lib/widgets/emoji_reaction.dart @@ -147,6 +147,7 @@ class ReactionChip extends StatelessWidget { @override Widget build(BuildContext context) { final store = PerAccountStoreWidget.of(context); + final zulipLocalizations = ZulipLocalizations.of(context); final reactionType = reactionWithVotes.reactionType; final emojiCode = reactionWithVotes.emojiCode; @@ -161,7 +162,7 @@ class ReactionChip extends StatelessWidget { ? userIds.map((id) { return id == store.selfUserId ? 'You' - : store.users[id]?.fullName ?? '(unknown user)'; // TODO(i18n) + : store.users[id]?.fullName ?? zulipLocalizations.unknownUserName; }).join(', ') : userIds.length.toString(); diff --git a/lib/widgets/inbox.dart b/lib/widgets/inbox.dart index 5ba771e62b..6dbe31ce04 100644 --- a/lib/widgets/inbox.dart +++ b/lib/widgets/inbox.dart @@ -384,16 +384,20 @@ class _DmItem extends StatelessWidget { final store = PerAccountStoreWidget.of(context); final selfUser = store.users[store.selfUserId]!; + final zulipLocalizations = ZulipLocalizations.of(context); final designVariables = DesignVariables.of(context); final title = switch (narrow.otherRecipientIds) { // TODO dedupe with [RecentDmConversationsItem] [] => selfUser.fullName, - [var otherUserId] => store.users[otherUserId]?.fullName ?? '(unknown user)', + [var otherUserId] => + store.users[otherUserId]?.fullName ?? zulipLocalizations.unknownUserName, // TODO(i18n): List formatting, like you can do in JavaScript: // new Intl.ListFormat('ja').format(['Chris', 'Greg', 'Alya', 'Shu']) // // 'Chris、Greg、Alya、Shu' - _ => narrow.otherRecipientIds.map((id) => store.users[id]?.fullName ?? '(unknown user)').join(', '), + _ => narrow.otherRecipientIds.map( + (id) => store.users[id]?.fullName ?? zulipLocalizations.unknownUserName + ).join(', '), }; return Material( diff --git a/lib/widgets/message_list.dart b/lib/widgets/message_list.dart index 8d4d453880..33903587c8 100644 --- a/lib/widgets/message_list.dart +++ b/lib/widgets/message_list.dart @@ -415,7 +415,8 @@ class MessageListAppBarTitle extends StatelessWidget { if (otherRecipientIds.isEmpty) { return Text(zulipLocalizations.dmsWithYourselfPageTitle); } else { - final names = otherRecipientIds.map((id) => store.users[id]?.fullName ?? '(unknown user)'); + final names = otherRecipientIds.map( + (id) => store.users[id]?.fullName ?? zulipLocalizations.unknownUserName); return Text("DMs with ${names.join(", ")}"); // TODO show avatars } } diff --git a/lib/widgets/profile.dart b/lib/widgets/profile.dart index e5a7593efc..f38daf792d 100644 --- a/lib/widgets/profile.dart +++ b/lib/widgets/profile.dart @@ -291,8 +291,9 @@ class _UserWidget extends StatelessWidget { @override Widget build(BuildContext context) { final store = PerAccountStoreWidget.of(context); + final zulipLocalizations = ZulipLocalizations.of(context); final user = store.users[userId]; - final fullName = user?.fullName ?? '(unknown user)'; + final fullName = user?.fullName ?? zulipLocalizations.unknownUserName; return InkWell( onTap: () => Navigator.push(context, ProfilePage.buildRoute(context: context, diff --git a/lib/widgets/recent_dm_conversations.dart b/lib/widgets/recent_dm_conversations.dart index c9d3131591..ddc32861a3 100644 --- a/lib/widgets/recent_dm_conversations.dart +++ b/lib/widgets/recent_dm_conversations.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; +import '../generated/l10n/zulip_localizations.dart'; import '../model/narrow.dart'; import '../model/recent_dm_conversations.dart'; import '../model/unreads.dart'; @@ -81,6 +82,7 @@ class RecentDmConversationsItem extends StatelessWidget { final store = PerAccountStoreWidget.of(context); final selfUser = store.users[store.selfUserId]!; + final zulipLocalizations = ZulipLocalizations.of(context); final designVariables = DesignVariables.of(context); final String title; @@ -94,13 +96,15 @@ class RecentDmConversationsItem extends StatelessWidget { // (should we offer a "spam folder" style summary screen of recent // 1:1 DM conversations from muted users?) final otherUser = store.users[otherUserId]; - title = otherUser?.fullName ?? '(unknown user)'; + title = otherUser?.fullName ?? zulipLocalizations.unknownUserName; avatar = AvatarImage(userId: otherUserId, size: _avatarSize); default: // TODO(i18n): List formatting, like you can do in JavaScript: // new Intl.ListFormat('ja').format(['Chris', 'Greg', 'Alya']) // // 'Chris、Greg、Alya' - title = narrow.otherRecipientIds.map((id) => store.users[id]?.fullName ?? '(unknown user)').join(', '); + title = narrow.otherRecipientIds.map( + (id) => store.users[id]?.fullName ?? zulipLocalizations.unknownUserName + ).join(', '); avatar = ColoredBox(color: designVariables.groupDmConversationIconBg, child: Center( child: Icon(color: designVariables.groupDmConversationIcon, From 627dead88b2b43ac4abcff93cc7cb4d7162bb81d Mon Sep 17 00:00:00 2001 From: Zixuan James Li Date: Thu, 12 Dec 2024 17:36:15 -0500 Subject: [PATCH 08/14] i18n: Sweep for non-localized '(unknown channel)' strings Renamed the "composeBoxUnknownChannelName" string to generalize it. Signed-off-by: Zixuan James Li --- assets/l10n/app_en.arb | 4 ++-- lib/generated/l10n/zulip_localizations.dart | 2 +- lib/generated/l10n/zulip_localizations_ar.dart | 2 +- lib/generated/l10n/zulip_localizations_en.dart | 2 +- lib/generated/l10n/zulip_localizations_ja.dart | 2 +- lib/generated/l10n/zulip_localizations_nb.dart | 2 +- lib/generated/l10n/zulip_localizations_pl.dart | 2 +- lib/generated/l10n/zulip_localizations_ru.dart | 2 +- lib/generated/l10n/zulip_localizations_sk.dart | 2 +- lib/notifications/display.dart | 2 +- lib/widgets/compose_box.dart | 4 ++-- lib/widgets/message_list.dart | 7 +++++-- 12 files changed, 18 insertions(+), 15 deletions(-) diff --git a/assets/l10n/app_en.arb b/assets/l10n/app_en.arb index 0032a57321..34793822cc 100644 --- a/assets/l10n/app_en.arb +++ b/assets/l10n/app_en.arb @@ -325,8 +325,8 @@ "@composeBoxSendTooltip": { "description": "Tooltip for send button in compose box." }, - "composeBoxUnknownChannelName": "(unknown channel)", - "@composeBoxUnknownChannelName": { + "unknownChannelName": "(unknown channel)", + "@unknownChannelName": { "description": "Replacement name for channel when it cannot be found in the store." }, "composeBoxTopicHintText": "Topic", diff --git a/lib/generated/l10n/zulip_localizations.dart b/lib/generated/l10n/zulip_localizations.dart index 7baf5f3ff6..5c9743437d 100644 --- a/lib/generated/l10n/zulip_localizations.dart +++ b/lib/generated/l10n/zulip_localizations.dart @@ -541,7 +541,7 @@ abstract class ZulipLocalizations { /// /// In en, this message translates to: /// **'(unknown channel)'** - String get composeBoxUnknownChannelName; + String get unknownChannelName; /// Hint text for topic input widget in compose box. /// diff --git a/lib/generated/l10n/zulip_localizations_ar.dart b/lib/generated/l10n/zulip_localizations_ar.dart index 743f4e04a7..dc532b49a2 100644 --- a/lib/generated/l10n/zulip_localizations_ar.dart +++ b/lib/generated/l10n/zulip_localizations_ar.dart @@ -259,7 +259,7 @@ class ZulipLocalizationsAr extends ZulipLocalizations { String get composeBoxSendTooltip => 'Send'; @override - String get composeBoxUnknownChannelName => '(unknown channel)'; + String get unknownChannelName => '(unknown channel)'; @override String get composeBoxTopicHintText => 'Topic'; diff --git a/lib/generated/l10n/zulip_localizations_en.dart b/lib/generated/l10n/zulip_localizations_en.dart index 883ddd71cf..a1ae751219 100644 --- a/lib/generated/l10n/zulip_localizations_en.dart +++ b/lib/generated/l10n/zulip_localizations_en.dart @@ -259,7 +259,7 @@ class ZulipLocalizationsEn extends ZulipLocalizations { String get composeBoxSendTooltip => 'Send'; @override - String get composeBoxUnknownChannelName => '(unknown channel)'; + String get unknownChannelName => '(unknown channel)'; @override String get composeBoxTopicHintText => 'Topic'; diff --git a/lib/generated/l10n/zulip_localizations_ja.dart b/lib/generated/l10n/zulip_localizations_ja.dart index 4ff8e0e283..117e423f9d 100644 --- a/lib/generated/l10n/zulip_localizations_ja.dart +++ b/lib/generated/l10n/zulip_localizations_ja.dart @@ -259,7 +259,7 @@ class ZulipLocalizationsJa extends ZulipLocalizations { String get composeBoxSendTooltip => 'Send'; @override - String get composeBoxUnknownChannelName => '(unknown channel)'; + String get unknownChannelName => '(unknown channel)'; @override String get composeBoxTopicHintText => 'Topic'; diff --git a/lib/generated/l10n/zulip_localizations_nb.dart b/lib/generated/l10n/zulip_localizations_nb.dart index ab58f84c90..5ef76ac8c2 100644 --- a/lib/generated/l10n/zulip_localizations_nb.dart +++ b/lib/generated/l10n/zulip_localizations_nb.dart @@ -259,7 +259,7 @@ class ZulipLocalizationsNb extends ZulipLocalizations { String get composeBoxSendTooltip => 'Send'; @override - String get composeBoxUnknownChannelName => '(unknown channel)'; + String get unknownChannelName => '(unknown channel)'; @override String get composeBoxTopicHintText => 'Topic'; diff --git a/lib/generated/l10n/zulip_localizations_pl.dart b/lib/generated/l10n/zulip_localizations_pl.dart index 507742a225..af3ba8c4cd 100644 --- a/lib/generated/l10n/zulip_localizations_pl.dart +++ b/lib/generated/l10n/zulip_localizations_pl.dart @@ -259,7 +259,7 @@ class ZulipLocalizationsPl extends ZulipLocalizations { String get composeBoxSendTooltip => 'Wyślij'; @override - String get composeBoxUnknownChannelName => '(nieznany kanał)'; + String get unknownChannelName => '(unknown channel)'; @override String get composeBoxTopicHintText => 'Wątek'; diff --git a/lib/generated/l10n/zulip_localizations_ru.dart b/lib/generated/l10n/zulip_localizations_ru.dart index 15942e396f..19900451ba 100644 --- a/lib/generated/l10n/zulip_localizations_ru.dart +++ b/lib/generated/l10n/zulip_localizations_ru.dart @@ -259,7 +259,7 @@ class ZulipLocalizationsRu extends ZulipLocalizations { String get composeBoxSendTooltip => 'Отправить'; @override - String get composeBoxUnknownChannelName => '(неизвестный канал)'; + String get unknownChannelName => '(unknown channel)'; @override String get composeBoxTopicHintText => 'Тема'; diff --git a/lib/generated/l10n/zulip_localizations_sk.dart b/lib/generated/l10n/zulip_localizations_sk.dart index b367b29bee..f1d343c9a7 100644 --- a/lib/generated/l10n/zulip_localizations_sk.dart +++ b/lib/generated/l10n/zulip_localizations_sk.dart @@ -259,7 +259,7 @@ class ZulipLocalizationsSk extends ZulipLocalizations { String get composeBoxSendTooltip => 'Send'; @override - String get composeBoxUnknownChannelName => '(unknown channel)'; + String get unknownChannelName => '(unknown channel)'; @override String get composeBoxTopicHintText => 'Topic'; diff --git a/lib/notifications/display.dart b/lib/notifications/display.dart index 5d36d09d97..b897530c21 100644 --- a/lib/notifications/display.dart +++ b/lib/notifications/display.dart @@ -263,7 +263,7 @@ class NotificationDisplayManager { FcmMessageChannelRecipient(:var streamName?, :var topic) => '#$streamName > ${topic.displayName}', FcmMessageChannelRecipient(:var topic) => - '#(unknown channel) > ${topic.displayName}', // TODO get stream name from data + '#${zulipLocalizations.unknownChannelName} > ${topic.displayName}', // TODO get stream name from data FcmMessageDmRecipient(:var allRecipientIds) when allRecipientIds.length > 2 => zulipLocalizations.notifGroupDmConversationLabel( data.senderFullName, allRecipientIds.length - 2), // TODO use others' names, from data diff --git a/lib/widgets/compose_box.dart b/lib/widgets/compose_box.dart index 3058425bf1..bdcce02b41 100644 --- a/lib/widgets/compose_box.dart +++ b/lib/widgets/compose_box.dart @@ -574,7 +574,7 @@ class _StreamContentInputState extends State<_StreamContentInput> { final store = PerAccountStoreWidget.of(context); final zulipLocalizations = ZulipLocalizations.of(context); final streamName = store.streams[widget.narrow.streamId]?.name - ?? zulipLocalizations.composeBoxUnknownChannelName; + ?? zulipLocalizations.unknownChannelName; return _ContentInput( narrow: widget.narrow, destination: TopicNarrow(widget.narrow.streamId, TopicName(_topicTextNormalized)), @@ -636,7 +636,7 @@ class _FixedDestinationContentInput extends StatelessWidget { case TopicNarrow(:final streamId, :final topic): final store = PerAccountStoreWidget.of(context); final streamName = store.streams[streamId]?.name - ?? zulipLocalizations.composeBoxUnknownChannelName; + ?? zulipLocalizations.unknownChannelName; return zulipLocalizations.composeBoxChannelContentHint( streamName, topic.displayName); diff --git a/lib/widgets/message_list.dart b/lib/widgets/message_list.dart index 33903587c8..2e8d4ba5f9 100644 --- a/lib/widgets/message_list.dart +++ b/lib/widgets/message_list.dart @@ -335,6 +335,7 @@ class MessageListAppBarTitle extends StatelessWidget { Widget _buildStreamRow(BuildContext context, { ZulipStream? stream, }) { + final zulipLocalizations = ZulipLocalizations.of(context); // A null [Icon.icon] makes a blank space. final icon = stream != null ? iconDataForStream(stream) : null; return Row( @@ -346,7 +347,8 @@ class MessageListAppBarTitle extends StatelessWidget { children: [ Icon(size: 16, icon), const SizedBox(width: 4), - Flexible(child: Text(stream?.name ?? '(unknown channel)')), + Flexible(child: Text( + stream?.name ?? zulipLocalizations.unknownChannelName)), ]); } @@ -1031,6 +1033,7 @@ class StreamMessageRecipientHeader extends StatelessWidget { // https://github.com/zulip/zulip-mobile/issues/5511 final store = PerAccountStoreWidget.of(context); final designVariables = DesignVariables.of(context); + final zulipLocalizations = ZulipLocalizations.of(context); final topic = message.topic; @@ -1055,7 +1058,7 @@ class StreamMessageRecipientHeader extends StatelessWidget { final stream = store.streams[message.streamId]; final streamName = stream?.name ?? message.displayRecipient - ?? '(unknown channel)'; // TODO(log) + ?? zulipLocalizations.unknownChannelName; // TODO(log) streamWidget = GestureDetector( onTap: () => Navigator.push(context, From e5a69575f011af06551471bb14fdeec6d7575c26 Mon Sep 17 00:00:00 2001 From: Zixuan James Li Date: Wed, 8 Jan 2025 21:22:49 +0800 Subject: [PATCH 09/14] lightbox: Translate video position slider semantic labels This descriptions were adapted from [VideoPlayerValue]. Signed-off-by: Zixuan James Li --- assets/l10n/app_en.arb | 8 ++++++++ lib/generated/l10n/zulip_localizations.dart | 12 ++++++++++++ lib/generated/l10n/zulip_localizations_ar.dart | 6 ++++++ lib/generated/l10n/zulip_localizations_en.dart | 6 ++++++ lib/generated/l10n/zulip_localizations_ja.dart | 6 ++++++ lib/generated/l10n/zulip_localizations_nb.dart | 6 ++++++ lib/generated/l10n/zulip_localizations_pl.dart | 6 ++++++ lib/generated/l10n/zulip_localizations_ru.dart | 6 ++++++ lib/generated/l10n/zulip_localizations_sk.dart | 6 ++++++ lib/widgets/lightbox.dart | 5 +++-- 10 files changed, 65 insertions(+), 2 deletions(-) diff --git a/assets/l10n/app_en.arb b/assets/l10n/app_en.arb index 34793822cc..7968bf5e84 100644 --- a/assets/l10n/app_en.arb +++ b/assets/l10n/app_en.arb @@ -403,6 +403,14 @@ "@lightboxCopyLinkTooltip": { "description": "Tooltip in lightbox for the copy link action." }, + "lightboxVideoCurrentPosition": "Current position", + "@lightboxVideoCurrentPosition": { + "description": "The current playback position of the video playing in the lightbox." + }, + "lightboxVideoDuration": "Video duration", + "@lightboxVideoDuration": { + "description": "The total duration of the video playing in the lightbox." + }, "loginPageTitle": "Log in", "@loginPageTitle": { "description": "Title for login page." diff --git a/lib/generated/l10n/zulip_localizations.dart b/lib/generated/l10n/zulip_localizations.dart index 5c9743437d..9aa25ee84d 100644 --- a/lib/generated/l10n/zulip_localizations.dart +++ b/lib/generated/l10n/zulip_localizations.dart @@ -645,6 +645,18 @@ abstract class ZulipLocalizations { /// **'Copy link'** String get lightboxCopyLinkTooltip; + /// The current playback position of the video playing in the lightbox. + /// + /// In en, this message translates to: + /// **'Current position'** + String get lightboxVideoCurrentPosition; + + /// The total duration of the video playing in the lightbox. + /// + /// In en, this message translates to: + /// **'Video duration'** + String get lightboxVideoDuration; + /// Title for login page. /// /// In en, this message translates to: diff --git a/lib/generated/l10n/zulip_localizations_ar.dart b/lib/generated/l10n/zulip_localizations_ar.dart index dc532b49a2..7aff3e30ef 100644 --- a/lib/generated/l10n/zulip_localizations_ar.dart +++ b/lib/generated/l10n/zulip_localizations_ar.dart @@ -316,6 +316,12 @@ class ZulipLocalizationsAr extends ZulipLocalizations { @override String get lightboxCopyLinkTooltip => 'Copy link'; + @override + String get lightboxVideoCurrentPosition => 'Current position'; + + @override + String get lightboxVideoDuration => 'Video duration'; + @override String get loginPageTitle => 'Log in'; diff --git a/lib/generated/l10n/zulip_localizations_en.dart b/lib/generated/l10n/zulip_localizations_en.dart index a1ae751219..aa3c1238fb 100644 --- a/lib/generated/l10n/zulip_localizations_en.dart +++ b/lib/generated/l10n/zulip_localizations_en.dart @@ -316,6 +316,12 @@ class ZulipLocalizationsEn extends ZulipLocalizations { @override String get lightboxCopyLinkTooltip => 'Copy link'; + @override + String get lightboxVideoCurrentPosition => 'Current position'; + + @override + String get lightboxVideoDuration => 'Video duration'; + @override String get loginPageTitle => 'Log in'; diff --git a/lib/generated/l10n/zulip_localizations_ja.dart b/lib/generated/l10n/zulip_localizations_ja.dart index 117e423f9d..8e50d9abe7 100644 --- a/lib/generated/l10n/zulip_localizations_ja.dart +++ b/lib/generated/l10n/zulip_localizations_ja.dart @@ -316,6 +316,12 @@ class ZulipLocalizationsJa extends ZulipLocalizations { @override String get lightboxCopyLinkTooltip => 'Copy link'; + @override + String get lightboxVideoCurrentPosition => 'Current position'; + + @override + String get lightboxVideoDuration => 'Video duration'; + @override String get loginPageTitle => 'Log in'; diff --git a/lib/generated/l10n/zulip_localizations_nb.dart b/lib/generated/l10n/zulip_localizations_nb.dart index 5ef76ac8c2..34a3a134e9 100644 --- a/lib/generated/l10n/zulip_localizations_nb.dart +++ b/lib/generated/l10n/zulip_localizations_nb.dart @@ -316,6 +316,12 @@ class ZulipLocalizationsNb extends ZulipLocalizations { @override String get lightboxCopyLinkTooltip => 'Copy link'; + @override + String get lightboxVideoCurrentPosition => 'Current position'; + + @override + String get lightboxVideoDuration => 'Video duration'; + @override String get loginPageTitle => 'Log in'; diff --git a/lib/generated/l10n/zulip_localizations_pl.dart b/lib/generated/l10n/zulip_localizations_pl.dart index af3ba8c4cd..c29c7488d5 100644 --- a/lib/generated/l10n/zulip_localizations_pl.dart +++ b/lib/generated/l10n/zulip_localizations_pl.dart @@ -316,6 +316,12 @@ class ZulipLocalizationsPl extends ZulipLocalizations { @override String get lightboxCopyLinkTooltip => 'Skopiuj odnośnik'; + @override + String get lightboxVideoCurrentPosition => 'Current position'; + + @override + String get lightboxVideoDuration => 'Video duration'; + @override String get loginPageTitle => 'Zaloguj'; diff --git a/lib/generated/l10n/zulip_localizations_ru.dart b/lib/generated/l10n/zulip_localizations_ru.dart index 19900451ba..a849b266c6 100644 --- a/lib/generated/l10n/zulip_localizations_ru.dart +++ b/lib/generated/l10n/zulip_localizations_ru.dart @@ -316,6 +316,12 @@ class ZulipLocalizationsRu extends ZulipLocalizations { @override String get lightboxCopyLinkTooltip => 'Скопировать ссылку'; + @override + String get lightboxVideoCurrentPosition => 'Current position'; + + @override + String get lightboxVideoDuration => 'Video duration'; + @override String get loginPageTitle => 'Вход в систему'; diff --git a/lib/generated/l10n/zulip_localizations_sk.dart b/lib/generated/l10n/zulip_localizations_sk.dart index f1d343c9a7..c0bef16a99 100644 --- a/lib/generated/l10n/zulip_localizations_sk.dart +++ b/lib/generated/l10n/zulip_localizations_sk.dart @@ -316,6 +316,12 @@ class ZulipLocalizationsSk extends ZulipLocalizations { @override String get lightboxCopyLinkTooltip => 'Skopírovať odkaz'; + @override + String get lightboxVideoCurrentPosition => 'Current position'; + + @override + String get lightboxVideoDuration => 'Video duration'; + @override String get loginPageTitle => 'Prihlásiť sa'; diff --git a/lib/widgets/lightbox.dart b/lib/widgets/lightbox.dart index 4635e496f4..1406b5fdbd 100644 --- a/lib/widgets/lightbox.dart +++ b/lib/widgets/lightbox.dart @@ -385,13 +385,14 @@ class _VideoPositionSliderControlState extends State<_VideoPositionSliderControl @override Widget build(BuildContext context) { + final zulipLocalizations = ZulipLocalizations.of(context); final currentPosition = _isSliderDragging ? _sliderValue : widget.controller.value.position; return Row(children: [ VideoDurationLabel(currentPosition, - semanticsLabel: "Current position"), + semanticsLabel: zulipLocalizations.lightboxVideoCurrentPosition), Expanded( child: Slider( value: currentPosition.inMilliseconds.toDouble(), @@ -421,7 +422,7 @@ class _VideoPositionSliderControlState extends State<_VideoPositionSliderControl ), ), VideoDurationLabel(widget.controller.value.duration, - semanticsLabel: "Video duration"), + semanticsLabel: zulipLocalizations.lightboxVideoDuration), ]); } } From a8a0c256b698d5b12daf0dd5dbd1b99e87f98b76 Mon Sep 17 00:00:00 2001 From: Zixuan James Li Date: Wed, 8 Jan 2025 21:37:24 +0800 Subject: [PATCH 10/14] msglist: Mostly translate remaining strings on message list page Ideally we should implement #1080 for DMs title, but we might switch to showing avatars as the TODO indicated before we work on lists' proper translation. Signed-off-by: Zixuan James Li --- assets/l10n/app_en.arb | 15 +++++++++++++++ lib/generated/l10n/zulip_localizations.dart | 18 ++++++++++++++++++ lib/generated/l10n/zulip_localizations_ar.dart | 11 +++++++++++ lib/generated/l10n/zulip_localizations_en.dart | 11 +++++++++++ lib/generated/l10n/zulip_localizations_ja.dart | 11 +++++++++++ lib/generated/l10n/zulip_localizations_nb.dart | 11 +++++++++++ lib/generated/l10n/zulip_localizations_pl.dart | 11 +++++++++++ lib/generated/l10n/zulip_localizations_ru.dart | 11 +++++++++++ lib/generated/l10n/zulip_localizations_sk.dart | 11 +++++++++++ lib/widgets/message_list.dart | 18 +++++++++++------- 10 files changed, 121 insertions(+), 7 deletions(-) diff --git a/assets/l10n/app_en.arb b/assets/l10n/app_en.arb index 7968bf5e84..cc821faca1 100644 --- a/assets/l10n/app_en.arb +++ b/assets/l10n/app_en.arb @@ -355,6 +355,13 @@ "others": {"type": "String", "example": "Alice, Bob"} } }, + "dmsWithOthersPageTitle": "DMs with {others}", + "@dmsWithOthersPageTitle": { + "description": "Message list page title for a DM group with others.", + "placeholders": { + "others": {"type": "String", "example": "Alice, Bob"} + } + }, "messageListGroupYouWithYourself": "You with yourself", "@messageListGroupYouWithYourself": { "description": "Message list recipient header for a DM group that only includes yourself." @@ -748,5 +755,13 @@ "emojiPickerSearchEmoji": "Search emoji", "@emojiPickerSearchEmoji": { "description": "Hint text for the emoji picker search text field." + }, + "noEarlierMessages": "No earlier messages", + "@noEarlierMessages": { + "description": "Text to show at the start of a message list if there are no earlier messages." + }, + "scrollToBottomTooltip": "Scroll to bottom", + "@scrollToBottomTooltip": { + "description": "Tooltip for button to scroll to bottom." } } diff --git a/lib/generated/l10n/zulip_localizations.dart b/lib/generated/l10n/zulip_localizations.dart index 9aa25ee84d..8172b8e105 100644 --- a/lib/generated/l10n/zulip_localizations.dart +++ b/lib/generated/l10n/zulip_localizations.dart @@ -573,6 +573,12 @@ abstract class ZulipLocalizations { /// **'You and {others}'** String messageListGroupYouAndOthers(String others); + /// Message list page title for a DM group with others. + /// + /// In en, this message translates to: + /// **'DMs with {others}'** + String dmsWithOthersPageTitle(String others); + /// Message list recipient header for a DM group that only includes yourself. /// /// In en, this message translates to: @@ -1118,6 +1124,18 @@ abstract class ZulipLocalizations { /// In en, this message translates to: /// **'Search emoji'** String get emojiPickerSearchEmoji; + + /// Text to show at the start of a message list if there are no earlier messages. + /// + /// In en, this message translates to: + /// **'No earlier messages'** + String get noEarlierMessages; + + /// Tooltip for button to scroll to bottom. + /// + /// In en, this message translates to: + /// **'Scroll to bottom'** + String get scrollToBottomTooltip; } class _ZulipLocalizationsDelegate extends LocalizationsDelegate { diff --git a/lib/generated/l10n/zulip_localizations_ar.dart b/lib/generated/l10n/zulip_localizations_ar.dart index 7aff3e30ef..f120e15f2e 100644 --- a/lib/generated/l10n/zulip_localizations_ar.dart +++ b/lib/generated/l10n/zulip_localizations_ar.dart @@ -280,6 +280,11 @@ class ZulipLocalizationsAr extends ZulipLocalizations { return 'You and $others'; } + @override + String dmsWithOthersPageTitle(String others) { + return 'DMs with $others'; + } + @override String get messageListGroupYouWithYourself => 'You with yourself'; @@ -588,4 +593,10 @@ class ZulipLocalizationsAr extends ZulipLocalizations { @override String get emojiPickerSearchEmoji => 'Search emoji'; + + @override + String get noEarlierMessages => 'No earlier messages'; + + @override + String get scrollToBottomTooltip => 'Scroll to bottom'; } diff --git a/lib/generated/l10n/zulip_localizations_en.dart b/lib/generated/l10n/zulip_localizations_en.dart index aa3c1238fb..db89853b57 100644 --- a/lib/generated/l10n/zulip_localizations_en.dart +++ b/lib/generated/l10n/zulip_localizations_en.dart @@ -280,6 +280,11 @@ class ZulipLocalizationsEn extends ZulipLocalizations { return 'You and $others'; } + @override + String dmsWithOthersPageTitle(String others) { + return 'DMs with $others'; + } + @override String get messageListGroupYouWithYourself => 'You with yourself'; @@ -588,4 +593,10 @@ class ZulipLocalizationsEn extends ZulipLocalizations { @override String get emojiPickerSearchEmoji => 'Search emoji'; + + @override + String get noEarlierMessages => 'No earlier messages'; + + @override + String get scrollToBottomTooltip => 'Scroll to bottom'; } diff --git a/lib/generated/l10n/zulip_localizations_ja.dart b/lib/generated/l10n/zulip_localizations_ja.dart index 8e50d9abe7..3aa1fc6497 100644 --- a/lib/generated/l10n/zulip_localizations_ja.dart +++ b/lib/generated/l10n/zulip_localizations_ja.dart @@ -280,6 +280,11 @@ class ZulipLocalizationsJa extends ZulipLocalizations { return 'You and $others'; } + @override + String dmsWithOthersPageTitle(String others) { + return 'DMs with $others'; + } + @override String get messageListGroupYouWithYourself => 'You with yourself'; @@ -588,4 +593,10 @@ class ZulipLocalizationsJa extends ZulipLocalizations { @override String get emojiPickerSearchEmoji => 'Search emoji'; + + @override + String get noEarlierMessages => 'No earlier messages'; + + @override + String get scrollToBottomTooltip => 'Scroll to bottom'; } diff --git a/lib/generated/l10n/zulip_localizations_nb.dart b/lib/generated/l10n/zulip_localizations_nb.dart index 34a3a134e9..222248839b 100644 --- a/lib/generated/l10n/zulip_localizations_nb.dart +++ b/lib/generated/l10n/zulip_localizations_nb.dart @@ -280,6 +280,11 @@ class ZulipLocalizationsNb extends ZulipLocalizations { return 'You and $others'; } + @override + String dmsWithOthersPageTitle(String others) { + return 'DMs with $others'; + } + @override String get messageListGroupYouWithYourself => 'You with yourself'; @@ -588,4 +593,10 @@ class ZulipLocalizationsNb extends ZulipLocalizations { @override String get emojiPickerSearchEmoji => 'Search emoji'; + + @override + String get noEarlierMessages => 'No earlier messages'; + + @override + String get scrollToBottomTooltip => 'Scroll to bottom'; } diff --git a/lib/generated/l10n/zulip_localizations_pl.dart b/lib/generated/l10n/zulip_localizations_pl.dart index c29c7488d5..a5b9364067 100644 --- a/lib/generated/l10n/zulip_localizations_pl.dart +++ b/lib/generated/l10n/zulip_localizations_pl.dart @@ -280,6 +280,11 @@ class ZulipLocalizationsPl extends ZulipLocalizations { return 'Ty i $others'; } + @override + String dmsWithOthersPageTitle(String others) { + return 'DMs with $others'; + } + @override String get messageListGroupYouWithYourself => 'Ty ze sobą'; @@ -588,4 +593,10 @@ class ZulipLocalizationsPl extends ZulipLocalizations { @override String get emojiPickerSearchEmoji => 'Szukaj emoji'; + + @override + String get noEarlierMessages => 'No earlier messages'; + + @override + String get scrollToBottomTooltip => 'Scroll to bottom'; } diff --git a/lib/generated/l10n/zulip_localizations_ru.dart b/lib/generated/l10n/zulip_localizations_ru.dart index a849b266c6..9493bca098 100644 --- a/lib/generated/l10n/zulip_localizations_ru.dart +++ b/lib/generated/l10n/zulip_localizations_ru.dart @@ -280,6 +280,11 @@ class ZulipLocalizationsRu extends ZulipLocalizations { return 'Вы и $others'; } + @override + String dmsWithOthersPageTitle(String others) { + return 'DMs with $others'; + } + @override String get messageListGroupYouWithYourself => 'Вы с собой'; @@ -588,4 +593,10 @@ class ZulipLocalizationsRu extends ZulipLocalizations { @override String get emojiPickerSearchEmoji => 'Поиск эмодзи'; + + @override + String get noEarlierMessages => 'No earlier messages'; + + @override + String get scrollToBottomTooltip => 'Scroll to bottom'; } diff --git a/lib/generated/l10n/zulip_localizations_sk.dart b/lib/generated/l10n/zulip_localizations_sk.dart index c0bef16a99..7e4b331fcc 100644 --- a/lib/generated/l10n/zulip_localizations_sk.dart +++ b/lib/generated/l10n/zulip_localizations_sk.dart @@ -280,6 +280,11 @@ class ZulipLocalizationsSk extends ZulipLocalizations { return 'You and $others'; } + @override + String dmsWithOthersPageTitle(String others) { + return 'DMs with $others'; + } + @override String get messageListGroupYouWithYourself => 'You with yourself'; @@ -588,4 +593,10 @@ class ZulipLocalizationsSk extends ZulipLocalizations { @override String get emojiPickerSearchEmoji => 'Hľadať emotikon'; + + @override + String get noEarlierMessages => 'No earlier messages'; + + @override + String get scrollToBottomTooltip => 'Scroll to bottom'; } diff --git a/lib/widgets/message_list.dart b/lib/widgets/message_list.dart index 2e8d4ba5f9..0d1a936dff 100644 --- a/lib/widgets/message_list.dart +++ b/lib/widgets/message_list.dart @@ -419,7 +419,9 @@ class MessageListAppBarTitle extends StatelessWidget { } else { final names = otherRecipientIds.map( (id) => store.users[id]?.fullName ?? zulipLocalizations.unknownUserName); - return Text("DMs with ${names.join(", ")}"); // TODO show avatars + // TODO show avatars + return Text( + zulipLocalizations.dmsWithOthersPageTitle(names.join(', '))); } } } @@ -571,6 +573,7 @@ class _MessageListState extends State with PerAccountStoreAwareStat Widget _buildListView(BuildContext context) { final length = model!.items.length; const centerSliverKey = ValueKey('center sliver'); + final zulipLocalizations = ZulipLocalizations.of(context); Widget sliver = SliverStickyHeaderList( headerPlacement: HeaderPlacement.scrollingStart, @@ -607,7 +610,7 @@ class _MessageListState extends State with PerAccountStoreAwareStat if (i == 2) return TypingStatusWidget(narrow: widget.narrow); final data = model!.items[length - 1 - (i - 3)]; - return _buildItem(data, i); + return _buildItem(zulipLocalizations, data, i); })); if (!ComposeBox.hasComposeBox(widget.narrow)) { @@ -643,13 +646,13 @@ class _MessageListState extends State with PerAccountStoreAwareStat ]); } - Widget _buildItem(MessageListItem data, int i) { + Widget _buildItem(ZulipLocalizations zulipLocalizations, MessageListItem data, int i) { switch (data) { case MessageListHistoryStartItem(): - return const Center( + return Center( child: Padding( - padding: EdgeInsets.symmetric(vertical: 16.0), - child: Text("No earlier messages."))); // TODO use an icon + padding: const EdgeInsets.symmetric(vertical: 16.0), + child: Text(zulipLocalizations.noEarlierMessages))); // TODO use an icon case MessageListLoadingItem(): return const Center( child: Padding( @@ -693,6 +696,7 @@ class ScrollToBottomButton extends StatelessWidget { @override Widget build(BuildContext context) { + final zulipLocalizations = ZulipLocalizations.of(context); return ValueListenableBuilder( valueListenable: visibleValue, builder: (BuildContext context, bool value, Widget? child) { @@ -700,7 +704,7 @@ class ScrollToBottomButton extends StatelessWidget { }, // TODO: fix hardcoded values for size and style here child: IconButton( - tooltip: "Scroll to bottom", + tooltip: zulipLocalizations.scrollToBottomTooltip, icon: const Icon(Icons.expand_circle_down_rounded), iconSize: 40, // Web has the same color in light and dark mode. From f104dc8218545c9e6506b0f2976e0dfe0329dd31 Mon Sep 17 00:00:00 2001 From: Zixuan James Li Date: Wed, 8 Jan 2025 21:59:02 +0800 Subject: [PATCH 11/14] content: Translate error dialog for _launchUrl Signed-off-by: Zixuan James Li --- assets/l10n/app_en.arb | 11 +++++++++++ lib/generated/l10n/zulip_localizations.dart | 12 ++++++++++++ lib/generated/l10n/zulip_localizations_ar.dart | 8 ++++++++ lib/generated/l10n/zulip_localizations_en.dart | 8 ++++++++ lib/generated/l10n/zulip_localizations_ja.dart | 8 ++++++++ lib/generated/l10n/zulip_localizations_nb.dart | 8 ++++++++ lib/generated/l10n/zulip_localizations_pl.dart | 8 ++++++++ lib/generated/l10n/zulip_localizations_ru.dart | 8 ++++++++ lib/generated/l10n/zulip_localizations_sk.dart | 8 ++++++++ lib/widgets/content.dart | 5 +++-- 10 files changed, 82 insertions(+), 2 deletions(-) diff --git a/assets/l10n/app_en.arb b/assets/l10n/app_en.arb index cc821faca1..79c360e14c 100644 --- a/assets/l10n/app_en.arb +++ b/assets/l10n/app_en.arb @@ -234,6 +234,17 @@ "event": {"type": "String", "example": "UpdateMessageEvent(id: 123, messageIds: [2345, 3456], newTopic: 'dinner')"} } }, + "errorCouldNotOpenLinkTitle": "Unable to open link", + "@errorCouldNotOpenLinkTitle": { + "description": "Error title when opening a link failed." + }, + "errorCouldNotOpenLink": "Link could not be opened: {url}", + "@errorCouldNotOpenLink": { + "description": "Error message when opening a link failed.", + "placeholders": { + "url": {"type": "String", "example": "https://chat.example.com"} + } + }, "errorMuteTopicFailed": "Failed to mute topic", "@errorMuteTopicFailed": { "description": "Error message when muting a topic failed." diff --git a/lib/generated/l10n/zulip_localizations.dart b/lib/generated/l10n/zulip_localizations.dart index 8172b8e105..668a448702 100644 --- a/lib/generated/l10n/zulip_localizations.dart +++ b/lib/generated/l10n/zulip_localizations.dart @@ -411,6 +411,18 @@ abstract class ZulipLocalizations { /// **'Error handling a Zulip event from {serverUrl}; will retry.\n\nError: {error}\n\nEvent: {event}'** String errorHandlingEventDetails(String serverUrl, String error, String event); + /// Error title when opening a link failed. + /// + /// In en, this message translates to: + /// **'Unable to open link'** + String get errorCouldNotOpenLinkTitle; + + /// Error message when opening a link failed. + /// + /// In en, this message translates to: + /// **'Link could not be opened: {url}'** + String errorCouldNotOpenLink(String url); + /// Error message when muting a topic failed. /// /// In en, this message translates to: diff --git a/lib/generated/l10n/zulip_localizations_ar.dart b/lib/generated/l10n/zulip_localizations_ar.dart index f120e15f2e..b4e82e9a84 100644 --- a/lib/generated/l10n/zulip_localizations_ar.dart +++ b/lib/generated/l10n/zulip_localizations_ar.dart @@ -191,6 +191,14 @@ class ZulipLocalizationsAr extends ZulipLocalizations { return 'Error handling a Zulip event from $serverUrl; will retry.\n\nError: $error\n\nEvent: $event'; } + @override + String get errorCouldNotOpenLinkTitle => 'Unable to open link'; + + @override + String errorCouldNotOpenLink(String url) { + return 'Link could not be opened: $url'; + } + @override String get errorMuteTopicFailed => 'Failed to mute topic'; diff --git a/lib/generated/l10n/zulip_localizations_en.dart b/lib/generated/l10n/zulip_localizations_en.dart index db89853b57..a8976c3a59 100644 --- a/lib/generated/l10n/zulip_localizations_en.dart +++ b/lib/generated/l10n/zulip_localizations_en.dart @@ -191,6 +191,14 @@ class ZulipLocalizationsEn extends ZulipLocalizations { return 'Error handling a Zulip event from $serverUrl; will retry.\n\nError: $error\n\nEvent: $event'; } + @override + String get errorCouldNotOpenLinkTitle => 'Unable to open link'; + + @override + String errorCouldNotOpenLink(String url) { + return 'Link could not be opened: $url'; + } + @override String get errorMuteTopicFailed => 'Failed to mute topic'; diff --git a/lib/generated/l10n/zulip_localizations_ja.dart b/lib/generated/l10n/zulip_localizations_ja.dart index 3aa1fc6497..9857bd3473 100644 --- a/lib/generated/l10n/zulip_localizations_ja.dart +++ b/lib/generated/l10n/zulip_localizations_ja.dart @@ -191,6 +191,14 @@ class ZulipLocalizationsJa extends ZulipLocalizations { return 'Error handling a Zulip event from $serverUrl; will retry.\n\nError: $error\n\nEvent: $event'; } + @override + String get errorCouldNotOpenLinkTitle => 'Unable to open link'; + + @override + String errorCouldNotOpenLink(String url) { + return 'Link could not be opened: $url'; + } + @override String get errorMuteTopicFailed => 'Failed to mute topic'; diff --git a/lib/generated/l10n/zulip_localizations_nb.dart b/lib/generated/l10n/zulip_localizations_nb.dart index 222248839b..df39891697 100644 --- a/lib/generated/l10n/zulip_localizations_nb.dart +++ b/lib/generated/l10n/zulip_localizations_nb.dart @@ -191,6 +191,14 @@ class ZulipLocalizationsNb extends ZulipLocalizations { return 'Error handling a Zulip event from $serverUrl; will retry.\n\nError: $error\n\nEvent: $event'; } + @override + String get errorCouldNotOpenLinkTitle => 'Unable to open link'; + + @override + String errorCouldNotOpenLink(String url) { + return 'Link could not be opened: $url'; + } + @override String get errorMuteTopicFailed => 'Failed to mute topic'; diff --git a/lib/generated/l10n/zulip_localizations_pl.dart b/lib/generated/l10n/zulip_localizations_pl.dart index a5b9364067..ead58dee08 100644 --- a/lib/generated/l10n/zulip_localizations_pl.dart +++ b/lib/generated/l10n/zulip_localizations_pl.dart @@ -191,6 +191,14 @@ class ZulipLocalizationsPl extends ZulipLocalizations { return 'Błąd zdarzenia Zulip z $serverUrl; ponawiam.\n\nBłąd: $error\n\nZdarzenie: $event'; } + @override + String get errorCouldNotOpenLinkTitle => 'Unable to open link'; + + @override + String errorCouldNotOpenLink(String url) { + return 'Link could not be opened: $url'; + } + @override String get errorMuteTopicFailed => 'Wyciszenie bez powodzenia'; diff --git a/lib/generated/l10n/zulip_localizations_ru.dart b/lib/generated/l10n/zulip_localizations_ru.dart index 9493bca098..b7b856b181 100644 --- a/lib/generated/l10n/zulip_localizations_ru.dart +++ b/lib/generated/l10n/zulip_localizations_ru.dart @@ -191,6 +191,14 @@ class ZulipLocalizationsRu extends ZulipLocalizations { return 'Ошибка обработки события Zulip от $serverUrl; повторим попытку.\n\nОшибка: $error\n\nСобытие: $event'; } + @override + String get errorCouldNotOpenLinkTitle => 'Unable to open link'; + + @override + String errorCouldNotOpenLink(String url) { + return 'Link could not be opened: $url'; + } + @override String get errorMuteTopicFailed => 'Не удалось отключить тему'; diff --git a/lib/generated/l10n/zulip_localizations_sk.dart b/lib/generated/l10n/zulip_localizations_sk.dart index 7e4b331fcc..72ec6b7117 100644 --- a/lib/generated/l10n/zulip_localizations_sk.dart +++ b/lib/generated/l10n/zulip_localizations_sk.dart @@ -191,6 +191,14 @@ class ZulipLocalizationsSk extends ZulipLocalizations { return 'Chyba obsluhy Zulip udalosti na serveri $serverUrl; skúsim znovu.\n\nChyba: $error\n\nUdalosť: $event'; } + @override + String get errorCouldNotOpenLinkTitle => 'Unable to open link'; + + @override + String errorCouldNotOpenLink(String url) { + return 'Link could not be opened: $url'; + } + @override String get errorMuteTopicFailed => 'Nepodarilo sa ztíšiť tému'; diff --git a/lib/widgets/content.dart b/lib/widgets/content.dart index c2ccd7dbec..02c4f05ca3 100644 --- a/lib/widgets/content.dart +++ b/lib/widgets/content.dart @@ -1319,10 +1319,11 @@ class MessageTableCell extends StatelessWidget { void _launchUrl(BuildContext context, String urlString) async { DialogStatus showError(BuildContext context, String? message) { + final zulipLocalizations = ZulipLocalizations.of(context); return showErrorDialog(context: context, - title: 'Unable to open link', + title: zulipLocalizations.errorCouldNotOpenLinkTitle, message: [ - 'Link could not be opened: $urlString', + zulipLocalizations.errorCouldNotOpenLink(urlString), if (message != null) message, ].join("\n\n")); } From 7ccb8d3e0724b73944bbd3212da18f6effc7533d Mon Sep 17 00:00:00 2001 From: Zixuan James Li Date: Thu, 9 Jan 2025 00:09:26 +0800 Subject: [PATCH 12/14] emoji: Translate "You" string for reactions added by self Signed-off-by: Zixuan James Li --- assets/l10n/app_en.arb | 4 ++++ lib/generated/l10n/zulip_localizations.dart | 6 ++++++ lib/generated/l10n/zulip_localizations_ar.dart | 3 +++ lib/generated/l10n/zulip_localizations_en.dart | 3 +++ lib/generated/l10n/zulip_localizations_ja.dart | 3 +++ lib/generated/l10n/zulip_localizations_nb.dart | 3 +++ lib/generated/l10n/zulip_localizations_pl.dart | 3 +++ lib/generated/l10n/zulip_localizations_ru.dart | 3 +++ lib/generated/l10n/zulip_localizations_sk.dart | 3 +++ lib/widgets/emoji_reaction.dart | 2 +- 10 files changed, 32 insertions(+), 1 deletion(-) diff --git a/assets/l10n/app_en.arb b/assets/l10n/app_en.arb index 79c360e14c..9c6bddaca2 100644 --- a/assets/l10n/app_en.arb +++ b/assets/l10n/app_en.arb @@ -672,6 +672,10 @@ "@notifSelfUser": { "description": "Display name for the user themself, to show after replying in an Android notification" }, + "reactedEmojiSelfUser": "You", + "@reactedEmojiSelfUser": { + "description": "Display name for the user themself, to show on an emoji reaction added by the user." + }, "onePersonTyping": "{typist} is typing…", "@onePersonTyping": { "description": "Text to display when there is one user typing.", diff --git a/lib/generated/l10n/zulip_localizations.dart b/lib/generated/l10n/zulip_localizations.dart index 668a448702..792a84d68e 100644 --- a/lib/generated/l10n/zulip_localizations.dart +++ b/lib/generated/l10n/zulip_localizations.dart @@ -1005,6 +1005,12 @@ abstract class ZulipLocalizations { /// **'You'** String get notifSelfUser; + /// Display name for the user themself, to show on an emoji reaction added by the user. + /// + /// In en, this message translates to: + /// **'You'** + String get reactedEmojiSelfUser; + /// Text to display when there is one user typing. /// /// In en, this message translates to: diff --git a/lib/generated/l10n/zulip_localizations_ar.dart b/lib/generated/l10n/zulip_localizations_ar.dart index b4e82e9a84..2cafe3746f 100644 --- a/lib/generated/l10n/zulip_localizations_ar.dart +++ b/lib/generated/l10n/zulip_localizations_ar.dart @@ -532,6 +532,9 @@ class ZulipLocalizationsAr extends ZulipLocalizations { @override String get notifSelfUser => 'You'; + @override + String get reactedEmojiSelfUser => 'You'; + @override String onePersonTyping(String typist) { return '$typist is typing…'; diff --git a/lib/generated/l10n/zulip_localizations_en.dart b/lib/generated/l10n/zulip_localizations_en.dart index a8976c3a59..18bcb204bb 100644 --- a/lib/generated/l10n/zulip_localizations_en.dart +++ b/lib/generated/l10n/zulip_localizations_en.dart @@ -532,6 +532,9 @@ class ZulipLocalizationsEn extends ZulipLocalizations { @override String get notifSelfUser => 'You'; + @override + String get reactedEmojiSelfUser => 'You'; + @override String onePersonTyping(String typist) { return '$typist is typing…'; diff --git a/lib/generated/l10n/zulip_localizations_ja.dart b/lib/generated/l10n/zulip_localizations_ja.dart index 9857bd3473..801406fa4a 100644 --- a/lib/generated/l10n/zulip_localizations_ja.dart +++ b/lib/generated/l10n/zulip_localizations_ja.dart @@ -532,6 +532,9 @@ class ZulipLocalizationsJa extends ZulipLocalizations { @override String get notifSelfUser => 'You'; + @override + String get reactedEmojiSelfUser => 'You'; + @override String onePersonTyping(String typist) { return '$typist is typing…'; diff --git a/lib/generated/l10n/zulip_localizations_nb.dart b/lib/generated/l10n/zulip_localizations_nb.dart index df39891697..d38872b3ca 100644 --- a/lib/generated/l10n/zulip_localizations_nb.dart +++ b/lib/generated/l10n/zulip_localizations_nb.dart @@ -532,6 +532,9 @@ class ZulipLocalizationsNb extends ZulipLocalizations { @override String get notifSelfUser => 'You'; + @override + String get reactedEmojiSelfUser => 'You'; + @override String onePersonTyping(String typist) { return '$typist is typing…'; diff --git a/lib/generated/l10n/zulip_localizations_pl.dart b/lib/generated/l10n/zulip_localizations_pl.dart index ead58dee08..dfc7b41720 100644 --- a/lib/generated/l10n/zulip_localizations_pl.dart +++ b/lib/generated/l10n/zulip_localizations_pl.dart @@ -532,6 +532,9 @@ class ZulipLocalizationsPl extends ZulipLocalizations { @override String get notifSelfUser => 'Ty'; + @override + String get reactedEmojiSelfUser => 'You'; + @override String onePersonTyping(String typist) { return '$typist coś pisze…'; diff --git a/lib/generated/l10n/zulip_localizations_ru.dart b/lib/generated/l10n/zulip_localizations_ru.dart index b7b856b181..62edfb248b 100644 --- a/lib/generated/l10n/zulip_localizations_ru.dart +++ b/lib/generated/l10n/zulip_localizations_ru.dart @@ -532,6 +532,9 @@ class ZulipLocalizationsRu extends ZulipLocalizations { @override String get notifSelfUser => 'Вы'; + @override + String get reactedEmojiSelfUser => 'You'; + @override String onePersonTyping(String typist) { return '$typist набирает сообщение…'; diff --git a/lib/generated/l10n/zulip_localizations_sk.dart b/lib/generated/l10n/zulip_localizations_sk.dart index 72ec6b7117..35a0dc6861 100644 --- a/lib/generated/l10n/zulip_localizations_sk.dart +++ b/lib/generated/l10n/zulip_localizations_sk.dart @@ -532,6 +532,9 @@ class ZulipLocalizationsSk extends ZulipLocalizations { @override String get notifSelfUser => 'Ty'; + @override + String get reactedEmojiSelfUser => 'You'; + @override String onePersonTyping(String typist) { return '$typist píše…'; diff --git a/lib/widgets/emoji_reaction.dart b/lib/widgets/emoji_reaction.dart index 491349a40d..de3e2baa26 100644 --- a/lib/widgets/emoji_reaction.dart +++ b/lib/widgets/emoji_reaction.dart @@ -161,7 +161,7 @@ class ReactionChip extends StatelessWidget { // // 'Chris、Greg、Alya、Shu' ? userIds.map((id) { return id == store.selfUserId - ? 'You' + ? zulipLocalizations.reactedEmojiSelfUser : store.users[id]?.fullName ?? zulipLocalizations.unknownUserName; }).join(', ') : userIds.length.toString(); From 399835ae0206213a77fb03ec07d51ce139c59cf0 Mon Sep 17 00:00:00 2001 From: Zixuan James Li Date: Wed, 15 Jan 2025 22:47:35 +0800 Subject: [PATCH 13/14] compose: Translate "(loading message {messageId})" and implement the necessary plumbing to access ZulipLocalizations Signed-off-by: Zixuan James Li --- assets/l10n/app_en.arb | 7 +++++++ lib/generated/l10n/zulip_localizations.dart | 6 ++++++ lib/generated/l10n/zulip_localizations_ar.dart | 5 +++++ lib/generated/l10n/zulip_localizations_en.dart | 5 +++++ lib/generated/l10n/zulip_localizations_ja.dart | 5 +++++ lib/generated/l10n/zulip_localizations_nb.dart | 5 +++++ lib/generated/l10n/zulip_localizations_pl.dart | 5 +++++ lib/generated/l10n/zulip_localizations_ru.dart | 5 +++++ lib/generated/l10n/zulip_localizations_sk.dart | 5 +++++ lib/model/compose.dart | 7 +++++-- lib/widgets/action_sheet.dart | 4 +++- lib/widgets/compose_box.dart | 9 +++++++-- test/model/compose_test.dart | 4 +++- test/widgets/action_sheet_test.dart | 3 ++- 14 files changed, 68 insertions(+), 7 deletions(-) diff --git a/assets/l10n/app_en.arb b/assets/l10n/app_en.arb index 9c6bddaca2..093d189d54 100644 --- a/assets/l10n/app_en.arb +++ b/assets/l10n/app_en.arb @@ -351,6 +351,13 @@ "filename": {"type": "String", "example": "file.txt"} } }, + "composeBoxLoadingMessage": "(loading message {messageId})", + "@composeBoxLoadingMessage": { + "description": "Placeholder in compose box showing the quoted message is currently loading.", + "placeholders": { + "messageId": {"type": "int", "example": "1234"} + } + }, "unknownUserName": "(unknown user)", "@unknownUserName": { "description": "Name placeholder to use for a user when we don't know their name." diff --git a/lib/generated/l10n/zulip_localizations.dart b/lib/generated/l10n/zulip_localizations.dart index 792a84d68e..7542e05e74 100644 --- a/lib/generated/l10n/zulip_localizations.dart +++ b/lib/generated/l10n/zulip_localizations.dart @@ -567,6 +567,12 @@ abstract class ZulipLocalizations { /// **'Uploading {filename}…'** String composeBoxUploadingFilename(String filename); + /// Placeholder in compose box showing the quoted message is currently loading. + /// + /// In en, this message translates to: + /// **'(loading message {messageId})'** + String composeBoxLoadingMessage(int messageId); + /// Name placeholder to use for a user when we don't know their name. /// /// In en, this message translates to: diff --git a/lib/generated/l10n/zulip_localizations_ar.dart b/lib/generated/l10n/zulip_localizations_ar.dart index 2cafe3746f..7995ed41d0 100644 --- a/lib/generated/l10n/zulip_localizations_ar.dart +++ b/lib/generated/l10n/zulip_localizations_ar.dart @@ -277,6 +277,11 @@ class ZulipLocalizationsAr extends ZulipLocalizations { return 'Uploading $filename…'; } + @override + String composeBoxLoadingMessage(int messageId) { + return '(loading message $messageId)'; + } + @override String get unknownUserName => '(unknown user)'; diff --git a/lib/generated/l10n/zulip_localizations_en.dart b/lib/generated/l10n/zulip_localizations_en.dart index 18bcb204bb..9523e2ccda 100644 --- a/lib/generated/l10n/zulip_localizations_en.dart +++ b/lib/generated/l10n/zulip_localizations_en.dart @@ -277,6 +277,11 @@ class ZulipLocalizationsEn extends ZulipLocalizations { return 'Uploading $filename…'; } + @override + String composeBoxLoadingMessage(int messageId) { + return '(loading message $messageId)'; + } + @override String get unknownUserName => '(unknown user)'; diff --git a/lib/generated/l10n/zulip_localizations_ja.dart b/lib/generated/l10n/zulip_localizations_ja.dart index 801406fa4a..4182e64bad 100644 --- a/lib/generated/l10n/zulip_localizations_ja.dart +++ b/lib/generated/l10n/zulip_localizations_ja.dart @@ -277,6 +277,11 @@ class ZulipLocalizationsJa extends ZulipLocalizations { return 'Uploading $filename…'; } + @override + String composeBoxLoadingMessage(int messageId) { + return '(loading message $messageId)'; + } + @override String get unknownUserName => '(unknown user)'; diff --git a/lib/generated/l10n/zulip_localizations_nb.dart b/lib/generated/l10n/zulip_localizations_nb.dart index d38872b3ca..b5f7631668 100644 --- a/lib/generated/l10n/zulip_localizations_nb.dart +++ b/lib/generated/l10n/zulip_localizations_nb.dart @@ -277,6 +277,11 @@ class ZulipLocalizationsNb extends ZulipLocalizations { return 'Uploading $filename…'; } + @override + String composeBoxLoadingMessage(int messageId) { + return '(loading message $messageId)'; + } + @override String get unknownUserName => '(unknown user)'; diff --git a/lib/generated/l10n/zulip_localizations_pl.dart b/lib/generated/l10n/zulip_localizations_pl.dart index dfc7b41720..14f836a81a 100644 --- a/lib/generated/l10n/zulip_localizations_pl.dart +++ b/lib/generated/l10n/zulip_localizations_pl.dart @@ -277,6 +277,11 @@ class ZulipLocalizationsPl extends ZulipLocalizations { return 'Przekazywanie $filename…'; } + @override + String composeBoxLoadingMessage(int messageId) { + return '(loading message $messageId)'; + } + @override String get unknownUserName => '(nieznany użytkownik)'; diff --git a/lib/generated/l10n/zulip_localizations_ru.dart b/lib/generated/l10n/zulip_localizations_ru.dart index 62edfb248b..66ff950ffa 100644 --- a/lib/generated/l10n/zulip_localizations_ru.dart +++ b/lib/generated/l10n/zulip_localizations_ru.dart @@ -277,6 +277,11 @@ class ZulipLocalizationsRu extends ZulipLocalizations { return 'Загрузка $filename…'; } + @override + String composeBoxLoadingMessage(int messageId) { + return '(loading message $messageId)'; + } + @override String get unknownUserName => '(неизвестный пользователь)'; diff --git a/lib/generated/l10n/zulip_localizations_sk.dart b/lib/generated/l10n/zulip_localizations_sk.dart index 35a0dc6861..4882e34646 100644 --- a/lib/generated/l10n/zulip_localizations_sk.dart +++ b/lib/generated/l10n/zulip_localizations_sk.dart @@ -277,6 +277,11 @@ class ZulipLocalizationsSk extends ZulipLocalizations { return 'Uploading $filename…'; } + @override + String composeBoxLoadingMessage(int messageId) { + return '(loading message $messageId)'; + } + @override String get unknownUserName => '(unknown user)'; diff --git a/lib/model/compose.dart b/lib/model/compose.dart index a0b633c330..54c7f6ce00 100644 --- a/lib/model/compose.dart +++ b/lib/model/compose.dart @@ -1,6 +1,7 @@ import 'dart:math'; import '../api/model/model.dart'; +import '../generated/l10n/zulip_localizations.dart'; import 'internal_link.dart'; import 'narrow.dart'; import 'store.dart'; @@ -182,7 +183,9 @@ String inlineLink(String visibleText, Uri? destination) { } /// What we show while fetching the target message's raw Markdown. -String quoteAndReplyPlaceholder(PerAccountStore store, { +String quoteAndReplyPlaceholder( + ZulipLocalizations zulipLocalizations, + PerAccountStore store, { required Message message, }) { final sender = store.users[message.senderId]; @@ -192,7 +195,7 @@ String quoteAndReplyPlaceholder(PerAccountStore store, { nearMessageId: message.id); // See note in [quoteAndReply] about asking `mention` to omit the | part. return '${userMention(sender!, silent: true)} ${inlineLink('said', url)}: ' // TODO(#1285) - '*(loading message ${message.id})*\n'; // TODO(i18n) ? + '*${zulipLocalizations.composeBoxLoadingMessage(message.id)}*\n'; } /// Quote-and-reply syntax. diff --git a/lib/widgets/action_sheet.dart b/lib/widgets/action_sheet.dart index 6a90b61e64..3eff182bca 100644 --- a/lib/widgets/action_sheet.dart +++ b/lib/widgets/action_sheet.dart @@ -665,7 +665,9 @@ class QuoteAndReplyButton extends MessageActionSheetMenuItemButton { // This inserts a "[Quoting…]" placeholder into the content input, // giving the user a form of progress feedback. final tag = composeBoxController.content - .registerQuoteAndReplyStart(PerAccountStoreWidget.of(pageContext), + .registerQuoteAndReplyStart( + zulipLocalizations, + PerAccountStoreWidget.of(pageContext), message: message, ); diff --git a/lib/widgets/compose_box.dart b/lib/widgets/compose_box.dart index bdcce02b41..9ee87754b8 100644 --- a/lib/widgets/compose_box.dart +++ b/lib/widgets/compose_box.dart @@ -266,10 +266,15 @@ class ComposeContentController extends ComposeController /// /// Returns an int "tag" that should be passed to registerQuoteAndReplyEnd on /// success or failure - int registerQuoteAndReplyStart(PerAccountStore store, {required Message message}) { + int registerQuoteAndReplyStart( + ZulipLocalizations zulipLocalizations, + PerAccountStore store, { + required Message message, + }) { final tag = _nextQuoteAndReplyTag; _nextQuoteAndReplyTag += 1; - final placeholder = quoteAndReplyPlaceholder(store, message: message); + final placeholder = quoteAndReplyPlaceholder( + zulipLocalizations, store, message: message); _quoteAndReplies[tag] = (messageId: message.id, placeholder: placeholder); notifyListeners(); // _quoteAndReplies change could affect validationErrors insertPadded(placeholder); diff --git a/test/model/compose_test.dart b/test/model/compose_test.dart index ceda0d4cd6..73fa9452d7 100644 --- a/test/model/compose_test.dart +++ b/test/model/compose_test.dart @@ -1,6 +1,7 @@ import 'package:checks/checks.dart'; import 'package:test/scaffolding.dart'; import 'package:zulip/model/compose.dart'; +import 'package:zulip/model/localizations.dart'; import 'package:zulip/model/store.dart'; import '../example_data.dart' as eg; @@ -288,7 +289,8 @@ hello await store.addStream(stream); await store.addUser(sender); - check(quoteAndReplyPlaceholder(store, message: message)).equals(''' + check(quoteAndReplyPlaceholder( + GlobalLocalizations.zulipLocalizations, store, message: message)).equals(''' @_**Full Name|123** [said](${eg.selfAccount.realmUrl}#narrow/stream/1-test-here/topic/some.20topic/near/${message.id}): *(loading message ${message.id})* '''); diff --git a/test/widgets/action_sheet_test.dart b/test/widgets/action_sheet_test.dart index e6b48384b8..2bb07b4946 100644 --- a/test/widgets/action_sheet_test.dart +++ b/test/widgets/action_sheet_test.dart @@ -641,7 +641,8 @@ void main() { }) { check(contentController).value.equals((ComposeContentController() ..value = valueBefore - ..insertPadded(quoteAndReplyPlaceholder(store, message: message)) + ..insertPadded(quoteAndReplyPlaceholder( + GlobalLocalizations.zulipLocalizations, store, message: message)) ).value); check(contentController).validationErrors.contains(ContentValidationError.quoteAndReplyInProgress); } From 951733683543847e3a2618cfa3eea7f45985031a Mon Sep 17 00:00:00 2001 From: Zixuan James Li Date: Wed, 15 Jan 2025 17:01:14 -0500 Subject: [PATCH 14/14] poll: Translate voter names wrapped in parentheses Signed-off-by: Zixuan James Li --- assets/l10n/app_en.arb | 7 +++++++ lib/generated/l10n/zulip_localizations.dart | 6 ++++++ lib/generated/l10n/zulip_localizations_ar.dart | 5 +++++ lib/generated/l10n/zulip_localizations_en.dart | 5 +++++ lib/generated/l10n/zulip_localizations_ja.dart | 5 +++++ lib/generated/l10n/zulip_localizations_nb.dart | 5 +++++ lib/generated/l10n/zulip_localizations_pl.dart | 5 +++++ lib/generated/l10n/zulip_localizations_ru.dart | 5 +++++ lib/generated/l10n/zulip_localizations_sk.dart | 5 +++++ lib/widgets/poll.dart | 4 ++-- 10 files changed, 50 insertions(+), 2 deletions(-) diff --git a/assets/l10n/app_en.arb b/assets/l10n/app_en.arb index 093d189d54..ee7e96c35f 100644 --- a/assets/l10n/app_en.arb +++ b/assets/l10n/app_en.arb @@ -746,6 +746,13 @@ "@messageIsMovedLabel": { "description": "Label for a moved message. (Use ALL CAPS for cased alphabets: Latin, Greek, Cyrillic, etc.)" }, + "pollVoterNames": "({voterNames})", + "@pollVoterNames": { + "description": "The list of people who voted for a poll option, wrapped in parentheses.", + "placeholders": { + "voterNames": {"type": "String", "example": "Alice, Bob, Chad"} + } + }, "pollWidgetQuestionMissing": "No question.", "@pollWidgetQuestionMissing": { "description": "Text to display for a poll when the question is missing" diff --git a/lib/generated/l10n/zulip_localizations.dart b/lib/generated/l10n/zulip_localizations.dart index 7542e05e74..b6fbb70769 100644 --- a/lib/generated/l10n/zulip_localizations.dart +++ b/lib/generated/l10n/zulip_localizations.dart @@ -1101,6 +1101,12 @@ abstract class ZulipLocalizations { /// **'MOVED'** String get messageIsMovedLabel; + /// The list of people who voted for a poll option, wrapped in parentheses. + /// + /// In en, this message translates to: + /// **'({voterNames})'** + String pollVoterNames(String voterNames); + /// Text to display for a poll when the question is missing /// /// In en, this message translates to: diff --git a/lib/generated/l10n/zulip_localizations_ar.dart b/lib/generated/l10n/zulip_localizations_ar.dart index 7995ed41d0..025b4b1444 100644 --- a/lib/generated/l10n/zulip_localizations_ar.dart +++ b/lib/generated/l10n/zulip_localizations_ar.dart @@ -586,6 +586,11 @@ class ZulipLocalizationsAr extends ZulipLocalizations { @override String get messageIsMovedLabel => 'MOVED'; + @override + String pollVoterNames(String voterNames) { + return '($voterNames)'; + } + @override String get pollWidgetQuestionMissing => 'No question.'; diff --git a/lib/generated/l10n/zulip_localizations_en.dart b/lib/generated/l10n/zulip_localizations_en.dart index 9523e2ccda..9467d33428 100644 --- a/lib/generated/l10n/zulip_localizations_en.dart +++ b/lib/generated/l10n/zulip_localizations_en.dart @@ -586,6 +586,11 @@ class ZulipLocalizationsEn extends ZulipLocalizations { @override String get messageIsMovedLabel => 'MOVED'; + @override + String pollVoterNames(String voterNames) { + return '($voterNames)'; + } + @override String get pollWidgetQuestionMissing => 'No question.'; diff --git a/lib/generated/l10n/zulip_localizations_ja.dart b/lib/generated/l10n/zulip_localizations_ja.dart index 4182e64bad..f363ee0043 100644 --- a/lib/generated/l10n/zulip_localizations_ja.dart +++ b/lib/generated/l10n/zulip_localizations_ja.dart @@ -586,6 +586,11 @@ class ZulipLocalizationsJa extends ZulipLocalizations { @override String get messageIsMovedLabel => 'MOVED'; + @override + String pollVoterNames(String voterNames) { + return '($voterNames)'; + } + @override String get pollWidgetQuestionMissing => 'No question.'; diff --git a/lib/generated/l10n/zulip_localizations_nb.dart b/lib/generated/l10n/zulip_localizations_nb.dart index b5f7631668..35b3e86fe5 100644 --- a/lib/generated/l10n/zulip_localizations_nb.dart +++ b/lib/generated/l10n/zulip_localizations_nb.dart @@ -586,6 +586,11 @@ class ZulipLocalizationsNb extends ZulipLocalizations { @override String get messageIsMovedLabel => 'MOVED'; + @override + String pollVoterNames(String voterNames) { + return '($voterNames)'; + } + @override String get pollWidgetQuestionMissing => 'No question.'; diff --git a/lib/generated/l10n/zulip_localizations_pl.dart b/lib/generated/l10n/zulip_localizations_pl.dart index 14f836a81a..0594722d31 100644 --- a/lib/generated/l10n/zulip_localizations_pl.dart +++ b/lib/generated/l10n/zulip_localizations_pl.dart @@ -586,6 +586,11 @@ class ZulipLocalizationsPl extends ZulipLocalizations { @override String get messageIsMovedLabel => 'PRZENIESIONO'; + @override + String pollVoterNames(String voterNames) { + return '($voterNames)'; + } + @override String get pollWidgetQuestionMissing => 'Brak pytania.'; diff --git a/lib/generated/l10n/zulip_localizations_ru.dart b/lib/generated/l10n/zulip_localizations_ru.dart index 66ff950ffa..879559fed4 100644 --- a/lib/generated/l10n/zulip_localizations_ru.dart +++ b/lib/generated/l10n/zulip_localizations_ru.dart @@ -586,6 +586,11 @@ class ZulipLocalizationsRu extends ZulipLocalizations { @override String get messageIsMovedLabel => 'ПЕРЕМЕЩЕНО'; + @override + String pollVoterNames(String voterNames) { + return '($voterNames)'; + } + @override String get pollWidgetQuestionMissing => 'Нет вопроса.'; diff --git a/lib/generated/l10n/zulip_localizations_sk.dart b/lib/generated/l10n/zulip_localizations_sk.dart index 4882e34646..af87dfd949 100644 --- a/lib/generated/l10n/zulip_localizations_sk.dart +++ b/lib/generated/l10n/zulip_localizations_sk.dart @@ -586,6 +586,11 @@ class ZulipLocalizationsSk extends ZulipLocalizations { @override String get messageIsMovedLabel => 'PRESUNUTÉ'; + @override + String pollVoterNames(String voterNames) { + return '($voterNames)'; + } + @override String get pollWidgetQuestionMissing => 'Bez otázky.'; diff --git a/lib/widgets/poll.dart b/lib/widgets/poll.dart index 07123fe196..dc340d08b8 100644 --- a/lib/widgets/poll.dart +++ b/lib/widgets/poll.dart @@ -126,8 +126,8 @@ class _PollWidgetState extends State { children: [ Text(option.text, style: textStyleBold.copyWith(fontSize: 16)), if (option.voters.isNotEmpty) - // TODO(i18n): Localize parenthesis characters. - Text('($voterNames)', style: textStyleVoterNames), + Text(zulipLocalizations.pollVoterNames(voterNames), + style: textStyleVoterNames), ]))), ]); }