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:
@@ -92,7 +92,7 @@ class _CreateRecipeScreenState extends ConsumerState<CreateRecipeScreen> {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
_parseError = mapErrorToUserMessage(e);
|
||||
_parseError = mapErrorToUserMessage(e, context);
|
||||
_isParsing = false;
|
||||
});
|
||||
}
|
||||
@@ -146,7 +146,7 @@ class _CreateRecipeScreenState extends ConsumerState<CreateRecipeScreen> {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
_saveError = mapErrorToUserMessage(e);
|
||||
_saveError = mapErrorToUserMessage(e, context);
|
||||
_isSaving = false;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ class RecipeDetailScreen extends ConsumerWidget {
|
||||
body: recipeAsync.when(
|
||||
loading: () => const LoadingStateView(label: 'Laddar recept...'),
|
||||
error: (error, _) => ErrorStateView(
|
||||
message: mapErrorToUserMessage(error),
|
||||
message: mapErrorToUserMessage(error, context),
|
||||
onRetry: () => ref.invalidate(recipeDetailProvider(recipeId)),
|
||||
),
|
||||
data: (recipe) => _RecipeBody(recipe: recipe),
|
||||
@@ -92,7 +92,7 @@ class _DeleteButton extends ConsumerWidget {
|
||||
} on ApiException catch (e) {
|
||||
if (!context.mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(mapErrorToUserMessage(e))),
|
||||
SnackBar(content: Text(mapErrorToUserMessage(e, context))),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,20 +152,20 @@ class _RecipeEditScreenState extends ConsumerState<RecipeEditScreen> {
|
||||
|
||||
String? _validateIngredients() {
|
||||
if (_ingredients.isEmpty) {
|
||||
return 'Minst en ingrediens kravs.';
|
||||
return 'Minst en ingrediens krävs.';
|
||||
}
|
||||
for (final ingredient in _ingredients) {
|
||||
if (ingredient.productId == null) {
|
||||
return 'Valj produkt for alla ingredienser.';
|
||||
return 'Välj produkt för alla ingredienser.';
|
||||
}
|
||||
final quantity = double.tryParse(
|
||||
ingredient.quantityCtrl.text.trim().replaceAll(',', '.'),
|
||||
);
|
||||
if (quantity == null || quantity < 0) {
|
||||
return 'Ange giltig mangd for alla ingredienser.';
|
||||
return 'Ange giltig mängd för alla ingredienser.';
|
||||
}
|
||||
if (ingredient.unit.trim().isEmpty) {
|
||||
return 'Valj enhet for alla ingredienser.';
|
||||
return 'Välj enhet för alla ingredienser.';
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -225,7 +225,7 @@ class _RecipeEditScreenState extends ConsumerState<RecipeEditScreen> {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
_saveError = mapErrorToUserMessage(e);
|
||||
_saveError = mapErrorToUserMessage(e, context);
|
||||
_isSaving = false;
|
||||
});
|
||||
}
|
||||
@@ -255,7 +255,7 @@ class _RecipeEditScreenState extends ConsumerState<RecipeEditScreen> {
|
||||
body: recipeAsync.when(
|
||||
loading: () => const LoadingStateView(label: 'Laddar recept...'),
|
||||
error: (error, _) => ErrorStateView(
|
||||
message: mapErrorToUserMessage(error),
|
||||
message: mapErrorToUserMessage(error, context),
|
||||
onRetry: () => ref.invalidate(recipeDetailProvider(widget.recipeId)),
|
||||
),
|
||||
data: (recipe) {
|
||||
@@ -321,13 +321,13 @@ class _RecipeEditScreenState extends ConsumerState<RecipeEditScreen> {
|
||||
OutlinedButton.icon(
|
||||
onPressed: _isSaving ? null : _addIngredient,
|
||||
icon: const Icon(Icons.add),
|
||||
label: const Text('Lagg till'),
|
||||
label: const Text('Lägg till'),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'Valj produkt, mangd och enhet for varje ingrediens.',
|
||||
'Välj produkt, mängd och enhet för varje ingrediens.',
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant),
|
||||
),
|
||||
@@ -341,7 +341,7 @@ class _RecipeEditScreenState extends ConsumerState<RecipeEditScreen> {
|
||||
const Card(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(16),
|
||||
child: Text('Inga ingredienser tillagda an.'),
|
||||
child: Text('Inga ingredienser tillagda än.'),
|
||||
),
|
||||
),
|
||||
...List.generate(
|
||||
@@ -441,14 +441,14 @@ class _RecipeEditScreenState extends ConsumerState<RecipeEditScreen> {
|
||||
child: TextFormField(
|
||||
controller: ingredient.quantityCtrl,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Mangd *',
|
||||
labelText: 'Mängd *',
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
keyboardType:
|
||||
const TextInputType.numberWithOptions(decimal: true),
|
||||
validator: (value) {
|
||||
if (value == null || value.trim().isEmpty) {
|
||||
return 'Ange mangd';
|
||||
return 'Ange mängd';
|
||||
}
|
||||
if (double.tryParse(value.trim().replaceAll(',', '.')) ==
|
||||
null) {
|
||||
|
||||
@@ -16,7 +16,7 @@ class RecipesScreen extends ConsumerWidget {
|
||||
body: recipesAsync.when(
|
||||
loading: () => const LoadingStateView(label: 'Laddar recept...'),
|
||||
error: (error, _) => ErrorStateView(
|
||||
message: mapErrorToUserMessage(error),
|
||||
message: mapErrorToUserMessage(error, context),
|
||||
onRetry: () => ref.invalidate(recipesProvider),
|
||||
),
|
||||
data: (recipes) {
|
||||
|
||||
Reference in New Issue
Block a user