Add Swedish localization for various app actions and inventory management strings

This commit is contained in:
Nils-Johan Gynther
2026-05-02 15:42:00 +02:00
parent 4e81f56225
commit 2563738fcf
24 changed files with 4510 additions and 366 deletions
@@ -5,6 +5,7 @@ import 'package:go_router/go_router.dart';
import '../../../core/api/api_error_mapper.dart';
import '../../../core/api/api_exception.dart';
import '../../../core/auth/jwt_decoder.dart';
import '../../../core/l10n/l10n.dart';
import '../../../core/ui/async_state_views.dart';
import '../../auth/data/auth_providers.dart';
import '../data/recipe_providers.dart';
@@ -38,31 +39,31 @@ class RecipeDetailScreen extends ConsumerWidget {
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () => context.go('/recipes'),
tooltip: 'Tillbaka till receptlistan',
tooltip: context.l10n.recipeDetailBackToList,
),
actions: recipe == null
? []
: [
if (isOwner)
IconButton(
tooltip: recipe.isPublic ? 'Gör privat' : 'Gör publik',
tooltip: recipe.isPublic ? context.l10n.recipeDetailMakePrivate : context.l10n.recipeDetailMakePublic,
icon: Icon(recipe.isPublic ? Icons.public : Icons.lock_outline),
onPressed: () => _toggleVisibility(context, ref, recipe),
),
if (isOwner)
IconButton(
tooltip: 'Dela med användare',
tooltip: context.l10n.recipeDetailShareWithUser,
icon: const Icon(Icons.person_add_alt_1_outlined),
onPressed: () => _shareRecipe(context, ref, recipe),
),
IconButton(
tooltip: 'Redigera',
tooltip: context.l10n.editTooltip,
icon: const Icon(Icons.edit_outlined),
onPressed: () =>
context.push('/recipes/$recipeId/edit'),
),
IconButton(
tooltip: 'Gå till inventarie',
tooltip: context.l10n.recipeDetailGoToInventory,
icon: const Icon(Icons.inventory_2_outlined),
onPressed: () => context.go('/inventory'),
),
@@ -70,7 +71,7 @@ class RecipeDetailScreen extends ConsumerWidget {
],
),
body: recipeAsync.when(
loading: () => const LoadingStateView(label: 'Laddar recept...'),
loading: () => LoadingStateView(label: context.l10n.recipeDetailLoading),
error: (error, _) => ErrorStateView(
message: mapErrorToUserMessage(error, context),
onRetry: () => ref.invalidate(recipeDetailProvider(recipeId)),
@@ -184,8 +185,8 @@ class RecipeDetailScreen extends ConsumerWidget {
SnackBar(
content: Text(
!recipe.isPublic
? 'Receptet är nu publikt.'
: 'Receptet är nu privat.',
? context.l10n.recipeDetailNowPublic
: context.l10n.recipeDetailNowPrivate,
),
),
);
@@ -206,13 +207,13 @@ class RecipeDetailScreen extends ConsumerWidget {
final result = await showDialog<(_ShareAction, String)>(
context: context,
builder: (context) => AlertDialog(
title: const Text('Dela recept'),
title: Text(context.l10n.recipeDetailShareTitle),
content: TextField(
controller: ctrl,
autofocus: true,
decoration: const InputDecoration(
labelText: 'Användarnamn',
hintText: 't.ex. anna',
decoration: InputDecoration(
labelText: context.l10n.recipeDetailUsernameLabel,
hintText: context.l10n.recipeDetailUsernameHint,
),
onSubmitted: (_) => Navigator.pop(
context,
@@ -222,21 +223,21 @@ class RecipeDetailScreen extends ConsumerWidget {
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('Avbryt'),
child: Text(context.l10n.cancelAction),
),
TextButton(
onPressed: () => Navigator.pop(
context,
(_ShareAction.unshare, ctrl.text.trim()),
),
child: const Text('Ta bort delning'),
child: Text(context.l10n.recipeDetailRemoveShare),
),
FilledButton(
onPressed: () => Navigator.pop(
context,
(_ShareAction.share, ctrl.text.trim()),
),
child: const Text('Dela'),
child: Text(context.l10n.recipeDetailShareAction),
),
],
),
@@ -272,8 +273,8 @@ class RecipeDetailScreen extends ConsumerWidget {
SnackBar(
content: Text(
action == _ShareAction.unshare
? 'Delning borttagen för $trimmed.'
: 'Receptet delades med $trimmed.',
? context.l10n.recipeDetailSharingRemoved(trimmed)
: context.l10n.recipeDetailSharedWith(trimmed),
),
),
);
@@ -310,7 +311,7 @@ class _DeleteButton extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
return IconButton(
tooltip: 'Ta bort',
tooltip: context.l10n.deleteTooltip,
icon: const Icon(Icons.delete_outline),
onPressed: () => _confirmDelete(context, ref),
);
@@ -320,19 +321,18 @@ class _DeleteButton extends ConsumerWidget {
final confirmed = await showDialog<bool>(
context: context,
builder: (_) => AlertDialog(
title: const Text('Ta bort recept?'),
content: Text(
'Vill du ta bort "${recipe.title}"? Åtgärden kan inte ångras.'),
title: Text(context.l10n.recipeDetailDeleteTitle),
content: Text(context.l10n.recipeDetailDeleteContent(recipe.title)),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: const Text('Avbryt'),
child: Text(context.l10n.cancelAction),
),
FilledButton(
style: FilledButton.styleFrom(
backgroundColor: Theme.of(context).colorScheme.error),
onPressed: () => Navigator.pop(context, true),
child: const Text('Ta bort'),
child: Text(context.l10n.deleteAction),
),
],
),
@@ -385,14 +385,14 @@ class _RecipeBody extends StatelessWidget {
children: [
const Icon(Icons.people_outline, size: 16),
const SizedBox(width: 4),
Text('${recipe.servings} portioner',
Text('${recipe.servings} ${context.l10n.recipeDetailServings}',
style: theme.textTheme.bodySmall),
],
),
],
if (recipe.ingredients.isNotEmpty) ...[
const SizedBox(height: 24),
Text('Ingredienser', style: theme.textTheme.titleMedium),
Text(context.l10n.recipeDetailIngredients, style: theme.textTheme.titleMedium),
const SizedBox(height: 12),
...recipe.ingredients.map((ing) {
final qtyStr = ing.quantity == 0 ? '' : _fmtQty(ing.quantity);
@@ -443,7 +443,7 @@ class _RecipeBody extends StatelessWidget {
if (recipe.instructions != null &&
recipe.instructions!.isNotEmpty) ...[
const SizedBox(height: 32),
Text('Tillvägagångssätt', style: theme.textTheme.titleMedium),
Text(context.l10n.recipeDetailInstructions, style: theme.textTheme.titleMedium),
const SizedBox(height: 16),
..._buildSteps(recipe.instructions!, theme),
],