Add localization support for various UI elements and messages

- Integrated localization for alert dialogs, snack bars, and button labels in PacketLogScreen and SettingsScreen.
- Updated location tracking service messages to use localized strings.
- Enhanced ContactTile and DirectMessageSheet with localized text for user interactions.
- Implemented localization in DrawingLayer and DrawingToolbar for map-related actions.
- Updated SAR Update Sheet to utilize localized strings for user prompts and actions.
- Ensured consistent use of localization across all relevant widgets and screens.
This commit is contained in:
Janez T
2025-10-16 15:19:05 +02:00
parent 9def8daf0c
commit 1056380f3a
24 changed files with 1246 additions and 236 deletions

View File

@@ -11,6 +11,7 @@ import '../../providers/map_provider.dart';
import 'direct_message_sheet.dart';
import 'room_login_sheet.dart';
import '../../utils/toast_logger.dart';
import '../../l10n/app_localizations.dart';
class ContactTile extends StatelessWidget {
final Contact contact;
@@ -359,7 +360,7 @@ class ContactTile extends StatelessWidget {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Delete Contact'),
title: Text(AppLocalizations.of(context)!.deleteContact),
content: Text(
'Are you sure you want to delete "${contact.displayName}"?\n\n'
'This will remove the contact from both the app and the companion radio device.',
@@ -367,7 +368,7 @@ class ContactTile extends StatelessWidget {
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('Cancel'),
child: Text(AppLocalizations.of(context)!.cancel),
),
TextButton(
onPressed: () async {
@@ -376,7 +377,7 @@ class ContactTile extends StatelessWidget {
await _deleteContact(context, contact);
},
style: TextButton.styleFrom(foregroundColor: Colors.red),
child: const Text('Delete'),
child: Text(AppLocalizations.of(context)!.delete),
),
],
),
@@ -504,9 +505,9 @@ class ContactTile extends StatelessWidget {
onTap: () {
Clipboard.setData(ClipboardData(text: contact.publicKeyHex));
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Public key copied to clipboard'),
duration: Duration(seconds: 2),
SnackBar(
content: Text(AppLocalizations.of(context)!.publicKeyCopied),
duration: const Duration(seconds: 2),
),
);
},
@@ -587,7 +588,7 @@ class ContactTile extends StatelessWidget {
DefaultTabController.of(context).animateTo(2);
},
icon: const Icon(Icons.map, size: 18),
label: const Text('View on Map'),
label: Text(AppLocalizations.of(context)!.viewOnMap),
style: TextButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
),
@@ -645,7 +646,7 @@ class ContactTile extends StatelessWidget {
ToastLogger.info(context, 'Requesting telemetry from ${contact.displayName}...');
},
icon: const Icon(Icons.refresh, size: 18),
label: const Text('Refresh'),
label: Text(AppLocalizations.of(context)!.refresh),
style: TextButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
),
@@ -688,7 +689,7 @@ class ContactTile extends StatelessWidget {
_showDirectMessageDialog(context, contact);
},
icon: const Icon(Icons.message),
label: const Text('Send Direct Message'),
label: Text(AppLocalizations.of(context)!.sendDirectMessage),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 14),
backgroundColor: _getTypeColor(contact.type, context),
@@ -705,7 +706,7 @@ class ContactTile extends StatelessWidget {
ToastLogger.info(context, 'Path reset for ${contact.displayName}. Next message will find a new route.');
},
icon: const Icon(Icons.route),
label: const Text('Reset Path (Re-route)'),
label: Text(AppLocalizations.of(context)!.resetPath),
style: OutlinedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 14),
side: BorderSide(color: _getTypeColor(contact.type, context)),
@@ -742,7 +743,7 @@ class ContactTile extends StatelessWidget {
child: OutlinedButton.icon(
onPressed: () => _showDeleteConfirmation(context, contact),
icon: const Icon(Icons.delete_outline),
label: const Text('Delete Contact'),
label: Text(AppLocalizations.of(context)!.deleteContact),
style: OutlinedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 14),
side: const BorderSide(color: Colors.red),
@@ -803,7 +804,7 @@ class ContactTile extends StatelessWidget {
Clipboard.setData(ClipboardData(text: value));
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('$label copied to clipboard'),
content: Text(AppLocalizations.of(context)!.copiedToClipboard(label)),
duration: const Duration(seconds: 2),
),
);

View File

@@ -7,6 +7,7 @@ import '../../models/message.dart';
import '../../providers/connection_provider.dart';
import '../../providers/messages_provider.dart';
import '../../utils/toast_logger.dart';
import '../../l10n/app_localizations.dart';
class DirectMessageSheet extends StatefulWidget {
final Contact contact;
@@ -51,7 +52,7 @@ class _DirectMessageSheetState extends State<DirectMessageSheet> {
if (!connectionProvider.deviceInfo.isConnected) {
if (!mounted) return;
ToastLogger.error(context, 'Not connected to device');
ToastLogger.error(context, AppLocalizations.of(context)!.notConnectedToDevice);
return;
}
@@ -100,10 +101,10 @@ class _DirectMessageSheetState extends State<DirectMessageSheet> {
if (!mounted) return;
Navigator.pop(context); // Close the dialog
ToastLogger.success(context, 'Direct message sent to ${widget.contact.displayName}');
ToastLogger.success(context, AppLocalizations.of(context)!.directMessageSentTo(widget.contact.displayName));
} catch (e) {
if (!mounted) return;
ToastLogger.error(context, 'Failed to send: $e');
ToastLogger.error(context, AppLocalizations.of(context)!.failedToSend(e.toString()));
}
}
@@ -137,7 +138,7 @@ class _DirectMessageSheetState extends State<DirectMessageSheet> {
child: Column(
children: [
Text(
'Direct Message',
AppLocalizations.of(context)!.directMessage,
style: TextStyle(
color: colorScheme.onSurface,
fontSize: 18,
@@ -173,7 +174,7 @@ class _DirectMessageSheetState extends State<DirectMessageSheet> {
const SizedBox(width: 12),
Expanded(
child: Text(
'This message will be sent directly to ${widget.contact.displayName}. It will also appear in the main messages feed.',
AppLocalizations.of(context)!.directMessageInfo(widget.contact.displayName),
style: TextStyle(
color: Theme.of(context).colorScheme.onPrimaryContainer,
fontSize: 13,
@@ -210,7 +211,7 @@ class _DirectMessageSheetState extends State<DirectMessageSheet> {
maxLengthEnforcement: MaxLengthEnforcement.enforced,
style: TextStyle(color: colorScheme.onSurface),
decoration: InputDecoration(
hintText: 'Type your message...',
hintText: AppLocalizations.of(context)!.typeYourMessage,
hintStyle: TextStyle(color: colorScheme.onSurfaceVariant),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
@@ -246,7 +247,7 @@ class _DirectMessageSheetState extends State<DirectMessageSheet> {
? null
: _sendDirectMessage,
icon: const Icon(Icons.send),
label: const Text('Send Direct Message'),
label: Text(AppLocalizations.of(context)!.sendDirectMessage),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 14),
backgroundColor: colorScheme.primary,

View File

@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../l10n/app_localizations.dart';
import '../../models/contact.dart';
import '../../providers/connection_provider.dart';
import '../../providers/contacts_provider.dart';
@@ -62,7 +63,7 @@ class _RoomLoginSheetState extends State<RoomLoginSheet> {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: const Text('Please enter a password'),
content: Text(AppLocalizations.of(context)!.pleaseEnterPassword),
backgroundColor: Theme.of(context).colorScheme.error,
),
);
@@ -73,7 +74,7 @@ class _RoomLoginSheetState extends State<RoomLoginSheet> {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: const Text('Not connected to device'),
content: Text(AppLocalizations.of(context)!.deviceNotConnected),
backgroundColor: Theme.of(context).colorScheme.error,
),
);
@@ -183,7 +184,7 @@ class _RoomLoginSheetState extends State<RoomLoginSheet> {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Failed to sync contacts: $e'),
content: Text(AppLocalizations.of(context)!.failedToSyncContacts(e.toString())),
backgroundColor: Theme.of(context).colorScheme.error,
),
);
@@ -215,7 +216,7 @@ class _RoomLoginSheetState extends State<RoomLoginSheet> {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: const Text('Logged in successfully! Waiting for room messages...'),
content: Text(AppLocalizations.of(context)!.loggedInSuccessfully),
backgroundColor: Theme.of(context).colorScheme.primary,
duration: const Duration(seconds: 3),
),
@@ -233,7 +234,7 @@ class _RoomLoginSheetState extends State<RoomLoginSheet> {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: const Text('Login failed - incorrect password'),
content: Text(AppLocalizations.of(context)!.loginFailed),
backgroundColor: Theme.of(context).colorScheme.error,
duration: const Duration(seconds: 3),
),
@@ -255,7 +256,7 @@ class _RoomLoginSheetState extends State<RoomLoginSheet> {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Logging in to ${widget.contact.displayName}...'),
content: Text(AppLocalizations.of(context)!.loggingIn(widget.contact.displayName)),
backgroundColor: Theme.of(context).colorScheme.primary,
duration: const Duration(seconds: 2),
),
@@ -268,7 +269,7 @@ class _RoomLoginSheetState extends State<RoomLoginSheet> {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Failed to send login: $e'),
content: Text(AppLocalizations.of(context)!.failedToSendLogin(e.toString())),
backgroundColor: Theme.of(context).colorScheme.error,
),
);