Finish localizations, remove now-inaccurate sandbox note

This commit is contained in:
stopflock
2025-09-29 11:42:48 -05:00
parent 5c80fdc169
commit 4a7a99502c
8 changed files with 112 additions and 50 deletions
+18 -1
View File
@@ -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"
}
}
+18 -1
View File
@@ -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"
}
}
+18 -1
View File
@@ -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"
}
}
+18 -1
View File
@@ -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"
}
}
@@ -49,7 +49,7 @@ class _OfflineAreasSectionState extends State<OfflineAreasSection> {
: '--';
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)}';
@@ -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:
+11 -9
View File
@@ -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<AppState>();
final providers = appState.tileProviders;
final locService = LocalizationService.instance;
// Group tile types by provider for display
final providerGroups = <TileProvider, List<TileType>>{};
@@ -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
+25 -23
View File
@@ -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<RefineTagsSheet> {
Widget build(BuildContext context) {
final appState = context.watch<AppState>();
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<RefineTagsSheet> {
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<RefineTagsSheet> {
child: Column(
children: [
RadioListTile<OperatorProfile?>(
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<OperatorProfile?>(
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<RefineTagsSheet> {
),
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<RefineTagsSheet> {
),
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) =>