Refactor localization in UI components and error messages

- Updated various UI components to utilize AppLocalizations for better internationalization support.
- Replaced hardcoded strings with localized strings in home_screen.dart, ble_connection_manager.dart, contact_tile.dart, room_login_sheet.dart, compass widgets, and sar_update_sheet.dart.
- Improved user feedback messages by integrating localization for actions like pinging contacts, displaying connection statuses, and error notifications.
- Enhanced the clarity of UI elements by ensuring all text is translatable, improving the overall user experience for non-English speakers.
This commit is contained in:
Janez T
2025-10-16 15:39:48 +02:00
parent 1056380f3a
commit 01a1bbec44
17 changed files with 2469 additions and 217 deletions

View File

@@ -1,6 +1,7 @@
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import '../../../models/contact.dart';
/// Contact list section for the compass dialog.
@@ -28,7 +29,7 @@ class CompassContactList extends StatelessWidget {
}
if (position == null) {
return const Text('Location unavailable');
return Text(AppLocalizations.of(context)!.locationUnavailable);
}
// Calculate bearings and distances
@@ -60,13 +61,14 @@ class CompassContactList extends StatelessWidget {
contactsWithBearing.sort((a, b) =>
(a['distance'] as double).compareTo(b['distance'] as double));
final l10n = AppLocalizations.of(context)!;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(left: 16, bottom: 8),
child: Text(
'Nearby Contacts',
l10n.nearbyContacts,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
),
@@ -120,7 +122,7 @@ class CompassContactList extends StatelessWidget {
),
if (heading != null)
Text(
_formatRelativeBearing(bearing, heading!),
_formatRelativeBearing(bearing, heading!, context),
style: Theme.of(context).textTheme.labelSmall?.copyWith(
color: Colors.grey,
),
@@ -189,7 +191,8 @@ class CompassContactList extends StatelessWidget {
}
}
String _formatRelativeBearing(double bearing, double heading) {
String _formatRelativeBearing(double bearing, double heading, BuildContext context) {
final l10n = AppLocalizations.of(context)!;
// Calculate relative bearing (how much to turn from current heading)
double relative = bearing - heading;
@@ -204,11 +207,11 @@ class CompassContactList extends StatelessWidget {
final absRelative = relative.abs().round();
if (absRelative < 10) {
return 'ahead';
return l10n.ahead;
} else if (relative > 0) {
return '$absRelative° right';
return l10n.degreesRight(absRelative);
} else {
return '$absRelative° left';
return l10n.degreesLeft(absRelative);
}
}
}

View File

@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import '../../../l10n/app_localizations.dart';
/// Filter controls for the compass dialog.
/// Allows filtering of contacts and SAR marker types.
@@ -32,15 +33,16 @@ class CompassFilters extends StatefulWidget {
class _CompassFiltersState extends State<CompassFilters> {
void _showFilterDialog() {
final l10n = AppLocalizations.of(context)!;
showDialog(
context: context,
builder: (context) => StatefulBuilder(
builder: (context, setDialogState) => AlertDialog(
title: const Row(
title: Row(
children: [
Icon(Icons.filter_list, size: 20),
SizedBox(width: 8),
Text('Filter Markers'),
const Icon(Icons.filter_list, size: 20),
const SizedBox(width: 8),
Text(l10n.filterMarkers),
],
),
contentPadding: const EdgeInsets.fromLTRB(24, 16, 24, 0),
@@ -52,7 +54,7 @@ class _CompassFiltersState extends State<CompassFilters> {
_CompactFilterItem(
icon: Icons.person,
color: Theme.of(context).colorScheme.primary,
label: 'Contacts',
label: l10n.contactsFilter,
value: widget.showContacts,
onChanged: (value) {
widget.onShowContactsChanged(value);
@@ -66,7 +68,7 @@ class _CompassFiltersState extends State<CompassFilters> {
Padding(
padding: const EdgeInsets.only(left: 8, bottom: 8, top: 4),
child: Text(
'SAR Markers',
l10n.sarMarkers,
style: Theme.of(context).textTheme.labelLarge?.copyWith(
fontWeight: FontWeight.bold,
),
@@ -75,7 +77,7 @@ class _CompassFiltersState extends State<CompassFilters> {
_CompactFilterItem(
icon: Icons.person_pin,
color: Colors.green,
label: 'Found Person',
label: l10n.foundPerson,
value: widget.showFoundPerson,
onChanged: (value) {
widget.onShowFoundPersonChanged(value);
@@ -86,7 +88,7 @@ class _CompassFiltersState extends State<CompassFilters> {
_CompactFilterItem(
icon: Icons.local_fire_department,
color: Colors.red,
label: 'Fire',
label: l10n.fire,
value: widget.showFire,
onChanged: (value) {
widget.onShowFireChanged(value);
@@ -97,7 +99,7 @@ class _CompassFiltersState extends State<CompassFilters> {
_CompactFilterItem(
icon: Icons.home_work,
color: Colors.orange,
label: 'Staging Area',
label: l10n.stagingArea,
value: widget.showStagingArea,
onChanged: (value) {
widget.onShowStagingAreaChanged(value);
@@ -112,11 +114,11 @@ class _CompassFiltersState extends State<CompassFilters> {
widget.onShowAll();
setDialogState(() {});
},
child: const Text('Show All'),
child: Text(l10n.showAll),
),
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('Close'),
child: Text(l10n.close),
),
],
),
@@ -126,9 +128,10 @@ class _CompassFiltersState extends State<CompassFilters> {
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
return IconButton(
icon: const Icon(Icons.filter_list),
tooltip: 'Filter markers',
tooltip: l10n.filterMarkersTooltip,
onPressed: () => _showFilterDialog(),
);
}

View File

@@ -3,6 +3,7 @@ import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:latlong2/latlong.dart';
import '../../../l10n/app_localizations.dart';
import '../../../models/contact.dart';
import '../../../models/sar_marker.dart';
@@ -76,18 +77,19 @@ class CompassHeader extends StatelessWidget {
}
Widget _buildInfoRow(BuildContext context, double? heading, Position? position) {
final l10n = AppLocalizations.of(context)!;
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_buildInfoCard(
context,
'Heading',
l10n.heading,
heading != null ? '${heading.round()}°' : '--',
Icons.explore,
),
_buildInfoCard(
context,
'Elevation',
l10n.elevation,
position?.altitude != null
? '${position!.altitude.round()}m'
: '--',
@@ -95,7 +97,7 @@ class CompassHeader extends StatelessWidget {
),
_buildInfoCard(
context,
'Accuracy',
l10n.accuracy,
position?.accuracy != null
? '±${position!.accuracy.round()}m'
: '--',
@@ -566,12 +568,16 @@ class _LocationFormatToggleState extends State<_LocationFormatToggle> {
return const SizedBox.shrink();
}
final l10n = AppLocalizations.of(context)!;
final String displayText;
if (_showDMS) {
displayText = '${_formatDMS(position.latitude, true)} ${_formatDMS(position.longitude, false)}';
} else {
displayText = 'Lat: ${position.latitude.toStringAsFixed(5)} Lon: ${position.longitude.toStringAsFixed(5)}';
displayText = l10n.latLonFormat(
position.latitude.toStringAsFixed(5),
position.longitude.toStringAsFixed(5),
);
}
return GestureDetector(

View File

@@ -1,6 +1,7 @@
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import '../../../models/sar_marker.dart';
/// SAR marker list section for the compass dialog.
@@ -28,7 +29,7 @@ class CompassSarList extends StatelessWidget {
}
if (position == null) {
return const Text('Location unavailable');
return Text(AppLocalizations.of(context)!.locationUnavailable);
}
// Calculate bearings and distances for SAR markers
@@ -58,13 +59,14 @@ class CompassSarList extends StatelessWidget {
markersWithBearing.sort((a, b) =>
(a['distance'] as double).compareTo(b['distance'] as double));
final l10n = AppLocalizations.of(context)!;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(left: 16, top: 16, bottom: 8),
child: Text(
'SAR Markers',
l10n.sarMarkers,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
),
@@ -139,7 +141,7 @@ class CompassSarList extends StatelessWidget {
),
if (heading != null)
Text(
_formatRelativeBearing(bearing, heading!),
_formatRelativeBearing(bearing, heading!, context),
style: Theme.of(context).textTheme.labelSmall?.copyWith(
color: Colors.grey,
),
@@ -208,7 +210,8 @@ class CompassSarList extends StatelessWidget {
}
}
String _formatRelativeBearing(double bearing, double heading) {
String _formatRelativeBearing(double bearing, double heading, BuildContext context) {
final l10n = AppLocalizations.of(context)!;
// Calculate relative bearing (how much to turn from current heading)
double relative = bearing - heading;
@@ -223,11 +226,11 @@ class CompassSarList extends StatelessWidget {
final absRelative = relative.abs().round();
if (absRelative < 10) {
return 'ahead';
return l10n.ahead;
} else if (relative > 0) {
return '$absRelative° right';
return l10n.degreesRight(absRelative);
} else {
return '$absRelative° left';
return l10n.degreesLeft(absRelative);
}
}
}