feat(localization): Implement Swedish localization and error messages
- Added localization support for Swedish and English languages. - Integrated localized strings for user messages in the API error mapper. - Updated UI components to use localized strings for labels and messages. - Ensured all error messages are context-aware and utilize the localization framework. - Created regression test to prevent common ASCII fallbacks in Swedish UI text.
This commit is contained in:
@@ -33,7 +33,7 @@ class _PantryScreenState extends ConsumerState<PantryScreen> {
|
||||
return StatefulBuilder(
|
||||
builder: (ctx, setDialogState) {
|
||||
return AlertDialog(
|
||||
title: Text('Lagg "${item.displayName}" i inventarie'),
|
||||
title: Text('Lägg "${item.displayName}" i inventarie'),
|
||||
content: SizedBox(
|
||||
width: 380,
|
||||
child: Column(
|
||||
@@ -44,7 +44,7 @@ class _PantryScreenState extends ConsumerState<PantryScreen> {
|
||||
keyboardType:
|
||||
const TextInputType.numberWithOptions(decimal: true),
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Mangd',
|
||||
labelText: 'Mängd',
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
),
|
||||
@@ -116,7 +116,7 @@ class _PantryScreenState extends ConsumerState<PantryScreen> {
|
||||
double.tryParse(quantityController.text.trim().replaceAll(',', '.'));
|
||||
if (quantity == null || quantity <= 0) {
|
||||
setDialogState(() {
|
||||
formError = 'Ange en giltig mangd over 0.';
|
||||
formError = 'Ange en giltig mängd över 0.';
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -126,7 +126,7 @@ class _PantryScreenState extends ConsumerState<PantryScreen> {
|
||||
'location': selectedLocation,
|
||||
});
|
||||
},
|
||||
child: const Text('Lagg till'),
|
||||
child: const Text('Lägg till'),
|
||||
),
|
||||
],
|
||||
);
|
||||
@@ -158,7 +158,7 @@ class _PantryScreenState extends ConsumerState<PantryScreen> {
|
||||
} catch (error) {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(mapErrorToUserMessage(error))),
|
||||
SnackBar(content: Text(mapErrorToUserMessage(error, context))),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -178,7 +178,7 @@ class _PantryScreenState extends ConsumerState<PantryScreen> {
|
||||
} catch (error) {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(mapErrorToUserMessage(error))),
|
||||
SnackBar(content: Text(mapErrorToUserMessage(error, context))),
|
||||
);
|
||||
} finally {
|
||||
if (mounted) setState(() => _isSubmitting = false);
|
||||
@@ -215,7 +215,7 @@ class _PantryScreenState extends ConsumerState<PantryScreen> {
|
||||
} catch (error) {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(mapErrorToUserMessage(error))),
|
||||
SnackBar(content: Text(mapErrorToUserMessage(error, context))),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -230,7 +230,7 @@ class _PantryScreenState extends ConsumerState<PantryScreen> {
|
||||
return item.category!;
|
||||
}
|
||||
|
||||
return 'Ovrigt';
|
||||
return 'Övrigt';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -245,7 +245,7 @@ class _PantryScreenState extends ConsumerState<PantryScreen> {
|
||||
if (pantryAsync.hasError || productsAsync.hasError) {
|
||||
final error = pantryAsync.error ?? productsAsync.error;
|
||||
return ErrorStateView(
|
||||
message: mapErrorToUserMessage(error ?? 'Okant fel'),
|
||||
message: mapErrorToUserMessage(error ?? 'Okänt fel', context),
|
||||
onRetry: () {
|
||||
ref.invalidate(pantryProvider);
|
||||
ref.invalidate(pantryProductsProvider);
|
||||
@@ -272,8 +272,8 @@ class _PantryScreenState extends ConsumerState<PantryScreen> {
|
||||
}
|
||||
final categories = grouped.keys.toList()
|
||||
..sort((a, b) {
|
||||
if (a == 'Ovrigt') return 1;
|
||||
if (b == 'Ovrigt') return -1;
|
||||
if (a == 'Övrigt') return 1;
|
||||
if (b == 'Övrigt') return -1;
|
||||
return a.toLowerCase().compareTo(b.toLowerCase());
|
||||
});
|
||||
|
||||
@@ -281,7 +281,7 @@ class _PantryScreenState extends ConsumerState<PantryScreen> {
|
||||
padding: const EdgeInsets.all(16),
|
||||
children: [
|
||||
Text(
|
||||
'Produkter du alltid raknar med att ha hemma.',
|
||||
'Produkter du alltid räknar med att ha hemma.',
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
@@ -324,7 +324,7 @@ class _PantryScreenState extends ConsumerState<PantryScreen> {
|
||||
width: 18,
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
)
|
||||
: const Text('Lagg till'),
|
||||
: const Text('Lägg till'),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -336,8 +336,8 @@ class _PantryScreenState extends ConsumerState<PantryScreen> {
|
||||
const SizedBox(height: 12),
|
||||
if (pantryItems.isEmpty)
|
||||
const EmptyStateView(
|
||||
title: 'Baslagret ar tomt',
|
||||
description: 'Lagg till produkter ovan.',
|
||||
title: 'Baslagret är tomt',
|
||||
description: 'Lägg till produkter ovan.',
|
||||
)
|
||||
else
|
||||
...categories.map((category) {
|
||||
@@ -364,21 +364,21 @@ class _PantryScreenState extends ConsumerState<PantryScreen> {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Tooltip(
|
||||
message: 'Konsumera (inte tillgangligt i baslager)',
|
||||
message: 'Konsumera (inte tillgängligt i baslager)',
|
||||
child: IconButton(
|
||||
onPressed: null,
|
||||
icon: Icon(Icons.remove_circle_outline),
|
||||
),
|
||||
),
|
||||
const Tooltip(
|
||||
message: 'Redigera (inte tillgangligt i baslager)',
|
||||
message: 'Redigera (inte tillgängligt i baslager)',
|
||||
child: IconButton(
|
||||
onPressed: null,
|
||||
icon: Icon(Icons.edit_outlined),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
tooltip: 'Lagg i inventarie',
|
||||
tooltip: 'Lägg i inventarie',
|
||||
icon: const Icon(Icons.inventory_2_outlined),
|
||||
onPressed: () => _addToInventory(item),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user