feat: Flutter client localisation (12 languages)
Add flutter_localizations + intl, 12 ARB files (en/ru/es/de/fr/it/pt/zh/ja/ko/ar/hi), replace all hardcoded Russian UI strings with AppLocalizations, detect system locale on first launch, localise bottom nav bar labels, document rule in CLAUDE.md. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,21 +1,23 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:food_ai/l10n/app_localizations.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../home/home_provider.dart';
|
||||
import '../scan/dish_result_screen.dart';
|
||||
import 'recognition_service.dart';
|
||||
|
||||
/// Full-screen page showing all of today's unlinked dish recognition jobs.
|
||||
/// Full-screen page showing all dish recognition jobs.
|
||||
class RecognitionHistoryScreen extends ConsumerWidget {
|
||||
const RecognitionHistoryScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final jobsState = ref.watch(todayJobsProvider);
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final jobsState = ref.watch(allJobsProvider);
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('История распознавания'),
|
||||
title: Text(l10n.historyTitle),
|
||||
),
|
||||
body: jobsState.when(
|
||||
loading: () => const Center(child: CircularProgressIndicator()),
|
||||
@@ -23,20 +25,18 @@ class RecognitionHistoryScreen extends ConsumerWidget {
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text('Не удалось загрузить историю'),
|
||||
Text(l10n.historyLoadError),
|
||||
const SizedBox(height: 12),
|
||||
FilledButton(
|
||||
onPressed: () => ref.invalidate(todayJobsProvider),
|
||||
child: const Text('Повторить'),
|
||||
onPressed: () => ref.invalidate(allJobsProvider),
|
||||
child: Text(l10n.retry),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
data: (jobs) {
|
||||
if (jobs.isEmpty) {
|
||||
return const Center(
|
||||
child: Text('Нет распознаваний за сегодня'),
|
||||
);
|
||||
return Center(child: Text(l10n.noHistory));
|
||||
}
|
||||
return ListView.separated(
|
||||
padding: const EdgeInsets.all(16),
|
||||
@@ -58,6 +58,7 @@ class _HistoryJobTile extends ConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final theme = Theme.of(context);
|
||||
|
||||
final isDone = job.status == 'done';
|
||||
@@ -84,11 +85,11 @@ class _HistoryJobTile extends ConsumerWidget {
|
||||
|
||||
final String titleText;
|
||||
if (isDone) {
|
||||
titleText = dishName ?? 'Блюдо распознано';
|
||||
titleText = dishName ?? l10n.dishRecognized;
|
||||
} else if (isProcessing) {
|
||||
titleText = 'Распознаётся…';
|
||||
titleText = l10n.recognizing;
|
||||
} else {
|
||||
titleText = 'Ошибка распознавания';
|
||||
titleText = l10n.recognitionError;
|
||||
}
|
||||
|
||||
final contextParts = [
|
||||
@@ -118,6 +119,8 @@ class _HistoryJobTile extends ConsumerWidget {
|
||||
dish: job.result!,
|
||||
preselectedMealType: job.targetMealType,
|
||||
jobId: job.id,
|
||||
targetDate: job.targetDate,
|
||||
createdAt: job.createdAt,
|
||||
onAdded: () => Navigator.pop(sheetContext),
|
||||
),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user