diff --git a/finlog_app/app/assets/i18n/de.i18n.json b/finlog_app/app/assets/i18n/de.i18n.json index 226efb6..f249c69 100644 --- a/finlog_app/app/assets/i18n/de.i18n.json +++ b/finlog_app/app/assets/i18n/de.i18n.json @@ -1,8 +1,30 @@ { "hello": "Hallo $name", "login": { + "title": "Login", + "pleaseSignIn": "Bitte melden Sie sich an", + "signingIn": "Melde Sie an…", "success": "Login erfolgreich" }, + "dashboard": { + "welcome": "Dashboard – Willkommen bei Finlog" + }, + "budget": { + "title": "Budgets" + }, + "app": { + "navigationSettings": "Einstellungen", + "navigationDashboard": "Dashboard", + "navigationBudgets": "Budgets", + "navigationInventory": "Inventar", + "navigationReports": "Berichte", + "tooltipMenu": "Menü", + "tooltipNotifications": "Benachrichtigungen", + "tooltipUserSettings": "Benutzer-Einstellungen", + "tooltipCollapseRail": "Leiste verkleinern", + "tooltipExpandRail": "Leiste erweitern", + "drawerSettings": "Einstellungen" + }, "settings": { "title": "Einstellungen", "sections": { @@ -21,6 +43,38 @@ }, "messages": { "logoutNotImplemented": "Logout… (noch nicht implementiert)" + }, + "app": { + "systemBackground": "System-Hintergrundfarbe", + "systemDefault": "Systemstandard", + "darkMode": "Dark Mode", + "lightMode": "Light Mode", + "textSize": "Textgröße", + "system": "System", + "small": "Klein", + "medium": "Mittel", + "large": "Groß", + "language": "Sprache", + "german": "Deutsch", + "english": "Englisch" + }, + "personalData": { + "name": "Name", + "maxMustermann": "Max Mustermann", + "changePassword": "Passwort ändern", + "twoFactor": "2-Faktor-Authentifizierung", + "off": "Aus" + }, + "accountManagement": { + "email": "E-Mail" + }, + "help": { + "faq": "FAQ", + "sendFeedback": "Feedback senden" + }, + "legal": { + "privacy": "Datenschutz", + "termsOfService": "Nutzungsbedingungen" } } } diff --git a/finlog_app/app/assets/i18n/en.i18n.json b/finlog_app/app/assets/i18n/en.i18n.json index 5464d10..4eff33a 100644 --- a/finlog_app/app/assets/i18n/en.i18n.json +++ b/finlog_app/app/assets/i18n/en.i18n.json @@ -1,8 +1,30 @@ { "hello": "Hello $name", "login": { + "title": "Login", + "pleaseSignIn": "Please sign in", + "signingIn": "Signing you in…", "success": "Logged in successfully" }, + "dashboard": { + "welcome": "Dashboard – Welcome to Finlog" + }, + "budget": { + "title": "Budgets" + }, + "app": { + "navigationSettings": "Settings", + "navigationDashboard": "Dashboard", + "navigationBudgets": "Budgets", + "navigationInventory": "Inventory", + "navigationReports": "Reports", + "tooltipMenu": "Menu", + "tooltipNotifications": "Notifications", + "tooltipUserSettings": "User Settings", + "tooltipCollapseRail": "Collapse Rail", + "tooltipExpandRail": "Expand Rail", + "drawerSettings": "Settings" + }, "settings": { "title": "Settings", "sections": { @@ -21,6 +43,38 @@ }, "messages": { "logoutNotImplemented": "Logout… (not implemented yet)" + }, + "app": { + "systemBackground": "System Background Color", + "systemDefault": "System Default", + "darkMode": "Dark Mode", + "lightMode": "Light Mode", + "textSize": "Text Size", + "system": "System", + "small": "Small", + "medium": "Medium", + "large": "Large", + "language": "Language", + "german": "German", + "english": "English" + }, + "personalData": { + "name": "Name", + "maxMustermann": "Max Mustermann", + "changePassword": "Change Password", + "twoFactor": "Two-Factor Authentication", + "off": "Off" + }, + "accountManagement": { + "email": "Email" + }, + "help": { + "faq": "FAQ", + "sendFeedback": "Send Feedback" + }, + "legal": { + "privacy": "Privacy", + "termsOfService": "Terms of Service" } } } diff --git a/finlog_app/app/lib/core/i18n/translations.g.dart b/finlog_app/app/lib/core/i18n/translations.g.dart index 3bf8b89..7b2f310 100644 --- a/finlog_app/app/lib/core/i18n/translations.g.dart +++ b/finlog_app/app/lib/core/i18n/translations.g.dart @@ -4,9 +4,9 @@ /// To regenerate, run: `dart run slang` /// /// Locales: 2 -/// Strings: 28 (14 per locale) +/// Strings: 104 (52 per locale) /// -/// Built on 2025-09-27 at 09:55 UTC +/// Built on 2025-09-27 at 10:12 UTC // coverage:ignore-file // ignore_for_file: type=lint, unused_import diff --git a/finlog_app/app/lib/core/i18n/translations_de.g.dart b/finlog_app/app/lib/core/i18n/translations_de.g.dart index 2f0e987..145b647 100644 --- a/finlog_app/app/lib/core/i18n/translations_de.g.dart +++ b/finlog_app/app/lib/core/i18n/translations_de.g.dart @@ -38,6 +38,9 @@ class TranslationsDe implements Translations { // Translations @override String hello({required Object name}) => 'Hallo ${name}'; @override late final _TranslationsLoginDe login = _TranslationsLoginDe._(_root); + @override late final _TranslationsDashboardDe dashboard = _TranslationsDashboardDe._(_root); + @override late final _TranslationsBudgetDe budget = _TranslationsBudgetDe._(_root); + @override late final _TranslationsAppDe app = _TranslationsAppDe._(_root); @override late final _TranslationsSettingsDe settings = _TranslationsSettingsDe._(_root); } @@ -48,9 +51,52 @@ class _TranslationsLoginDe implements TranslationsLoginEn { final TranslationsDe _root; // ignore: unused_field // Translations + @override String get title => 'Login'; + @override String get pleaseSignIn => 'Bitte melden Sie sich an'; + @override String get signingIn => 'Melde Sie an…'; @override String get success => 'Login erfolgreich'; } +// Path: dashboard +class _TranslationsDashboardDe implements TranslationsDashboardEn { + _TranslationsDashboardDe._(this._root); + + final TranslationsDe _root; // ignore: unused_field + + // Translations + @override String get welcome => 'Dashboard – Willkommen bei Finlog'; +} + +// Path: budget +class _TranslationsBudgetDe implements TranslationsBudgetEn { + _TranslationsBudgetDe._(this._root); + + final TranslationsDe _root; // ignore: unused_field + + // Translations + @override String get title => 'Budgets'; +} + +// Path: app +class _TranslationsAppDe implements TranslationsAppEn { + _TranslationsAppDe._(this._root); + + final TranslationsDe _root; // ignore: unused_field + + // Translations + @override String get navigationSettings => 'Einstellungen'; + @override String get navigationDashboard => 'Dashboard'; + @override String get navigationBudgets => 'Budgets'; + @override String get navigationInventory => 'Inventar'; + @override String get navigationReports => 'Berichte'; + @override String get tooltipMenu => 'Menü'; + @override String get tooltipNotifications => 'Benachrichtigungen'; + @override String get tooltipUserSettings => 'Benutzer-Einstellungen'; + @override String get tooltipCollapseRail => 'Leiste verkleinern'; + @override String get tooltipExpandRail => 'Leiste erweitern'; + @override String get drawerSettings => 'Einstellungen'; +} + // Path: settings class _TranslationsSettingsDe implements TranslationsSettingsEn { _TranslationsSettingsDe._(this._root); @@ -62,6 +108,11 @@ class _TranslationsSettingsDe implements TranslationsSettingsEn { @override late final _TranslationsSettingsSectionsDe sections = _TranslationsSettingsSectionsDe._(_root); @override late final _TranslationsSettingsItemsDe items = _TranslationsSettingsItemsDe._(_root); @override late final _TranslationsSettingsMessagesDe messages = _TranslationsSettingsMessagesDe._(_root); + @override late final _TranslationsSettingsAppDe app = _TranslationsSettingsAppDe._(_root); + @override late final _TranslationsSettingsPersonalDataDe personalData = _TranslationsSettingsPersonalDataDe._(_root); + @override late final _TranslationsSettingsAccountManagementDe accountManagement = _TranslationsSettingsAccountManagementDe._(_root); + @override late final _TranslationsSettingsHelpDe help = _TranslationsSettingsHelpDe._(_root); + @override late final _TranslationsSettingsLegalDe legal = _TranslationsSettingsLegalDe._(_root); } // Path: settings.sections @@ -102,13 +153,96 @@ class _TranslationsSettingsMessagesDe implements TranslationsSettingsMessagesEn @override String get logoutNotImplemented => 'Logout… (noch nicht implementiert)'; } +// Path: settings.app +class _TranslationsSettingsAppDe implements TranslationsSettingsAppEn { + _TranslationsSettingsAppDe._(this._root); + + final TranslationsDe _root; // ignore: unused_field + + // Translations + @override String get systemBackground => 'System-Hintergrundfarbe'; + @override String get systemDefault => 'Systemstandard'; + @override String get darkMode => 'Dark Mode'; + @override String get lightMode => 'Light Mode'; + @override String get textSize => 'Textgröße'; + @override String get system => 'System'; + @override String get small => 'Klein'; + @override String get medium => 'Mittel'; + @override String get large => 'Groß'; + @override String get language => 'Sprache'; + @override String get german => 'Deutsch'; + @override String get english => 'Englisch'; +} + +// Path: settings.personalData +class _TranslationsSettingsPersonalDataDe implements TranslationsSettingsPersonalDataEn { + _TranslationsSettingsPersonalDataDe._(this._root); + + final TranslationsDe _root; // ignore: unused_field + + // Translations + @override String get name => 'Name'; + @override String get maxMustermann => 'Max Mustermann'; + @override String get changePassword => 'Passwort ändern'; + @override String get twoFactor => '2-Faktor-Authentifizierung'; + @override String get off => 'Aus'; +} + +// Path: settings.accountManagement +class _TranslationsSettingsAccountManagementDe implements TranslationsSettingsAccountManagementEn { + _TranslationsSettingsAccountManagementDe._(this._root); + + final TranslationsDe _root; // ignore: unused_field + + // Translations + @override String get email => 'E-Mail'; +} + +// Path: settings.help +class _TranslationsSettingsHelpDe implements TranslationsSettingsHelpEn { + _TranslationsSettingsHelpDe._(this._root); + + final TranslationsDe _root; // ignore: unused_field + + // Translations + @override String get faq => 'FAQ'; + @override String get sendFeedback => 'Feedback senden'; +} + +// Path: settings.legal +class _TranslationsSettingsLegalDe implements TranslationsSettingsLegalEn { + _TranslationsSettingsLegalDe._(this._root); + + final TranslationsDe _root; // ignore: unused_field + + // Translations + @override String get privacy => 'Datenschutz'; + @override String get termsOfService => 'Nutzungsbedingungen'; +} + /// Flat map(s) containing all translations. /// Only for edge cases! For simple maps, use the map function of this library. extension on TranslationsDe { dynamic _flatMapFunction(String path) { switch (path) { case 'hello': return ({required Object name}) => 'Hallo ${name}'; + case 'login.title': return 'Login'; + case 'login.pleaseSignIn': return 'Bitte melden Sie sich an'; + case 'login.signingIn': return 'Melde Sie an…'; case 'login.success': return 'Login erfolgreich'; + case 'dashboard.welcome': return 'Dashboard – Willkommen bei Finlog'; + case 'budget.title': return 'Budgets'; + case 'app.navigationSettings': return 'Einstellungen'; + case 'app.navigationDashboard': return 'Dashboard'; + case 'app.navigationBudgets': return 'Budgets'; + case 'app.navigationInventory': return 'Inventar'; + case 'app.navigationReports': return 'Berichte'; + case 'app.tooltipMenu': return 'Menü'; + case 'app.tooltipNotifications': return 'Benachrichtigungen'; + case 'app.tooltipUserSettings': return 'Benutzer-Einstellungen'; + case 'app.tooltipCollapseRail': return 'Leiste verkleinern'; + case 'app.tooltipExpandRail': return 'Leiste erweitern'; + case 'app.drawerSettings': return 'Einstellungen'; case 'settings.title': return 'Einstellungen'; case 'settings.sections.account': return 'Konto & Daten'; case 'settings.sections.app': return 'App'; @@ -121,6 +255,28 @@ extension on TranslationsDe { case 'settings.items.legalPrivacy': return 'Rechtliches & Datenschutz'; case 'settings.items.logout': return 'Abmelden'; case 'settings.messages.logoutNotImplemented': return 'Logout… (noch nicht implementiert)'; + case 'settings.app.systemBackground': return 'System-Hintergrundfarbe'; + case 'settings.app.systemDefault': return 'Systemstandard'; + case 'settings.app.darkMode': return 'Dark Mode'; + case 'settings.app.lightMode': return 'Light Mode'; + case 'settings.app.textSize': return 'Textgröße'; + case 'settings.app.system': return 'System'; + case 'settings.app.small': return 'Klein'; + case 'settings.app.medium': return 'Mittel'; + case 'settings.app.large': return 'Groß'; + case 'settings.app.language': return 'Sprache'; + case 'settings.app.german': return 'Deutsch'; + case 'settings.app.english': return 'Englisch'; + case 'settings.personalData.name': return 'Name'; + case 'settings.personalData.maxMustermann': return 'Max Mustermann'; + case 'settings.personalData.changePassword': return 'Passwort ändern'; + case 'settings.personalData.twoFactor': return '2-Faktor-Authentifizierung'; + case 'settings.personalData.off': return 'Aus'; + case 'settings.accountManagement.email': return 'E-Mail'; + case 'settings.help.faq': return 'FAQ'; + case 'settings.help.sendFeedback': return 'Feedback senden'; + case 'settings.legal.privacy': return 'Datenschutz'; + case 'settings.legal.termsOfService': return 'Nutzungsbedingungen'; default: return null; } } diff --git a/finlog_app/app/lib/core/i18n/translations_en.g.dart b/finlog_app/app/lib/core/i18n/translations_en.g.dart index 787daed..881707d 100644 --- a/finlog_app/app/lib/core/i18n/translations_en.g.dart +++ b/finlog_app/app/lib/core/i18n/translations_en.g.dart @@ -44,6 +44,9 @@ class Translations implements BaseTranslations { String hello({required Object name}) => 'Hello ${name}'; late final TranslationsLoginEn login = TranslationsLoginEn._(_root); + late final TranslationsDashboardEn dashboard = TranslationsDashboardEn._(_root); + late final TranslationsBudgetEn budget = TranslationsBudgetEn._(_root); + late final TranslationsAppEn app = TranslationsAppEn._(_root); late final TranslationsSettingsEn settings = TranslationsSettingsEn._(_root); } @@ -55,10 +58,85 @@ class TranslationsLoginEn { // Translations + /// en: 'Login' + String get title => 'Login'; + + /// en: 'Please sign in' + String get pleaseSignIn => 'Please sign in'; + + /// en: 'Signing you in…' + String get signingIn => 'Signing you in…'; + /// en: 'Logged in successfully' String get success => 'Logged in successfully'; } +// Path: dashboard +class TranslationsDashboardEn { + TranslationsDashboardEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + + /// en: 'Dashboard – Welcome to Finlog' + String get welcome => 'Dashboard – Welcome to Finlog'; +} + +// Path: budget +class TranslationsBudgetEn { + TranslationsBudgetEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + + /// en: 'Budgets' + String get title => 'Budgets'; +} + +// Path: app +class TranslationsAppEn { + TranslationsAppEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + + /// en: 'Settings' + String get navigationSettings => 'Settings'; + + /// en: 'Dashboard' + String get navigationDashboard => 'Dashboard'; + + /// en: 'Budgets' + String get navigationBudgets => 'Budgets'; + + /// en: 'Inventory' + String get navigationInventory => 'Inventory'; + + /// en: 'Reports' + String get navigationReports => 'Reports'; + + /// en: 'Menu' + String get tooltipMenu => 'Menu'; + + /// en: 'Notifications' + String get tooltipNotifications => 'Notifications'; + + /// en: 'User Settings' + String get tooltipUserSettings => 'User Settings'; + + /// en: 'Collapse Rail' + String get tooltipCollapseRail => 'Collapse Rail'; + + /// en: 'Expand Rail' + String get tooltipExpandRail => 'Expand Rail'; + + /// en: 'Settings' + String get drawerSettings => 'Settings'; +} + // Path: settings class TranslationsSettingsEn { TranslationsSettingsEn._(this._root); @@ -73,6 +151,11 @@ class TranslationsSettingsEn { late final TranslationsSettingsSectionsEn sections = TranslationsSettingsSectionsEn._(_root); late final TranslationsSettingsItemsEn items = TranslationsSettingsItemsEn._(_root); late final TranslationsSettingsMessagesEn messages = TranslationsSettingsMessagesEn._(_root); + late final TranslationsSettingsAppEn app = TranslationsSettingsAppEn._(_root); + late final TranslationsSettingsPersonalDataEn personalData = TranslationsSettingsPersonalDataEn._(_root); + late final TranslationsSettingsAccountManagementEn accountManagement = TranslationsSettingsAccountManagementEn._(_root); + late final TranslationsSettingsHelpEn help = TranslationsSettingsHelpEn._(_root); + late final TranslationsSettingsLegalEn legal = TranslationsSettingsLegalEn._(_root); } // Path: settings.sections @@ -135,13 +218,140 @@ class TranslationsSettingsMessagesEn { String get logoutNotImplemented => 'Logout… (not implemented yet)'; } +// Path: settings.app +class TranslationsSettingsAppEn { + TranslationsSettingsAppEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + + /// en: 'System Background Color' + String get systemBackground => 'System Background Color'; + + /// en: 'System Default' + String get systemDefault => 'System Default'; + + /// en: 'Dark Mode' + String get darkMode => 'Dark Mode'; + + /// en: 'Light Mode' + String get lightMode => 'Light Mode'; + + /// en: 'Text Size' + String get textSize => 'Text Size'; + + /// en: 'System' + String get system => 'System'; + + /// en: 'Small' + String get small => 'Small'; + + /// en: 'Medium' + String get medium => 'Medium'; + + /// en: 'Large' + String get large => 'Large'; + + /// en: 'Language' + String get language => 'Language'; + + /// en: 'German' + String get german => 'German'; + + /// en: 'English' + String get english => 'English'; +} + +// Path: settings.personalData +class TranslationsSettingsPersonalDataEn { + TranslationsSettingsPersonalDataEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + + /// en: 'Name' + String get name => 'Name'; + + /// en: 'Max Mustermann' + String get maxMustermann => 'Max Mustermann'; + + /// en: 'Change Password' + String get changePassword => 'Change Password'; + + /// en: 'Two-Factor Authentication' + String get twoFactor => 'Two-Factor Authentication'; + + /// en: 'Off' + String get off => 'Off'; +} + +// Path: settings.accountManagement +class TranslationsSettingsAccountManagementEn { + TranslationsSettingsAccountManagementEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + + /// en: 'Email' + String get email => 'Email'; +} + +// Path: settings.help +class TranslationsSettingsHelpEn { + TranslationsSettingsHelpEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + + /// en: 'FAQ' + String get faq => 'FAQ'; + + /// en: 'Send Feedback' + String get sendFeedback => 'Send Feedback'; +} + +// Path: settings.legal +class TranslationsSettingsLegalEn { + TranslationsSettingsLegalEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + + /// en: 'Privacy' + String get privacy => 'Privacy'; + + /// en: 'Terms of Service' + String get termsOfService => 'Terms of Service'; +} + /// Flat map(s) containing all translations. /// Only for edge cases! For simple maps, use the map function of this library. extension on Translations { dynamic _flatMapFunction(String path) { switch (path) { case 'hello': return ({required Object name}) => 'Hello ${name}'; + case 'login.title': return 'Login'; + case 'login.pleaseSignIn': return 'Please sign in'; + case 'login.signingIn': return 'Signing you in…'; case 'login.success': return 'Logged in successfully'; + case 'dashboard.welcome': return 'Dashboard – Welcome to Finlog'; + case 'budget.title': return 'Budgets'; + case 'app.navigationSettings': return 'Settings'; + case 'app.navigationDashboard': return 'Dashboard'; + case 'app.navigationBudgets': return 'Budgets'; + case 'app.navigationInventory': return 'Inventory'; + case 'app.navigationReports': return 'Reports'; + case 'app.tooltipMenu': return 'Menu'; + case 'app.tooltipNotifications': return 'Notifications'; + case 'app.tooltipUserSettings': return 'User Settings'; + case 'app.tooltipCollapseRail': return 'Collapse Rail'; + case 'app.tooltipExpandRail': return 'Expand Rail'; + case 'app.drawerSettings': return 'Settings'; case 'settings.title': return 'Settings'; case 'settings.sections.account': return 'Account & Data'; case 'settings.sections.app': return 'App'; @@ -154,6 +364,28 @@ extension on Translations { case 'settings.items.legalPrivacy': return 'Legal & Privacy'; case 'settings.items.logout': return 'Sign out'; case 'settings.messages.logoutNotImplemented': return 'Logout… (not implemented yet)'; + case 'settings.app.systemBackground': return 'System Background Color'; + case 'settings.app.systemDefault': return 'System Default'; + case 'settings.app.darkMode': return 'Dark Mode'; + case 'settings.app.lightMode': return 'Light Mode'; + case 'settings.app.textSize': return 'Text Size'; + case 'settings.app.system': return 'System'; + case 'settings.app.small': return 'Small'; + case 'settings.app.medium': return 'Medium'; + case 'settings.app.large': return 'Large'; + case 'settings.app.language': return 'Language'; + case 'settings.app.german': return 'German'; + case 'settings.app.english': return 'English'; + case 'settings.personalData.name': return 'Name'; + case 'settings.personalData.maxMustermann': return 'Max Mustermann'; + case 'settings.personalData.changePassword': return 'Change Password'; + case 'settings.personalData.twoFactor': return 'Two-Factor Authentication'; + case 'settings.personalData.off': return 'Off'; + case 'settings.accountManagement.email': return 'Email'; + case 'settings.help.faq': return 'FAQ'; + case 'settings.help.sendFeedback': return 'Send Feedback'; + case 'settings.legal.privacy': return 'Privacy'; + case 'settings.legal.termsOfService': return 'Terms of Service'; default: return null; } } diff --git a/finlog_app/app/lib/modules/app_shell.dart b/finlog_app/app/lib/modules/app_shell.dart index 16da236..f69da0e 100644 --- a/finlog_app/app/lib/modules/app_shell.dart +++ b/finlog_app/app/lib/modules/app_shell.dart @@ -1,3 +1,4 @@ +import 'package:app/core/i18n/translations.g.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; @@ -23,53 +24,55 @@ class _AppShellState extends State { // --- NAV ITEMS ------------------------------------------------------------- - final _items = - const < - ({IconData icon, IconData? selectedIcon, String label, String route}) - >[ - ( - icon: Icons.dashboard_outlined, - selectedIcon: Icons.dashboard, - label: 'Dashboard', - route: '/home', - ), - ( - icon: Icons.account_balance_wallet_outlined, - selectedIcon: Icons.account_balance_wallet, - label: 'Budgets', - route: '/budget', - ), - ( - icon: Icons.inventory_2_outlined, - selectedIcon: Icons.inventory_2, - label: 'Inventar', - route: '/inventory', - ), - ( - icon: Icons.bar_chart_outlined, - selectedIcon: Icons.bar_chart, - label: 'Reports', - route: '/reports', - ), - ( + List<({IconData icon, IconData? selectedIcon, String label, String route})> _getItems(BuildContext context) { + final t = Translations.of(context); + return [ + ( + icon: Icons.dashboard_outlined, + selectedIcon: Icons.dashboard, + label: t.app.navigationDashboard, + route: '/home', + ), + ( + icon: Icons.account_balance_wallet_outlined, + selectedIcon: Icons.account_balance_wallet, + label: t.app.navigationBudgets, + route: '/budget', + ), + ( + icon: Icons.inventory_2_outlined, + selectedIcon: Icons.inventory_2, + label: t.app.navigationInventory, + route: '/inventory', + ), + ( + icon: Icons.bar_chart_outlined, + selectedIcon: Icons.bar_chart, + label: t.app.navigationReports, + route: '/reports', + ), + ( icon: Icons.settings, selectedIcon: Icons.settings_outlined, - label: 'Settings', + label: t.app.navigationSettings, route: '/settings', - ), - ]; + ), + ]; + } - int _indexForPath(String p) { - for (var i = 0; i < _items.length; i++) { - if (p.startsWith(_items[i].route)) return i; + int _indexForPath(String p, List<({IconData icon, IconData? selectedIcon, String label, String route})> items) { + for (var i = 0; i < items.length; i++) { + if (p.startsWith(items[i].route)) return i; } return 0; } - void _goForIndex(BuildContext ctx, int i) => ctx.go(_items[i].route); + void _goForIndex(BuildContext ctx, int i, List<({IconData icon, IconData? selectedIcon, String label, String route})> items) => ctx.go(items[i].route); @override Widget build(BuildContext context) { + final t = Translations.of(context); + final items = _getItems(context); final width = MediaQuery.of(context).size.width; final isRail = width >= _railBreakpoint; final currentPath = GoRouterState.of(context).matchedLocation; @@ -89,17 +92,17 @@ class _AppShellState extends State { builder: (ctx) => IconButton( icon: const Icon(Icons.menu), onPressed: () => Scaffold.of(ctx).openDrawer(), - tooltip: 'Menü', + tooltip: t.app.tooltipMenu, ), ), actions: [ IconButton( - tooltip: 'Benachrichtigungen', + tooltip: t.app.tooltipNotifications, onPressed: () {}, icon: const Icon(Icons.notifications_none), ), IconButton( - tooltip: 'Benutzer-Einstellungen', + tooltip: t.app.tooltipUserSettings, onPressed: () => context.push('/settings'), icon: const Icon(Icons.account_circle_outlined), ), @@ -108,16 +111,16 @@ class _AppShellState extends State { if (!isRail) { // ------------------- MOBILE: Drawer ------------------- - final selectedIndex = _indexForPath(currentPath); + final selectedIndex = _indexForPath(currentPath, items); return Scaffold( appBar: appBar, - drawer: _AppDrawer(items: _items, selectedIndex: selectedIndex), + drawer: _AppDrawer(items: items, selectedIndex: selectedIndex), body: SafeArea(child: widget.child), ); } // ------------------- TABLET/DESKTOP: NavigationRail ------------------- - final selected = _indexForPath(currentPath); + final selected = _indexForPath(currentPath, items); final scheme = Theme.of(context).colorScheme; return Scaffold( @@ -143,13 +146,13 @@ class _AppShellState extends State { child: NavigationRail( extended: _railExtended, selectedIndex: selected, - onDestinationSelected: (i) => _goForIndex(context, i), + onDestinationSelected: (i) => _goForIndex(context, i, items), // leading: const Padding( // padding: EdgeInsets.only(top: 8), // child: _LogoHeader(), // ), destinations: [ - for (final it in _items) + for (final it in items) NavigationRailDestination( icon: Icon(it.icon), selectedIcon: Icon(it.selectedIcon ?? it.icon), @@ -164,8 +167,8 @@ class _AppShellState extends State { // toggle lives at the very bottom so layout doesn't jump IconButton( tooltip: _railExtended - ? 'Leiste verkleinern' - : 'Leiste erweitern', + ? t.app.tooltipCollapseRail + : t.app.tooltipExpandRail, onPressed: () => setState(() => _railExtended = !_railExtended), icon: Icon( @@ -234,7 +237,7 @@ class _AppDrawer extends StatelessWidget { const Divider(), ListTile( leading: const Icon(Icons.settings_outlined), - title: const Text('Einstellungen'), + title: Text(Translations.of(context).app.drawerSettings), onTap: () { Navigator.of(context).maybePop(); context.go('/settings'); diff --git a/finlog_app/app/lib/modules/login/pages/login_page.dart b/finlog_app/app/lib/modules/login/pages/login_page.dart index 53e4367..8ab1ba1 100644 --- a/finlog_app/app/lib/modules/login/pages/login_page.dart +++ b/finlog_app/app/lib/modules/login/pages/login_page.dart @@ -1,4 +1,5 @@ import 'package:app/core/app/router.dart'; +import 'package:app/core/i18n/translations.g.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; @@ -28,9 +29,10 @@ class _LoginPageState extends State { @override Widget build(BuildContext context) { + final t = Translations.of(context); final theme = Theme.of(context); return Scaffold( - appBar: AppBar(title: const Text('Login')), + appBar: AppBar(title: Text(t.login.title)), body: Center( child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 360), @@ -39,7 +41,7 @@ class _LoginPageState extends State { children: [ const FlutterLogo(size: 64), const SizedBox(height: 24), - Text('Please sign in', style: theme.textTheme.titleMedium), + Text(t.login.pleaseSignIn, style: theme.textTheme.titleMedium), const SizedBox(height: 24), SizedBox( width: double.infinity, @@ -56,7 +58,7 @@ class _LoginPageState extends State { height: 20, child: CircularProgressIndicator(strokeWidth: 2), ) - : const Text('Login', key: ValueKey('text')), + : Text(t.login.title, key: const ValueKey('text')), ), ), ), @@ -67,7 +69,7 @@ class _LoginPageState extends State { ? Padding( padding: const EdgeInsets.only(top: 4), child: Text( - 'Signing you in…', + t.login.signingIn, style: theme.textTheme.bodySmall, ), ) diff --git a/finlog_app/app/lib/modules/settings/modules/app/app_settings_view.dart b/finlog_app/app/lib/modules/settings/modules/app/app_settings_view.dart index 5db8ff1..35c3f47 100644 --- a/finlog_app/app/lib/modules/settings/modules/app/app_settings_view.dart +++ b/finlog_app/app/lib/modules/settings/modules/app/app_settings_view.dart @@ -1,3 +1,4 @@ +import 'package:app/core/i18n/translations.g.dart'; import 'package:app/core/ui/controller/locale_controller.dart'; import 'package:app/core/ui/controller/scale_controller.dart'; import 'package:app/core/ui/controller/theme.dart'; @@ -61,15 +62,16 @@ class _SystemBackgroundSection extends StatelessWidget { @override Widget build(BuildContext context) { + final t = Translations.of(context); final vm = context.watch(); final selected = vm.themeMode; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text( - 'System-Hintergrundfarbe', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600), + Text( + t.settings.app.systemBackground, + style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600), ), const SizedBox(height: 10), @@ -94,10 +96,10 @@ class _SystemBackgroundSection extends StatelessWidget { }, borderRadius: BorderRadius.circular(24), constraints: const BoxConstraints(minHeight: 44, minWidth: 140), - children: const [ - _SegItem(icon: Icons.phone_iphone, label: 'Systemstandard'), - _SegItem(emoji: '🌙', label: 'Dark Mode'), - _SegItem(emoji: '☀️', label: 'White Mode'), + children: [ + _SegItem(icon: Icons.phone_iphone, label: t.settings.app.systemDefault), + _SegItem(emoji: '🌙', label: t.settings.app.darkMode), + _SegItem(emoji: '☀️', label: t.settings.app.lightMode), ], ), ], @@ -134,13 +136,14 @@ class _TextScaleSection extends StatelessWidget { @override Widget build(BuildContext context) { + final t = Translations.of(context); final vm = context.watch(); final selected = vm.textScale; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('Textgröße', style: TextStyle(fontWeight: FontWeight.w600)), + Text(t.settings.app.textSize, style: const TextStyle(fontWeight: FontWeight.w600)), const SizedBox(height: 8), ToggleButtons( isSelected: [ @@ -167,11 +170,11 @@ class _TextScaleSection extends StatelessWidget { }, borderRadius: BorderRadius.circular(24), constraints: const BoxConstraints(minHeight: 44, minWidth: 120), - children: const [ - _SegItem(icon: Icons.phone_android, label: 'System'), - _SegItem(icon: Icons.text_fields, label: 'Klein'), - _SegItem(icon: Icons.text_fields, label: 'Mittel'), - _SegItem(icon: Icons.text_fields, label: 'Groß'), + children: [ + _SegItem(icon: Icons.phone_android, label: t.settings.app.system), + _SegItem(icon: Icons.text_fields, label: t.settings.app.small), + _SegItem(icon: Icons.text_fields, label: t.settings.app.medium), + _SegItem(icon: Icons.text_fields, label: t.settings.app.large), ], ), ], @@ -184,25 +187,26 @@ class _LanguageSection extends StatelessWidget { @override Widget build(BuildContext context) { + final t = Translations.of(context); final vm = context.watch(); final scheme = Theme.of(context).colorScheme; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('Sprache', style: Theme.of(context).textTheme.titleMedium), + Text(t.settings.app.language, style: Theme.of(context).textTheme.titleMedium), const SizedBox(height: 8), DropdownButtonFormField( initialValue: vm.language, onChanged: (v) => vm.setLanguage(v ?? LanguagePref.en), - items: const [ + items: [ DropdownMenuItem( value: LanguagePref.system, - child: Text('Systemstandard'), + child: Text(t.settings.app.systemDefault), ), - DropdownMenuItem(value: LanguagePref.de, child: Text('Deutsch')), - DropdownMenuItem(value: LanguagePref.en, child: Text('Englisch')), + DropdownMenuItem(value: LanguagePref.de, child: Text(t.settings.app.german)), + DropdownMenuItem(value: LanguagePref.en, child: Text(t.settings.app.english)), ], decoration: InputDecoration( isDense: true,