From 4a7a99502c3ac5615270607de9cab66d3f86502c Mon Sep 17 00:00:00 2001 From: stopflock Date: Mon, 29 Sep 2025 11:42:48 -0500 Subject: [PATCH] Finish localizations, remove now-inaccurate sandbox note --- lib/localizations/de.json | 19 +++++++- lib/localizations/en.json | 19 +++++++- lib/localizations/es.json | 19 +++++++- lib/localizations/fr.json | 19 +++++++- .../offline_areas_section.dart | 2 +- .../upload_mode_section.dart | 16 ++----- lib/widgets/map/layer_selector_button.dart | 20 ++++---- lib/widgets/refine_tags_sheet.dart | 48 ++++++++++--------- 8 files changed, 112 insertions(+), 50 deletions(-) diff --git a/lib/localizations/de.json b/lib/localizations/de.json index 4a39dfd..9ed1a00 100644 --- a/lib/localizations/de.json +++ b/lib/localizations/de.json @@ -90,7 +90,6 @@ "simulate": "Simulieren", "productionDescription": "Hochladen in die Live-OSM-Datenbank (für alle Benutzer sichtbar)", "sandboxDescription": "Uploads gehen an die OSM Sandbox (sicher zum Testen, wird regelmäßig zurückgesetzt).", - "sandboxNote": "HINWEIS: Aufgrund von OpenStreetMap-Limitierungen werden Kameras, die an die Sandbox übermittelt werden, NICHT in der Karte dieser App angezeigt.", "simulateDescription": "Uploads simulieren (kontaktiert OSM-Server nicht)" }, "auth": { @@ -220,6 +219,7 @@ "noAreasTitle": "Keine Offline-Bereiche", "noAreasSubtitle": "Laden Sie einen Kartenbereich für die Offline-Nutzung herunter.", "provider": "Anbieter", + "maxZoom": "Max Zoom", "zoomLevels": "Z{}-{}", "latitude": "Breite", "longitude": "Länge", @@ -237,5 +237,22 @@ "megabytes": "MB", "kilobytes": "KB", "progress": "{}%" + }, + "refineTagsSheet": { + "title": "Tags Verfeinern", + "operatorProfile": "Betreiber-Profil", + "done": "Fertig", + "none": "Keine", + "noAdditionalOperatorTags": "Keine zusätzlichen Betreiber-Tags", + "additionalTags": "zusätzliche Tags", + "additionalTagsTitle": "Zusätzliche Tags", + "noTagsDefinedForProfile": "Keine Tags für dieses Betreiber-Profil definiert.", + "noOperatorProfiles": "Keine Betreiber-Profile definiert", + "noOperatorProfilesMessage": "Erstellen Sie Betreiber-Profile in den Einstellungen, um zusätzliche Tags auf Ihre Knoten-Übertragungen anzuwenden." + }, + "layerSelector": { + "cannotChangeTileTypes": "Kachel-Typen können während des Herunterladens von Offline-Bereichen nicht geändert werden", + "selectMapLayer": "Kartenschicht Auswählen", + "noTileProvidersAvailable": "Keine Kachel-Anbieter verfügbar" } } \ No newline at end of file diff --git a/lib/localizations/en.json b/lib/localizations/en.json index 3f0409f..f3a8168 100644 --- a/lib/localizations/en.json +++ b/lib/localizations/en.json @@ -90,7 +90,6 @@ "simulate": "Simulate", "productionDescription": "Upload to the live OSM database (visible to all users)", "sandboxDescription": "Uploads go to the OSM Sandbox (safe for testing, resets regularly).", - "sandboxNote": "NOTE: Due to OpenStreetMap limitations, cameras submitted to the sandbox will NOT appear on the map in this app.", "simulateDescription": "Simulate uploads (does not contact OSM servers)" }, "auth": { @@ -220,6 +219,7 @@ "noAreasTitle": "No offline areas", "noAreasSubtitle": "Download a map area for offline use.", "provider": "Provider", + "maxZoom": "Max zoom", "zoomLevels": "Z{}-{}", "latitude": "Lat", "longitude": "Lon", @@ -237,5 +237,22 @@ "megabytes": "MB", "kilobytes": "KB", "progress": "{}%" + }, + "refineTagsSheet": { + "title": "Refine Tags", + "operatorProfile": "Operator Profile", + "done": "Done", + "none": "None", + "noAdditionalOperatorTags": "No additional operator tags", + "additionalTags": "additional tags", + "additionalTagsTitle": "Additional Tags", + "noTagsDefinedForProfile": "No tags defined for this operator profile.", + "noOperatorProfiles": "No operator profiles defined", + "noOperatorProfilesMessage": "Create operator profiles in Settings to apply additional tags to your node submissions." + }, + "layerSelector": { + "cannotChangeTileTypes": "Cannot change tile types while downloading offline areas", + "selectMapLayer": "Select Map Layer", + "noTileProvidersAvailable": "No tile providers available" } } \ No newline at end of file diff --git a/lib/localizations/es.json b/lib/localizations/es.json index 38d2eae..6f8b035 100644 --- a/lib/localizations/es.json +++ b/lib/localizations/es.json @@ -90,7 +90,6 @@ "simulate": "Simular", "productionDescription": "Subir a la base de datos OSM en vivo (visible para todos los usuarios)", "sandboxDescription": "Las subidas van al Sandbox de OSM (seguro para pruebas, se reinicia regularmente).", - "sandboxNote": "NOTA: Debido a las limitaciones de OpenStreetMap, las cámaras enviadas al sandbox NO aparecerán en el mapa de esta aplicación.", "simulateDescription": "Simular subidas (no contacta servidores OSM)" }, "auth": { @@ -220,6 +219,7 @@ "noAreasTitle": "Sin áreas sin conexión", "noAreasSubtitle": "Descarga un área del mapa para uso sin conexión.", "provider": "Proveedor", + "maxZoom": "Zoom máx", "zoomLevels": "Z{}-{}", "latitude": "Lat", "longitude": "Lon", @@ -237,5 +237,22 @@ "megabytes": "MB", "kilobytes": "KB", "progress": "{}%" + }, + "refineTagsSheet": { + "title": "Refinar Etiquetas", + "operatorProfile": "Perfil de Operador", + "done": "Listo", + "none": "Ninguno", + "noAdditionalOperatorTags": "Sin etiquetas adicionales de operador", + "additionalTags": "etiquetas adicionales", + "additionalTagsTitle": "Etiquetas Adicionales", + "noTagsDefinedForProfile": "No hay etiquetas definidas para este perfil de operador.", + "noOperatorProfiles": "No hay perfiles de operador definidos", + "noOperatorProfilesMessage": "Cree perfiles de operador en Configuración para aplicar etiquetas adicionales a sus envíos de nodos." + }, + "layerSelector": { + "cannotChangeTileTypes": "No se pueden cambiar los tipos de teselas mientras se descargan áreas sin conexión", + "selectMapLayer": "Seleccionar Capa del Mapa", + "noTileProvidersAvailable": "No hay proveedores de teselas disponibles" } } \ No newline at end of file diff --git a/lib/localizations/fr.json b/lib/localizations/fr.json index 209c921..429cde5 100644 --- a/lib/localizations/fr.json +++ b/lib/localizations/fr.json @@ -90,7 +90,6 @@ "simulate": "Simuler", "productionDescription": "Télécharger vers la base de données OSM en direct (visible pour tous les utilisateurs)", "sandboxDescription": "Les téléchargements vont vers le Sandbox OSM (sûr pour les tests, réinitialisé régulièrement).", - "sandboxNote": "NOTE: En raison des limitations d'OpenStreetMap, les caméras soumises au sandbox n'apparaîtront PAS sur la carte dans cette application.", "simulateDescription": "Simuler les téléchargements (ne contacte pas les serveurs OSM)" }, "auth": { @@ -220,6 +219,7 @@ "noAreasTitle": "Aucune zone hors ligne", "noAreasSubtitle": "Téléchargez une zone de carte pour utilisation hors ligne.", "provider": "Fournisseur", + "maxZoom": "Zoom max", "zoomLevels": "Z{}-{}", "latitude": "Lat", "longitude": "Lon", @@ -237,5 +237,22 @@ "megabytes": "Mo", "kilobytes": "Ko", "progress": "{}%" + }, + "refineTagsSheet": { + "title": "Affiner les Étiquettes", + "operatorProfile": "Profil d'Opérateur", + "done": "Terminé", + "none": "Aucun", + "noAdditionalOperatorTags": "Aucune étiquette d'opérateur supplémentaire", + "additionalTags": "étiquettes supplémentaires", + "additionalTagsTitle": "Étiquettes Supplémentaires", + "noTagsDefinedForProfile": "Aucune étiquette définie pour ce profil d'opérateur.", + "noOperatorProfiles": "Aucun profil d'opérateur défini", + "noOperatorProfilesMessage": "Créez des profils d'opérateur dans les Paramètres pour appliquer des étiquettes supplémentaires à vos soumissions de nœuds." + }, + "layerSelector": { + "cannotChangeTileTypes": "Impossible de changer les types de tuiles pendant le téléchargement des zones hors ligne", + "selectMapLayer": "Sélectionner la Couche de Carte", + "noTileProvidersAvailable": "Aucun fournisseur de tuiles disponible" } } \ No newline at end of file diff --git a/lib/screens/settings_screen_sections/offline_areas_section.dart b/lib/screens/settings_screen_sections/offline_areas_section.dart index 2c895cf..54e7ec3 100644 --- a/lib/screens/settings_screen_sections/offline_areas_section.dart +++ b/lib/screens/settings_screen_sections/offline_areas_section.dart @@ -49,7 +49,7 @@ class _OfflineAreasSectionState extends State { : '--'; String subtitle = '${locService.t('offlineAreas.provider')}: ${area.tileProviderDisplay}\n' + - 'Max zoom: Z${area.maxZoom}' + '\n' + + '${locService.t('offlineAreas.maxZoom')}: Z${area.maxZoom}' + '\n' + '${locService.t('offlineAreas.latitude')}: ${area.bounds.southWest.latitude.toStringAsFixed(3)}, ${area.bounds.southWest.longitude.toStringAsFixed(3)}\n' + '${locService.t('offlineAreas.latitude')}: ${area.bounds.northEast.latitude.toStringAsFixed(3)}, ${area.bounds.northEast.longitude.toStringAsFixed(3)}'; diff --git a/lib/screens/settings_screen_sections/upload_mode_section.dart b/lib/screens/settings_screen_sections/upload_mode_section.dart index c56d676..d5abcc0 100644 --- a/lib/screens/settings_screen_sections/upload_mode_section.dart +++ b/lib/screens/settings_screen_sections/upload_mode_section.dart @@ -53,19 +53,9 @@ class UploadModeSection extends StatelessWidget { style: TextStyle(fontSize: 12, color: Theme.of(context).colorScheme.onSurface.withOpacity(0.7)) ); case UploadMode.sandbox: - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - locService.t('uploadMode.sandboxDescription'), - style: const TextStyle(fontSize: 12, color: Colors.orange), - ), - const SizedBox(height: 2), - Text( - locService.t('uploadMode.sandboxNote'), - style: const TextStyle(fontSize: 11, color: Colors.redAccent), - ), - ], + return Text( + locService.t('uploadMode.sandboxDescription'), + style: const TextStyle(fontSize: 12, color: Colors.orange), ); case UploadMode.simulate: default: diff --git a/lib/widgets/map/layer_selector_button.dart b/lib/widgets/map/layer_selector_button.dart index 439275b..f820289 100644 --- a/lib/widgets/map/layer_selector_button.dart +++ b/lib/widgets/map/layer_selector_button.dart @@ -4,6 +4,7 @@ import 'package:provider/provider.dart'; import '../../app_state.dart'; import '../../models/tile_provider.dart'; import '../../services/offline_area_service.dart'; +import '../../services/localization_service.dart'; class LayerSelectorButton extends StatelessWidget { const LayerSelectorButton({super.key}); @@ -22,9 +23,9 @@ class LayerSelectorButton extends StatelessWidget { final offlineService = OfflineAreaService(); if (offlineService.hasActiveDownloads) { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Cannot change tile types while downloading offline areas'), - duration: Duration(seconds: 3), + SnackBar( + content: Text(LocalizationService.instance.t('layerSelector.cannotChangeTileTypes')), + duration: const Duration(seconds: 3), ), ); return; @@ -58,6 +59,7 @@ class _LayerSelectorDialogState extends State<_LayerSelectorDialog> { Widget build(BuildContext context) { final appState = context.watch(); final providers = appState.tileProviders; + final locService = LocalizationService.instance; // Group tile types by provider for display final providerGroups = >{}; @@ -86,9 +88,9 @@ class _LayerSelectorDialogState extends State<_LayerSelectorDialog> { children: [ const Icon(Icons.layers), const SizedBox(width: 8), - const Text( - 'Select Map Layer', - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18), + Text( + locService.t('layerSelector.selectMapLayer'), + style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 18), ), const Spacer(), IconButton( @@ -104,10 +106,10 @@ class _LayerSelectorDialogState extends State<_LayerSelectorDialog> { padding: EdgeInsets.zero, children: [ if (providerGroups.isEmpty) - const Padding( - padding: EdgeInsets.all(24), + Padding( + padding: const EdgeInsets.all(24), child: Center( - child: Text('No tile providers available'), + child: Text(locService.t('layerSelector.noTileProvidersAvailable')), ), ) else diff --git a/lib/widgets/refine_tags_sheet.dart b/lib/widgets/refine_tags_sheet.dart index 98800dd..befa7c5 100644 --- a/lib/widgets/refine_tags_sheet.dart +++ b/lib/widgets/refine_tags_sheet.dart @@ -3,6 +3,7 @@ import 'package:provider/provider.dart'; import '../app_state.dart'; import '../models/operator_profile.dart'; +import '../services/localization_service.dart'; class RefineTagsSheet extends StatefulWidget { const RefineTagsSheet({ @@ -29,10 +30,11 @@ class _RefineTagsSheetState extends State { Widget build(BuildContext context) { final appState = context.watch(); final operatorProfiles = appState.operatorProfiles; + final locService = LocalizationService.instance; return Scaffold( appBar: AppBar( - title: const Text('Refine Tags'), + title: Text(locService.t('refineTagsSheet.title')), leading: IconButton( icon: const Icon(Icons.close), onPressed: () => Navigator.pop(context, widget.selectedOperatorProfile), @@ -40,34 +42,34 @@ class _RefineTagsSheetState extends State { actions: [ TextButton( onPressed: () => Navigator.pop(context, _selectedOperatorProfile), - child: const Text('Done'), + child: Text(locService.t('refineTagsSheet.done')), ), ], ), body: ListView( padding: const EdgeInsets.all(16), children: [ - const Text( - 'Operator Profile', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + Text( + locService.t('refineTagsSheet.operatorProfile'), + style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold), ), const SizedBox(height: 8), if (operatorProfiles.isEmpty) - const Card( + Card( child: Padding( - padding: EdgeInsets.all(16.0), + padding: const EdgeInsets.all(16.0), child: Column( children: [ - Icon(Icons.info_outline, color: Colors.grey, size: 48), - SizedBox(height: 8), + const Icon(Icons.info_outline, color: Colors.grey, size: 48), + const SizedBox(height: 8), Text( - 'No operator profiles defined', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + locService.t('refineTagsSheet.noOperatorProfiles'), + style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold), ), - SizedBox(height: 4), + const SizedBox(height: 4), Text( - 'Create operator profiles in Settings to apply additional tags to your node submissions.', - style: TextStyle(color: Colors.grey), + locService.t('refineTagsSheet.noOperatorProfilesMessage'), + style: const TextStyle(color: Colors.grey), textAlign: TextAlign.center, ), ], @@ -79,15 +81,15 @@ class _RefineTagsSheetState extends State { child: Column( children: [ RadioListTile( - title: const Text('None'), - subtitle: const Text('No additional operator tags'), + title: Text(locService.t('refineTagsSheet.none')), + subtitle: Text(locService.t('refineTagsSheet.noAdditionalOperatorTags')), value: null, groupValue: _selectedOperatorProfile, onChanged: (value) => setState(() => _selectedOperatorProfile = value), ), ...operatorProfiles.map((profile) => RadioListTile( title: Text(profile.name), - subtitle: Text('${profile.tags.length} additional tags'), + subtitle: Text('${profile.tags.length} ${locService.t('refineTagsSheet.additionalTags')}'), value: profile, groupValue: _selectedOperatorProfile, onChanged: (value) => setState(() => _selectedOperatorProfile = value), @@ -97,9 +99,9 @@ class _RefineTagsSheetState extends State { ), const SizedBox(height: 16), if (_selectedOperatorProfile != null) ...[ - const Text( - 'Additional Tags', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + Text( + locService.t('refineTagsSheet.additionalTagsTitle'), + style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold), ), const SizedBox(height: 8), Card( @@ -114,9 +116,9 @@ class _RefineTagsSheetState extends State { ), const SizedBox(height: 8), if (_selectedOperatorProfile!.tags.isEmpty) - const Text( - 'No tags defined for this operator profile.', - style: TextStyle(color: Colors.grey), + Text( + locService.t('refineTagsSheet.noTagsDefinedForProfile'), + style: const TextStyle(color: Colors.grey), ) else ...(_selectedOperatorProfile!.tags.entries.map((entry) =>