From 84a30b9218b96e11eb834d0db8d477a079b34767 Mon Sep 17 00:00:00 2001 From: Shu Chen Date: Mon, 2 Oct 2023 19:00:23 +0100 Subject: [PATCH] compose: Add translations to UI widgets --- assets/l10n/app_en.arb | 51 +++++++++++++++++++++++++++++ lib/widgets/compose_box.dart | 43 +++++++++++++++--------- test/widgets/autocomplete_test.dart | 3 ++ 3 files changed, 82 insertions(+), 15 deletions(-) diff --git a/assets/l10n/app_en.arb b/assets/l10n/app_en.arb index 575cbb2338..a191a36a7e 100644 --- a/assets/l10n/app_en.arb +++ b/assets/l10n/app_en.arb @@ -132,6 +132,57 @@ "@successMessageCopied": { "description": "Message when content of a message was copied to the users system clipboard." }, + "composeBoxAttachFilesTooltip": "Attach files", + "@composeBoxAttachFilesTooltip": { + "description": "Tooltip for compose box icon to attach a file to the message." + }, + "composeBoxAttachMediaTooltip": "Attach images or videos", + "@composeBoxAttachMediaTooltip": { + "description": "Tooltip for compose box icon to attach media to the message." + }, + "composeBoxAttachFromCameraTooltip": "Take a photo", + "@composeBoxAttachFromCameraTooltip": { + "description": "Tooltip for compose box icon to attach an image from the camera to the message." + }, + "composeBoxGenericContentHint": "Type a message", + "@composeBoxGenericContentHint": { + "description": "Hint text for content input when sending a message." + }, + "composeBoxDmContentHint": "Message @{user}", + "@composeBoxDmContentHint": { + "description": "Hint text for content input when sending a message to one other person.", + "placeholders": { + "user": {"type": "String", "example": "stream name"} + } + }, + "composeBoxGroupDmContentHint": "Message group", + "@composeBoxGroupDmContentHint": { + "description": "Hint text for content input when sending a message to a group." + }, + "composeBoxSelfDmContentHint": "Jot down something", + "@composeBoxSelfDmContentHint": { + "description": "Hint text for content input when sending a message to yourself." + }, + "composeBoxStreamContentHint": "Message #{stream} > {topic}", + "@composeBoxStreamContentHint": { + "description": "Hint text for content input when sending a message to a stream", + "placeholders": { + "stream": {"type": "String", "example": "stream name"}, + "topic": {"type": "String", "example": "topic name"} + } + }, + "composeBoxSendTooltip": "Send", + "@composeBoxSendTooltip": { + "description": "Tooltip for send button in compose box." + }, + "composeBoxUnknownStreamName": "(unknown stream)", + "@composeBoxUnknownStreamName": { + "description": "Replacement name for stream when it cannot be found in the store." + }, + "composeBoxTopicHintText": "Topic", + "@composeBoxTopicHintText": { + "description": "Hint text for topic input widget in compose box." + }, "composeBoxUploadingFilename": "Uploading {filename}...", "@composeBoxUploadingFilename": { "description": "Label in compose box showing the specified file is currently uploading.", diff --git a/lib/widgets/compose_box.dart b/lib/widgets/compose_box.dart index 13ee962adc..34b2c6d33b 100644 --- a/lib/widgets/compose_box.dart +++ b/lib/widgets/compose_box.dart @@ -360,12 +360,14 @@ class _StreamContentInputState extends State<_StreamContentInput> { @override Widget build(BuildContext context) { final store = PerAccountStoreWidget.of(context); - final streamName = store.streams[widget.narrow.streamId]?.name ?? '(unknown stream)'; + final zulipLocalizations = ZulipLocalizations.of(context); + final streamName = store.streams[widget.narrow.streamId]?.name + ?? zulipLocalizations.composeBoxUnknownStreamName; return _ContentInput( narrow: widget.narrow, controller: widget.controller, focusNode: widget.focusNode, - hintText: "Message #$streamName > $_topicTextNormalized"); + hintText: zulipLocalizations.composeBoxStreamContentHint(streamName, _topicTextNormalized)); } } @@ -381,23 +383,25 @@ class _FixedDestinationContentInput extends StatelessWidget { final FocusNode focusNode; String _hintText(BuildContext context) { + final zulipLocalizations = ZulipLocalizations.of(context); switch (narrow) { case TopicNarrow(:final streamId, :final topic): final store = PerAccountStoreWidget.of(context); - final streamName = store.streams[streamId]?.name ?? '(unknown stream)'; - return "Message #$streamName > $topic"; + final streamName = store.streams[streamId]?.name + ?? zulipLocalizations.composeBoxUnknownStreamName; + return zulipLocalizations.composeBoxStreamContentHint(streamName, topic); case DmNarrow(otherRecipientIds: []): // The self-1:1 thread. - return "Jot down something"; + return zulipLocalizations.composeBoxSelfDmContentHint; case DmNarrow(otherRecipientIds: [final otherUserId]): final store = PerAccountStoreWidget.of(context); final fullName = store.users[otherUserId]?.fullName; - if (fullName == null) return 'Type a message'; - return 'Message @$fullName'; + if (fullName == null) return zulipLocalizations.composeBoxGenericContentHint; + return zulipLocalizations.composeBoxDmContentHint(fullName); case DmNarrow(): // A group DM thread. - return 'Message group'; + return zulipLocalizations.composeBoxGroupDmContentHint; } } @@ -493,7 +497,7 @@ abstract class _AttachUploadsButton extends StatelessWidget { final FocusNode contentFocusNode; IconData get icon; - String get tooltip; + String tooltip(ZulipLocalizations zulipLocalizations); /// Request files from the user, in the way specific to this upload type. /// @@ -525,9 +529,10 @@ abstract class _AttachUploadsButton extends StatelessWidget { @override Widget build(BuildContext context) { + final zulipLocalizations = ZulipLocalizations.of(context); return IconButton( icon: Icon(icon), - tooltip: tooltip, + tooltip: tooltip(zulipLocalizations), onPressed: () => _handlePress(context)); } } @@ -576,8 +581,10 @@ class _AttachFileButton extends _AttachUploadsButton { @override IconData get icon => Icons.attach_file; + @override - String get tooltip => 'Attach files'; + String tooltip(ZulipLocalizations zulipLocalizations) => + zulipLocalizations.composeBoxAttachFilesTooltip; @override Future> getFiles(BuildContext context) async { @@ -590,8 +597,10 @@ class _AttachMediaButton extends _AttachUploadsButton { @override IconData get icon => Icons.image; + @override - String get tooltip => 'Attach images or videos'; + String tooltip(ZulipLocalizations zulipLocalizations) => + zulipLocalizations.composeBoxAttachMediaTooltip; @override Future> getFiles(BuildContext context) async { @@ -605,8 +614,10 @@ class _AttachFromCameraButton extends _AttachUploadsButton { @override IconData get icon => Icons.camera_alt; + @override - String get tooltip => 'Take a photo'; + String tooltip(ZulipLocalizations zulipLocalizations) => + zulipLocalizations.composeBoxAttachFromCameraTooltip; @override Future> getFiles(BuildContext context) async { @@ -731,6 +742,7 @@ class _SendButtonState extends State<_SendButton> { Widget build(BuildContext context) { final disabled = _hasValidationErrors; final colorScheme = Theme.of(context).colorScheme; + final zulipLocalizations = ZulipLocalizations.of(context); // Copy FilledButton defaults (_FilledButtonDefaultsM3.backgroundColor) final backgroundColor = disabled @@ -748,7 +760,7 @@ class _SendButtonState extends State<_SendButton> { color: backgroundColor, ), child: IconButton( - tooltip: 'Send', + tooltip: zulipLocalizations.composeBoxSendTooltip, // Match the height of the content input. Zeroing the padding lets the // constraints take over. @@ -866,6 +878,7 @@ class _StreamComposeBoxState extends State<_StreamComposeBox> implements Compose @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; + final zulipLocalizations = ZulipLocalizations.of(context); return _ComposeBoxLayout( contentController: _contentController, @@ -873,7 +886,7 @@ class _StreamComposeBoxState extends State<_StreamComposeBox> implements Compose topicInput: TextField( controller: _topicController, style: TextStyle(color: colorScheme.onSurface), - decoration: const InputDecoration(hintText: 'Topic'), + decoration: InputDecoration(hintText: zulipLocalizations.composeBoxTopicHintText), ), contentInput: _StreamContentInput( narrow: widget.narrow, diff --git a/test/widgets/autocomplete_test.dart b/test/widgets/autocomplete_test.dart index 164cd76515..6f540111ca 100644 --- a/test/widgets/autocomplete_test.dart +++ b/test/widgets/autocomplete_test.dart @@ -1,5 +1,6 @@ import 'package:checks/checks.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/zulip_localizations.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:zulip/api/model/model.dart'; import 'package:zulip/api/route/messages.dart'; @@ -40,6 +41,8 @@ Future setupToComposeInput(WidgetTester tester, { await tester.pumpWidget( MaterialApp( + localizationsDelegates: ZulipLocalizations.localizationsDelegates, + supportedLocales: ZulipLocalizations.supportedLocales, home: GlobalStoreWidget( child: PerAccountStoreWidget( accountId: eg.selfAccount.id,