@tduncan / Cortana / commits / be7c3ad

feat: implement onboarding language selection screen and update localization files

abdulmominsakib committed May 20, 2026 at 13:55 UTC be7c3ad25c291f04983d09798493f5b3eb486925
25 files changed +529 -6
assets/images/flag_bd.png
Binary files /dev/null and b/assets/images/flag_bd.png differ
assets/images/flag_cn.png
Binary files /dev/null and b/assets/images/flag_cn.png differ
assets/images/flag_es.png
Binary files /dev/null and b/assets/images/flag_es.png differ
assets/images/flag_in.png
Binary files /dev/null and b/assets/images/flag_in.png differ
assets/images/flag_sa.png
Binary files /dev/null and b/assets/images/flag_sa.png differ
assets/images/flag_us.png
Binary files /dev/null and b/assets/images/flag_us.png differ
lib/app.dart
+6
@@ -12,6 +12,7 @@ import 'core/theme/app_theme.dart';
12 import 'features/chat/views/chat_screen.dart';
13 import 'features/conversations/views/chat_history_screen.dart';
14 import 'features/on_device/views/model_manager_screen.dart';
15 +import 'features/onboarding/screens/onboarding_language_screen.dart';
16 import 'features/onboarding/screens/onboarding_model_download_screen.dart';
17 import 'features/onboarding/screens/onboarding_notification_permission_screen.dart';
18 import 'features/onboarding/screens/onboarding_server_setup_screen.dart';
@@ -55,6 +56,11 @@ final routerProvider = Provider<GoRouter>((ref) {
56 routes: [
57 GoRoute(
58 path: AppRoutes.onboarding,
59 + pageBuilder: (context, state) =>
60 + const NoTransitionPage(child: OnboardingLanguageScreen()),
61 + ),
62 + GoRoute(
63 + path: AppRoutes.onboardingServerType,
64 pageBuilder: (context, state) =>
65 const NoTransitionPage(child: OnboardingServerTypeScreen()),
66 ),
lib/core/routes/app_routes.dart
+1
@@ -1,6 +1,7 @@
1 class AppRoutes {
2 static const String home = '/';
3 static const String onboarding = '/onboarding';
4 + static const String onboardingServerType = '/onboarding/server-type';
5 static const String onboardingSetup = '/onboarding/setup';
6 static const String onboardingModelDownload = '/onboarding/model-download';
7 static const String onboardingTheme = '/onboarding/theme';
lib/features/onboarding/screens/onboarding_language_screen.dart new
+397
@@ -0,0 +1,397 @@
1 +import 'package:flutter/material.dart';
2 +import 'package:flutter_riverpod/flutter_riverpod.dart';
3 +import 'package:go_router/go_router.dart';
4 +import 'package:hugeicons/hugeicons.dart';
5 +import 'package:shadcn_ui/shadcn_ui.dart';
6 +
7 +import '../../../core/providers/app_providers.dart';
8 +import '../../../core/routes/app_routes.dart';
9 +import '../../../l10n/app_localizations.dart';
10 +
11 +class _LanguageOption {
12 + final String code;
13 + final String nativeName;
14 + final String englishName;
15 + final String flag;
16 + final String flagAsset;
17 + final String countryCode;
18 + final String shortText;
19 + final List<Color> gradient;
20 +
21 + const _LanguageOption({
22 + required this.code,
23 + required this.nativeName,
24 + required this.englishName,
25 + required this.flag,
26 + required this.flagAsset,
27 + required this.countryCode,
28 + required this.shortText,
29 + required this.gradient,
30 + });
31 +}
32 +
33 +const _languages = [
34 + _LanguageOption(
35 + code: 'en',
36 + nativeName: 'English',
37 + englishName: 'English',
38 + flag: '🇺🇸',
39 + flagAsset: 'assets/images/flag_us.png',
40 + countryCode: 'US',
41 + shortText: 'En',
42 + gradient: [Color(0xFF6366F1), Color(0xFF4F46E5)],
43 + ),
44 + _LanguageOption(
45 + code: 'es',
46 + nativeName: 'Español',
47 + englishName: 'Spanish',
48 + flag: '🇪🇸',
49 + flagAsset: 'assets/images/flag_es.png',
50 + countryCode: 'ES',
51 + shortText: 'Es',
52 + gradient: [Color(0xFFF59E0B), Color(0xFFD97706)],
53 + ),
54 + _LanguageOption(
55 + code: 'zh',
56 + nativeName: '中文',
57 + englishName: 'Chinese',
58 + flag: '🇨🇳',
59 + flagAsset: 'assets/images/flag_cn.png',
60 + countryCode: 'CN',
61 + shortText: 'Zh',
62 + gradient: [Color(0xFFEF4444), Color(0xFFDC2626)],
63 + ),
64 + _LanguageOption(
65 + code: 'ar',
66 + nativeName: 'العربية',
67 + englishName: 'Arabic',
68 + flag: '🇸🇦',
69 + flagAsset: 'assets/images/flag_sa.png',
70 + countryCode: 'SA',
71 + shortText: 'Ar',
72 + gradient: [Color(0xFF10B981), Color(0xFF059669)],
73 + ),
74 + _LanguageOption(
75 + code: 'hi',
76 + nativeName: 'हिन्दी',
77 + englishName: 'Hindi',
78 + flag: '🇮🇳',
79 + flagAsset: 'assets/images/flag_in.png',
80 + countryCode: 'IN',
81 + shortText: 'Hi',
82 + gradient: [Color(0xFFEC4899), Color(0xFFDB2777)],
83 + ),
84 + _LanguageOption(
85 + code: 'bn',
86 + nativeName: 'বাংলা',
87 + englishName: 'Bengali',
88 + flag: '🇧🇩',
89 + flagAsset: 'assets/images/flag_bd.png',
90 + countryCode: 'BD',
91 + shortText: 'Bn',
92 + gradient: [Color(0xFF06B6D4), Color(0xFF0891B2)],
93 + ),
94 +];
95 +
96 +class OnboardingLanguageScreen extends ConsumerStatefulWidget {
97 + const OnboardingLanguageScreen({super.key});
98 +
99 + @override
100 + ConsumerState<OnboardingLanguageScreen> createState() =>
101 + _OnboardingLanguageScreenState();
102 +}
103 +
104 +class _OnboardingLanguageScreenState
105 + extends ConsumerState<OnboardingLanguageScreen> {
106 + String? _selectedCode;
107 +
108 + @override
109 + void initState() {
110 + super.initState();
111 + // Read the current settings locale code
112 + WidgetsBinding.instance.addPostFrameCallback((_) {
113 + final settings = ref.read(settingsProvider);
114 + setState(() {
115 + _selectedCode = settings.localeCode ?? 'en';
116 + });
117 + });
118 + }
119 +
120 + @override
121 + Widget build(BuildContext context) {
122 + final l10n = AppLocalizations.of(context)!;
123 + final theme = Theme.of(context);
124 + final screenWidth = MediaQuery.of(context).size.width;
125 + final crossAxisCount = screenWidth > 600 ? 3 : 2;
126 +
127 + return Scaffold(
128 + appBar: AppBar(
129 + title: Row(
130 + children: [
131 + Padding(
132 + padding: const EdgeInsets.all(8),
133 + child: Image.asset(
134 + 'assets/images/logo.webp',
135 + width: 24,
136 + height: 24,
137 + ),
138 + ),
139 + Text(
140 + l10n.onboarding_localmind,
141 + style: const TextStyle(letterSpacing: 2, fontSize: 14),
142 + ),
143 + ],
144 + ),
145 + centerTitle: false,
146 + actions: [
147 + TextButton.icon(
148 + onPressed: () => _skipOnboarding(),
149 + label: Text(l10n.skip),
150 + icon: HugeIcon(
151 + icon: HugeIcons.strokeRoundedNext,
152 + color: theme.colorScheme.primary,
153 + size: 20,
154 + ),
155 + ),
156 + ],
157 + ),
158 + body: Column(
159 + crossAxisAlignment: CrossAxisAlignment.stretch,
160 + children: [
161 + Expanded(
162 + child: SingleChildScrollView(
163 + padding: const EdgeInsets.symmetric(horizontal: 24.0),
164 + child: Column(
165 + crossAxisAlignment: CrossAxisAlignment.stretch,
166 + children: [
167 + const SizedBox(height: 24),
168 + Text(
169 + l10n.onboarding_welcome,
170 + textAlign: TextAlign.center,
171 + style: theme.textTheme.headlineLarge?.copyWith(
172 + fontWeight: FontWeight.w800,
173 + height: 1.1,
174 + ),
175 + ),
176 + const SizedBox(height: 12),
177 + Text(
178 + l10n.onboarding_choose_language,
179 + textAlign: TextAlign.center,
180 + style: theme.textTheme.titleMedium?.copyWith(
181 + fontWeight: FontWeight.w600,
182 + color: theme.colorScheme.primary,
183 + ),
184 + ),
185 + const SizedBox(height: 8),
186 + Text(
187 + l10n.onboarding_choose_language_desc,
188 + textAlign: TextAlign.center,
189 + style: theme.textTheme.bodySmall?.copyWith(
190 + color: theme.colorScheme.onSurface.withValues(alpha: 0.7),
191 + height: 1.5,
192 + ),
193 + ),
194 + const SizedBox(height: 32),
195 + GridView.builder(
196 + shrinkWrap: true,
197 + physics: const NeverScrollableScrollPhysics(),
198 + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
199 + crossAxisCount: crossAxisCount,
200 + crossAxisSpacing: 16,
201 + mainAxisSpacing: 16,
202 + childAspectRatio: 1.05,
203 + ),
204 + itemCount: _languages.length,
205 + itemBuilder: (context, index) {
206 + final lang = _languages[index];
207 + final isSelected = _selectedCode == lang.code;
208 +
209 + return GestureDetector(
210 + onTap: () {
211 + setState(() {
212 + _selectedCode = lang.code;
213 + });
214 + // Dynamically apply settings localization update
215 + ref
216 + .read(settingsProvider.notifier)
217 + .setLocaleCode(lang.code);
218 + },
219 + child: AnimatedContainer(
220 + duration: const Duration(milliseconds: 200),
221 + padding: const EdgeInsets.all(16),
222 + decoration: BoxDecoration(
223 + color: theme.colorScheme.surface,
224 + borderRadius: BorderRadius.circular(16),
225 + border: Border.all(
226 + color: isSelected
227 + ? theme.colorScheme.primary
228 + : theme.colorScheme.outline
229 + .withValues(alpha: 0.3),
230 + width: isSelected ? 2 : 1,
231 + ),
232 + boxShadow: isSelected
233 + ? [
234 + BoxShadow(
235 + color: theme.colorScheme.primary
236 + .withValues(alpha: 0.15),
237 + blurRadius: 10,
238 + offset: const Offset(0, 4),
239 + )
240 + ]
241 + : null,
242 + ),
243 + child: Column(
244 + crossAxisAlignment: CrossAxisAlignment.start,
245 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
246 + children: [
247 + Row(
248 + mainAxisAlignment:
249 + MainAxisAlignment.spaceBetween,
250 + children: [
251 + Container(
252 + width: 52,
253 + height: 36,
254 + decoration: BoxDecoration(
255 + color: Colors.white,
256 + borderRadius: BorderRadius.circular(6),
257 + border: Border.all(
258 + color: theme.colorScheme.outline
259 + .withValues(alpha: 0.15),
260 + width: 1,
261 + ),
262 + boxShadow: [
263 + BoxShadow(
264 + color: Colors.black.withValues(alpha: 0.05),
265 + blurRadius: 4,
266 + offset: const Offset(0, 2),
267 + ),
268 + ],
269 + ),
270 + alignment: Alignment.center,
271 + child: ClipRRect(
272 + borderRadius: BorderRadius.circular(5),
273 + child: Image.asset(
274 + lang.flagAsset,
275 + width: 52,
276 + height: 36,
277 + fit: BoxFit.cover,
278 + errorBuilder: (context, error, stackTrace) {
279 + return Text(
280 + lang.flag,
281 + style: const TextStyle(fontSize: 18),
282 + );
283 + },
284 + ),
285 + ),
286 + ),
287 + if (isSelected)
288 + Icon(
289 + Icons.check_circle_rounded,
290 + color: theme.colorScheme.primary,
291 + size: 20,
292 + ),
293 + ],
294 + ),
295 + const SizedBox(height: 12),
296 + Column(
297 + crossAxisAlignment: CrossAxisAlignment.start,
298 + children: [
299 + Text(
300 + lang.nativeName,
301 + style:
302 + theme.textTheme.titleMedium?.copyWith(
303 + fontWeight: FontWeight.bold,
304 + ),
305 + maxLines: 1,
306 + overflow: TextOverflow.ellipsis,
307 + ),
308 + const SizedBox(height: 2),
309 + Text(
310 + '${lang.englishName} • ${lang.shortText.toUpperCase()}',
311 + style: theme.textTheme.labelSmall?.copyWith(
312 + color: theme.colorScheme.onSurface
313 + .withValues(alpha: 0.5),
314 + ),
315 + maxLines: 1,
316 + overflow: TextOverflow.ellipsis,
317 + ),
318 + ],
319 + ),
320 + ],
321 + ),
322 + ),
323 + );
324 + },
325 + ),
326 + const SizedBox(height: 32),
327 + ],
328 + ),
329 + ),
330 + ),
331 + Padding(
332 + padding: const EdgeInsets.symmetric(horizontal: 24.0),
333 + child: Column(
334 + children: [
335 + Row(
336 + mainAxisAlignment: MainAxisAlignment.center,
337 + children: [
338 + Container(
339 + width: 8,
340 + height: 8,
341 + decoration: BoxDecoration(
342 + color: theme.colorScheme.primary,
343 + shape: BoxShape.circle,
344 + ),
345 + ),
346 + const SizedBox(width: 8),
347 + Text(
348 + l10n.ready_continue,
349 + style: theme.textTheme.labelSmall?.copyWith(
350 + color: theme.colorScheme.onSurface.withValues(
351 + alpha: 0.5,
352 + ),
353 + letterSpacing: 2,
354 + fontWeight: FontWeight.w600,
355 + ),
356 + ),
357 + ],
358 + ),
359 + const SizedBox(height: 16),
360 + ShadButton(
361 + width: double.infinity,
362 + onPressed: () {
363 + context.push(AppRoutes.onboardingServerType);
364 + },
365 + child: Text(
366 + l10n.continue_action,
367 + style: const TextStyle(
368 + fontSize: 16,
369 + fontWeight: FontWeight.w600,
370 + ),
371 + ),
372 + ),
373 + SizedBox(
374 + height: MediaQuery.of(context).padding.bottom,
375 + ),
376 + ],
377 + ),
378 + ),
379 + ],
380 + ),
381 + );
382 + }
383 +
384 + Future<void> _completeOnboarding() async {
385 + final settings = ref.read(settingsProvider);
386 + await ref
387 + .read(settingsProvider.notifier)
388 + .updateSettings(settings.copyWith(hasCompletedOnboarding: true));
389 + if (mounted) {
390 + context.go(AppRoutes.home);
391 + }
392 + }
393 +
394 + void _skipOnboarding() {
395 + _completeOnboarding();
396 + }
397 +}
lib/features/onboarding/screens/onboarding_server_setup_screen.dart
+9 -4
@@ -156,7 +156,9 @@ class _OnboardingServerSetupScreenState
156 if (mounted) {
157 ScaffoldMessenger.of(context).showSnackBar(
158 SnackBar(
159 - content: Text(AppLocalizations.of(context)!.error_with_message(e.toString())),
159 + content: Text(
160 + AppLocalizations.of(context)!.error_with_message(e.toString()),
161 + ),
162 backgroundColor: Colors.red,
163 ),
164 );
@@ -202,8 +204,9 @@ class _OnboardingServerSetupScreenState
204 filled: true,
205 fillColor: theme.colorScheme.surface,
206 ),
205 - validator: (val) =>
206 - val == null || val.trim().isEmpty ? l10n.name_required : null,
207 + validator: (val) => val == null || val.trim().isEmpty
208 + ? l10n.name_required
209 + : null,
210 ),
211 const SizedBox(height: 16),
212
@@ -246,7 +249,9 @@ class _OnboardingServerSetupScreenState
249 TextFormField(
250 controller: _apiKeyController,
251 decoration: InputDecoration(
249 - labelText: isCloud ? l10n.api_key_required : l10n.api_key_optional,
252 + labelText: isCloud
253 + ? l10n.api_key_required
254 + : l10n.api_key_optional,
255 filled: true,
256 fillColor: theme.colorScheme.surface,
257 ),
lib/features/onboarding/screens/onboarding_server_type_screen.dart
+5 -1
@@ -34,6 +34,7 @@ class _OnboardingServerTypeScreenState
34
35 return Scaffold(
36 appBar: AppBar(
37 + automaticallyImplyLeading: false,
38 title: Row(
39 children: [
40 Padding(
@@ -196,7 +197,10 @@ class _OnboardingServerTypeScreenState
197 },
198 child: Text(
199 l10n.continue_action,
199 - style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
200 + style: const TextStyle(
201 + fontSize: 16,
202 + fontWeight: FontWeight.w600,
203 + ),
204 ),
205 ),
206 SizedBox(
lib/l10n/app_ar.arb
+6
@@ -473,12 +473,18 @@
473
474 "older_section": "الأقدم",
475
476 + "onboarding_choose_language": "اختر اللغة",
477 +
478 + "onboarding_choose_language_desc": "اختر لغتك المفضلة. يمكنك تغيير هذا في أي وقت من الإعدادات.",
479 +
480 "onboarding_localmind": "LOCALMIND",
481
482 "onboarding_connect_server": "اتصل\nبخادمك",
483
484 "onboarding_connect_desc": "اتصل بـ LM Studio أو Ollama أو\nOpenRouter لبدء تجربة الذكاء\nالاصطناعي الخاصة بك.",
485
486 + "onboarding_welcome": "مرحباً بك في LocalMind",
487 +
488 "server_type_on_device": "محلي",
489
490 "server_type_on_device_sub": "لا يحتاج خادماً",
lib/l10n/app_bn.arb
+3
@@ -243,9 +243,12 @@
243 "older_section": "পূর্বের",
244 "on_device_android_only": "অন-ডিভাইস ইনফারেন্স বর্তমানে শুধুমাত্র অ্যান্ড্রয়েডেই উপলব্ধ।",
245 "on_device_models_title": "অন-ডিভাইস মডেলসমূহ",
246 + "onboarding_choose_language": "ভাষা নির্বাচন করুন",
247 + "onboarding_choose_language_desc": "আপনার পছন্দের ভাষা নির্বাচন করুন। আপনি সেটিংস থেকে যেকোনো সময় এটি পরিবর্তন করতে পারবেন।",
248 "onboarding_connect_desc": "আপনার নিজস্ব ব্যক্তিগত এআই অভিজ্ঞতা শুরু করতে\nLM Studio, Ollama, অথবা OpenRouter-এর সাথে\nসংযোগ করুন।",
249 "onboarding_connect_server": "আপনার সার্ভার\nসংযোগ করুন",
250 "onboarding_localmind": "LOCALMIND",
251 + "onboarding_welcome": "LocalMind-এ স্বাগতম",
252 "online": "অনলাইন",
253 "open_source": "ওপেন সোর্স",
254 "open_source_desc": "LocalMind একটি ওপেন সোর্স প্রকল্প। গিটহাবে (GitHub) আমাদের অগ্রগতি অনুসরণ করুন বা অবদান রাখুন।",
lib/l10n/app_en.arb
+15
@@ -1309,6 +1309,16 @@
1309 "description": "Older conversations section header"
1310 },
1311
1312 + "onboarding_choose_language": "Choose Language",
1313 + "@onboarding_choose_language": {
1314 + "description": "Onboarding title to select application language"
1315 + },
1316 +
1317 + "onboarding_choose_language_desc": "Select your preferred language. You can change this anytime in settings.",
1318 + "@onboarding_choose_language_desc": {
1319 + "description": "Onboarding description for language selection"
1320 + },
1321 +
1322 "onboarding_localmind": "LOCALMIND",
1323 "@onboarding_localmind": {
1324 "description": "Onboarding screen branding text"
@@ -1324,6 +1334,11 @@
1334 "description": "Onboarding server connection description"
1335 },
1336
1337 + "onboarding_welcome": "Welcome to LocalMind",
1338 + "@onboarding_welcome": {
1339 + "description": "Onboarding welcome message"
1340 + },
1341 +
1342 "server_type_on_device": "On-Device",
1343 "@server_type_on_device": {
1344 "description": "On-device server type card title"
lib/l10n/app_es.arb
+3
@@ -243,9 +243,12 @@
243 "older_section": "MÁS ANTIGUOS",
244 "on_device_android_only": "La inferencia local está disponible actualmente solo en Android.",
245 "on_device_models_title": "Modelos locales",
246 + "onboarding_choose_language": "Elija el idioma",
247 + "onboarding_choose_language_desc": "Seleccione su idioma preferido. Puede cambiar esto en cualquier momento en la configuración.",
248 "onboarding_connect_desc": "Conéctese a LM Studio, Ollama o\nOpenRouter para comenzar su experiencia\nprivada de IA.",
249 "onboarding_connect_server": "Conecte su\nservidor",
250 "onboarding_localmind": "LOCALMIND",
251 + "onboarding_welcome": "Bienvenido a LocalMind",
252 "online": "En línea",
253 "open_source": "Código abierto",
254 "open_source_desc": "LocalMind es de código abierto. Siga nuestro progreso o contribuya en GitHub.",
lib/l10n/app_hi.arb
+3
@@ -243,9 +243,12 @@
243 "older_section": "पुराने",
244 "on_device_android_only": "ऑन-डिवाइस अनुमान वर्तमान में केवल Android पर उपलब्ध है।",
245 "on_device_models_title": "ऑन-डिवाइस मॉडल",
246 + "onboarding_choose_language": "भाषा चुनें",
247 + "onboarding_choose_language_desc": "अपनी पसंदीदा भाषा चुनें। आप इसे सेटिंग्स में कभी भी बदल सकते हैं।",
248 "onboarding_connect_desc": "अपना निजी AI अनुभव शुरू करने के लिए\nLM Studio, Ollama, या OpenRouter से\nकनेक्ट करें।",
249 "onboarding_connect_server": "अपना सर्वर\nकनेक्ट करें",
250 "onboarding_localmind": "LOCALMIND",
251 + "onboarding_welcome": "LocalMind में आपका स्वागत है",
252 "online": "ऑनलाइन",
253 "open_source": "ओपन सोर्स",
254 "open_source_desc": "LocalMind ओपन सोर्स है। गिटहब (GitHub) पर हमारी प्रगति का अनुसरण करें या योगदान दें।",
lib/l10n/app_localizations.dart
+18
@@ -1522,6 +1522,18 @@ abstract class AppLocalizations {
1522 /// **'OLDER'**
1523 String get older_section;
1524
1525 + /// Onboarding title to select application language
1526 + ///
1527 + /// In en, this message translates to:
1528 + /// **'Choose Language'**
1529 + String get onboarding_choose_language;
1530 +
1531 + /// Onboarding description for language selection
1532 + ///
1533 + /// In en, this message translates to:
1534 + /// **'Select your preferred language. You can change this anytime in settings.'**
1535 + String get onboarding_choose_language_desc;
1536 +
1537 /// Onboarding screen branding text
1538 ///
1539 /// In en, this message translates to:
@@ -1540,6 +1552,12 @@ abstract class AppLocalizations {
1552 /// **'Connect to LM Studio, Ollama, or\nOpenRouter to start your private AI\nexperience.'**
1553 String get onboarding_connect_desc;
1554
1555 + /// Onboarding welcome message
1556 + ///
1557 + /// In en, this message translates to:
1558 + /// **'Welcome to LocalMind'**
1559 + String get onboarding_welcome;
1560 +
1561 /// On-device server type card title
1562 ///
1563 /// In en, this message translates to:
lib/l10n/app_localizations_ar.dart
+10
@@ -761,6 +761,13 @@ class AppLocalizationsAr extends AppLocalizations {
761 @override
762 String get older_section => 'الأقدم';
763
764 + @override
765 + String get onboarding_choose_language => 'اختر اللغة';
766 +
767 + @override
768 + String get onboarding_choose_language_desc =>
769 + 'اختر لغتك المفضلة. يمكنك تغيير هذا في أي وقت من الإعدادات.';
770 +
771 @override
772 String get onboarding_localmind => 'LOCALMIND';
773
@@ -771,6 +778,9 @@ class AppLocalizationsAr extends AppLocalizations {
778 String get onboarding_connect_desc =>
779 'اتصل بـ LM Studio أو Ollama أو\nOpenRouter لبدء تجربة الذكاء\nالاصطناعي الخاصة بك.';
780
781 + @override
782 + String get onboarding_welcome => 'مرحباً بك في LocalMind';
783 +
784 @override
785 String get server_type_on_device => 'محلي';
786
lib/l10n/app_localizations_bn.dart
+10
@@ -765,6 +765,13 @@ class AppLocalizationsBn extends AppLocalizations {
765 @override
766 String get older_section => 'পূর্বের';
767
768 + @override
769 + String get onboarding_choose_language => 'ভাষা নির্বাচন করুন';
770 +
771 + @override
772 + String get onboarding_choose_language_desc =>
773 + 'আপনার পছন্দের ভাষা নির্বাচন করুন। আপনি সেটিংস থেকে যেকোনো সময় এটি পরিবর্তন করতে পারবেন।';
774 +
775 @override
776 String get onboarding_localmind => 'LOCALMIND';
777
@@ -775,6 +782,9 @@ class AppLocalizationsBn extends AppLocalizations {
782 String get onboarding_connect_desc =>
783 'আপনার নিজস্ব ব্যক্তিগত এআই অভিজ্ঞতা শুরু করতে\nLM Studio, Ollama, অথবা OpenRouter-এর সাথে\nসংযোগ করুন।';
784
785 + @override
786 + String get onboarding_welcome => 'LocalMind-এ স্বাগতম';
787 +
788 @override
789 String get server_type_on_device => 'অন-ডিভাইস (On-Device)';
790
lib/l10n/app_localizations_en.dart
+10
@@ -762,6 +762,13 @@ class AppLocalizationsEn extends AppLocalizations {
762 @override
763 String get older_section => 'OLDER';
764
765 + @override
766 + String get onboarding_choose_language => 'Choose Language';
767 +
768 + @override
769 + String get onboarding_choose_language_desc =>
770 + 'Select your preferred language. You can change this anytime in settings.';
771 +
772 @override
773 String get onboarding_localmind => 'LOCALMIND';
774
@@ -772,6 +779,9 @@ class AppLocalizationsEn extends AppLocalizations {
779 String get onboarding_connect_desc =>
780 'Connect to LM Studio, Ollama, or\nOpenRouter to start your private AI\nexperience.';
781
782 + @override
783 + String get onboarding_welcome => 'Welcome to LocalMind';
784 +
785 @override
786 String get server_type_on_device => 'On-Device';
787
lib/l10n/app_localizations_es.dart
+10
@@ -765,6 +765,13 @@ class AppLocalizationsEs extends AppLocalizations {
765 @override
766 String get older_section => 'MÁS ANTIGUOS';
767
768 + @override
769 + String get onboarding_choose_language => 'Elija el idioma';
770 +
771 + @override
772 + String get onboarding_choose_language_desc =>
773 + 'Seleccione su idioma preferido. Puede cambiar esto en cualquier momento en la configuración.';
774 +
775 @override
776 String get onboarding_localmind => 'LOCALMIND';
777
@@ -775,6 +782,9 @@ class AppLocalizationsEs extends AppLocalizations {
782 String get onboarding_connect_desc =>
783 'Conéctese a LM Studio, Ollama o\nOpenRouter para comenzar su experiencia\nprivada de IA.';
784
785 + @override
786 + String get onboarding_welcome => 'Bienvenido a LocalMind';
787 +
788 @override
789 String get server_type_on_device => 'Local';
790
lib/l10n/app_localizations_hi.dart
+10
@@ -764,6 +764,13 @@ class AppLocalizationsHi extends AppLocalizations {
764 @override
765 String get older_section => 'पुराने';
766
767 + @override
768 + String get onboarding_choose_language => 'भाषा चुनें';
769 +
770 + @override
771 + String get onboarding_choose_language_desc =>
772 + 'अपनी पसंदीदा भाषा चुनें। आप इसे सेटिंग्स में कभी भी बदल सकते हैं।';
773 +
774 @override
775 String get onboarding_localmind => 'LOCALMIND';
776
@@ -774,6 +781,9 @@ class AppLocalizationsHi extends AppLocalizations {
781 String get onboarding_connect_desc =>
782 'अपना निजी AI अनुभव शुरू करने के लिए\nLM Studio, Ollama, या OpenRouter से\nकनेक्ट करें।';
783
784 + @override
785 + String get onboarding_welcome => 'LocalMind में आपका स्वागत है';
786 +
787 @override
788 String get server_type_on_device => 'ऑन-डिवाइस';
789
lib/l10n/app_localizations_zh.dart
+9
@@ -752,6 +752,12 @@ class AppLocalizationsZh extends AppLocalizations {
752 @override
753 String get older_section => '更早';
754
755 + @override
756 + String get onboarding_choose_language => '选择语言';
757 +
758 + @override
759 + String get onboarding_choose_language_desc => '选择您首选的语言。您随时可以在设置中更改此项。';
760 +
761 @override
762 String get onboarding_localmind => 'LOCALMIND';
763
@@ -762,6 +768,9 @@ class AppLocalizationsZh extends AppLocalizations {
768 String get onboarding_connect_desc =>
769 '连接到 LM Studio、Ollama 或\nOpenRouter,开启您的私有 AI\n体验。';
770
771 + @override
772 + String get onboarding_welcome => '欢迎使用 LocalMind';
773 +
774 @override
775 String get server_type_on_device => '设备端';
776
lib/l10n/app_zh.arb
+3
@@ -243,9 +243,12 @@
243 "older_section": "更早",
244 "on_device_android_only": "设备端推理当前仅可在 Android 上使用。",
245 "on_device_models_title": "设备端模型",
246 + "onboarding_choose_language": "选择语言",
247 + "onboarding_choose_language_desc": "选择您首选的语言。您随时可以在设置中更改此项。",
248 "onboarding_connect_desc": "连接到 LM Studio、Ollama 或\nOpenRouter,开启您的私有 AI\n体验。",
249 "onboarding_connect_server": "连接您的\n服务器",
250 "onboarding_localmind": "LOCALMIND",
251 + "onboarding_welcome": "欢迎使用 LocalMind",
252 "online": "在线",
253 "open_source": "开源",
254 "open_source_desc": "LocalMind 是开源项目。可在 GitHub 上关注我们的进展或参与贡献。",
pubspec.yaml
+1 -1
@@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
16 # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
17 # In Windows, build-name is used as the major, minor, and patch parts
18 # of the product and file versions while build-number is used as the build suffix.
19 -version: 1.2.6+25
19 +version: 1.2.7+26
20
21 environment:
22 sdk: ^3.11.0