From 99f3107961bbe57df941cd40fcfd702acd7c3d1b Mon Sep 17 00:00:00 2001 From: Achraf Labidi Date: Tue, 30 Jan 2024 09:30:13 +0100 Subject: [PATCH] Add `en`, `de`, `fr`, `es` language supports --- l10n.yaml | 3 +- lib/l10n/app_de.arb | 20 ++++++-- lib/l10n/app_en.arb | 22 +++++++-- lib/l10n/app_es.arb | 18 +++++++- lib/l10n/app_fr.arb | 20 ++++++-- lib/main.dart | 2 +- lib/views/chat_view/chat_view_state.dart | 1 + lib/views/chat_view/inactive_view.dart | 6 ++- lib/views/chat_view/poll_view_state.dart | 38 +++++++-------- .../components/custom_bottom_nav_bar.dart | 10 ++-- .../custom_search_filter_top_nav_bar.dart | 10 ++-- .../components/custom_search_top_nav_bar.dart | 4 +- ...custom_search_top_nav_bar_back_button.dart | 4 +- lib/views/login_view/internal_login_view.dart | 24 +++++----- .../notifications_overview.dart | 4 +- .../notifications_screen_view.dart | 12 +++-- .../enable_notification_view.dart | 22 +++++---- .../on_boarding_view/welcome_screen_view.dart | 36 +++++++-------- .../custom_playback_speed_view.dart | 4 +- .../edit_profile_screen_view.dart | 6 +-- .../playback_speed_picker_view.dart | 10 ++-- .../playback_speed_settings_view.dart | 5 +- .../preferred_greeting_view.dart | 4 +- .../settings_view/settings_screen_view.dart | 46 ++++++++++--------- 24 files changed, 204 insertions(+), 127 deletions(-) diff --git a/l10n.yaml b/l10n.yaml index 4e6692e5..dbaf35b5 100644 --- a/l10n.yaml +++ b/l10n.yaml @@ -1,3 +1,4 @@ arb-dir: lib/l10n template-arb-file: app_en.arb -output-localization-file: app_localizations.dart \ No newline at end of file +output-localization-file: app_localizations.dart +untranslated-messages-file: desiredFileName.txt diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 436a7365..90e4206e 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -11,13 +11,15 @@ "pin": "Anheften", "unpin": "Lösen", "pinned": "Angeheftet", - "downloads": "Downloads", + "downloads": "Heruntergeladen", "download": "Herunterladen", "notification": "Benachrichtigung", "notifications": "Benachrichtigungen", "no_downloaded_courses": "Sie haben keine Kurse heruntergeladen.", "no_notifications_found": "Keine Benachrichtigungen gefunden.", "banner_notification": "Banner-Benachrichtigung", + "recent_uploads": "Neueste Uploads", + "feature_notifications": "Feature Notifications", "confirm_unpin_title": "Lösen Bestätigen", "confirm_unpin_message": "Sind Sie sicher, dass Sie diesen Kurs lösen möchten?", "newest_first": "Neueste Zuerst", @@ -56,6 +58,7 @@ "video_playback_speed": "Videowiedergabegeschwindigkeit", "playback_speed": "Wiedergabegeschwindigkeit", "add_custom_playback_speed": "Benutzerdefinierte Wiedergabegeschwindigkeit hinzufügen", + "custom_playback_speed": "Benutzerdefinierte Wiedergabegeschwindigkeit", "logout": "Abmelden", "more": "Mehr", "about_us": "Über Uns", @@ -67,7 +70,7 @@ "download_not_allowed": "Download nicht erlaubt", "download_not_allowed_message": "Sie befinden sich derzeit in einem Mobilfunknetz. Das Video kann aufgrund Ihrer Einstellungen nicht über mobile Daten heruntergeladen werden.", "auth_required_title": "Authentifizierung erforderlich", - "auth_required_content": "Bitte melden Sie sich an, um auf diese Funktion zuzugreifen.", + "auth_required_message": "Bitte melden Sie sich an, um auf diese Funktion zuzugreifen.", "add_custom_speed": "Benutzerdefinierte Geschwindigkeit hinzufügen", "enter_speed": "Geschwindigkeit eingeben (z.B. 1.7)", "add": "Hinzufügen", @@ -79,5 +82,16 @@ "enter_preferred_name": "Geben Sie Ihren bevorzugten Namen ein", "enter_preferred_name_prompt": "Bitte geben Sie einen bevorzugten Namen ein", "preferred_name": "Bevorzugter Name", - "save": "Speichern" + "save": "Speichern", + "number_too_long": "Nummer ist zu lang", + "enter_number_between": "Bitte geben Sie eine Zahl zwischen\n0.25 und 2.0 ein", + "turn_on_notifications": "Benachrichtigungen einschalten?", + "notifications_description": "Erhalten Sie sofortige Updates zu Live-Vorlesungen, bevorstehenden Quizzen und wichtigen Ankündigungen. Verpassen Sie keinen Moment Ihrer akademischen Laufbahn.", + "enable_notifications": "Benachrichtigungen aktivieren", + "skip": "Überspringen", + "forgot_password": "Passwort vergessen?", + "username": "Benutzername", + "password": "Passwort", + "enter_your_password": "Geben Sie Ihr Passwort ein", + "home": "Startseite" } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 2812ca3f..9f66c726 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -17,7 +17,9 @@ "notifications": "Notifications", "no_downloaded_courses": "You have no downloaded courses.", "no_notifications_found": "No notifications found.", - "banner_notification": "Banner Notification", + "banner_notification": "Banner Alerts", + "recent_uploads": "Recent Uploads", + "feature_notifications": "Feature Notifications", "confirm_unpin_title": "Confirm Unpin", "confirm_unpin_message": "Are you sure you want to unpin this course?", "newest_first": "Newest First", @@ -56,6 +58,7 @@ "video_playback_speed": "Video Playback Speed", "playback_speed": "Playback Speed", "add_custom_playback_speed": "Add Custom Playback Speed", + "custom_playback_speed": "Custom Playback Speed", "logout": "Logout", "more": "More", "about_us": "About Us", @@ -67,7 +70,7 @@ "download_not_allowed": "Download not allowed", "download_not_allowed_message": "You are currently on mobile data. Video cannot be downloaded over mobile data due to your settings.", "auth_required_title": "Authentication Required", - "auth_required_message": "You need to be authenticated to access this content.", + "auth_required_message": "You need to be authenticated to access this content.", "add_custom_speed": "Add Custom Speed", "enter_speed": "Enter speed (e.g., 1.7)", "add": "Add", @@ -79,5 +82,16 @@ "enter_preferred_name": "Enter your preferred name", "enter_preferred_name_prompt": "Please enter a preferred name", "preferred_name": "Preferred Name", - "save": "Save" -} + "save": "Save", + "number_too_long": "Number is too long", + "enter_number_between": "Please enter a number between\n0.25 and 2.0", + "turn_on_notifications": "Turn on Notifications?", + "notifications_description": "Receive instant updates on live lectures, upcoming quizzes, and important announcements. Never miss a beat in your academic journey.", + "enable_notifications": "Enable notifications", + "skip": "Skip", + "forgot_password": "Forgot Password?", + "username": "username", + "password": "password", + "enter_your_password": "Enter your password", + "home": "Home" +} \ No newline at end of file diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 40f1504b..b681829a 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -18,6 +18,8 @@ "no_downloaded_courses": "No tienes cursos descargados.", "no_notifications_found": "No se encontraron notificaciones.", "banner_notification": "Notificación de Banner", + "recent_uploads": "Cargas Recientes", + "feature_notifications": "Feature Notifications", "confirm_unpin_title": "Confirmar Desanclaje", "confirm_unpin_message": "¿Estás seguro de que quieres desanclar este curso?", "newest_first": "Los Más Nuevos Primero", @@ -56,6 +58,7 @@ "video_playback_speed": "Velocidad de Reproducción de Video", "playback_speed": "Velocidad de Reproducción", "add_custom_playback_speed": "Agregar Velocidad de Reproducción Personalizada", + "custom_playback_speed": "Velocidad de Reproducción Personalizada", "logout": "Cerrar Sesión", "more": "Más", "about_us": "Acerca de Nosotros", @@ -67,7 +70,7 @@ "download_not_allowed": "Descarga no permitida", "download_not_allowed_message": "Actualmente estás en datos móviles. El video no se puede descargar usando datos móviles debido a tus configuraciones.", "auth_required_title": "Autenticación Requerida", - "auth_required_content": "Por favor, inicia sesión para acceder a esta función.", + "auth_required_message": "Por favor, inicia sesión para acceder a esta función.", "add_custom_speed": "Agregar Velocidad Personalizada", "enter_speed": "Ingresa la velocidad (por ejemplo, 1.7)", "add": "Agregar", @@ -79,5 +82,16 @@ "enter_preferred_name": "Ingresa tu nombre preferido", "enter_preferred_name_prompt": "Por favor, ingresa un nombre preferido", "preferred_name": "Nombre Preferido", - "save": "Guardar" + "save": "Guardar", + "number_too_long": "El número es demasiado largo", + "enter_number_between": "Por favor, introduce un número entre\n0.25 y 2.0", + "turn_on_notifications": "¿Activar notificaciones?", + "notifications_description": "Recibe actualizaciones instantáneas sobre conferencias en vivo, próximos cuestionarios y anuncios importantes. Nunca te pierdas un detalle en tu trayectoria académica.", + "enable_notifications": "Activar notificaciones", + "skip": "Omitir", + "forgot_password": "¿Olvidaste la contraseña?", + "username": "nombre de usuario", + "password": "contraseña", + "enter_your_password": "Introduce tu contraseña", + "home": "Inicio" } diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 09a6f271..7218e553 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -17,7 +17,9 @@ "notifications": "Notifications", "no_downloaded_courses": "Vous n'avez aucun cours téléchargé.", "no_notifications_found": "Aucune notification trouvée.", - "banner_notification": "Notification de Bannière", + "banner_notification": "Alertes Bannière", + "recent_uploads": "Derniers Téléchargements", + "feature_notifications": "Notifications de Fonctionnalités", "confirm_unpin_title": "Confirmer le Détachement", "confirm_unpin_message": "Êtes-vous sûr de vouloir détacher ce cours?", "newest_first": "Le Plus Récent en Premier", @@ -56,6 +58,7 @@ "video_playback_speed": "Vitesse de Lecture Vidéo", "playback_speed": "Vitesse de Lecture", "add_custom_playback_speed": "Ajouter une Vitesse de Lecture Personnalisée", + "custom_playback_speed": "Vitesse de Lecture Personnalisée", "logout": "Se Déconnecter", "more": "Plus", "about_us": "À Propos de Nous", @@ -67,7 +70,7 @@ "download_not_allowed": "Téléchargement non autorisé", "download_not_allowed_message": "Vous utilisez actuellement des données mobiles. La vidéo ne peut pas être téléchargée en utilisant les données mobiles en raison de vos paramètres.", "auth_required_title": "Authentification requise", - "auth_required_content": "Veuillez vous connecter pour accéder à cette fonctionnalité.", + "auth_required_message": "Veuillez vous connecter pour accéder à cette fonctionnalité.", "add_custom_speed": "Ajouter une Vitesse Personnalisée", "enter_speed": "Entrez la vitesse (par exemple, 1.7)", "add": "Ajouter", @@ -79,5 +82,16 @@ "enter_preferred_name": "Entrez votre nom préféré", "enter_preferred_name_prompt": "Veuillez entrer un nom préféré", "preferred_name": "Nom Préféré", - "save": "Enregistrer" + "save": "Enregistrer", + "number_too_long": "Le numéro est trop long", + "enter_number_between": "Veuillez entrer un nombre entre\n0.25 et 2.0", + "turn_on_notifications": "Activer les notifications ?", + "notifications_description": "Recevez des mises à jour instantanées sur les conférences en direct, les quiz à venir et les annonces importantes. Ne manquez jamais un moment clé de votre parcours académique.", + "enable_notifications": "Activer les notifications", + "skip": "Passer", + "forgot_password": "Mot de passe oublié ?", + "username": "nom d'utilisateur", + "password": "mot de passe", + "enter_your_password": "Entrez votre mot de passe", + "home": "Accueil" } diff --git a/lib/main.dart b/lib/main.dart index b35e70b0..cecb3731 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -56,7 +56,7 @@ class App extends ConsumerWidget { GlobalCupertinoLocalizations.delegate, ], supportedLocales: L10n.all, - locale: const Locale('fr'), + locale: const Locale('de'), theme: appTheme, // Your light theme darkTheme: darkAppTheme, // Define your dark theme themeMode: diff --git a/lib/views/chat_view/chat_view_state.dart b/lib/views/chat_view/chat_view_state.dart index 37601d35..d11eb412 100644 --- a/lib/views/chat_view/chat_view_state.dart +++ b/lib/views/chat_view/chat_view_state.dart @@ -8,6 +8,7 @@ import 'package:gocast_mobile/providers.dart'; import 'package:gocast_mobile/views/chat_view/chat_view.dart'; import 'package:logger/logger.dart'; + class ChatViewState extends ConsumerState { late ScrollController _scrollController; Timer? _updateTimer; diff --git a/lib/views/chat_view/inactive_view.dart b/lib/views/chat_view/inactive_view.dart index 3cb8aeeb..7cf7f08d 100644 --- a/lib/views/chat_view/inactive_view.dart +++ b/lib/views/chat_view/inactive_view.dart @@ -5,6 +5,8 @@ import 'package:gocast_mobile/providers.dart'; import 'package:gocast_mobile/views/chat_view/suggested_streams_list.dart'; import 'package:gocast_mobile/views/video_view/video_player.dart'; import 'package:gocast_mobile/base/networking/api/gocast/api_v2.pb.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + class InactiveView extends ConsumerStatefulWidget { final int? streamID; @@ -62,8 +64,8 @@ class InactiveViewState extends ConsumerState { ), child: Text( chatState.accessDenied - ? 'Chat is disabled for this lecture' - : 'Chat is Hidden', + ? AppLocalizations.of(context)!.chat_is_disabled_for_this_lecture + : AppLocalizations.of(context)!.chat_is_hidden, textAlign: TextAlign.center, style: const TextStyle( color: Colors.black, diff --git a/lib/views/chat_view/poll_view_state.dart b/lib/views/chat_view/poll_view_state.dart index 7e1ee976..c71b7e4c 100644 --- a/lib/views/chat_view/poll_view_state.dart +++ b/lib/views/chat_view/poll_view_state.dart @@ -5,6 +5,7 @@ import 'package:gocast_mobile/base/networking/api/gocast/api_v2.pb.dart'; import 'package:gocast_mobile/providers.dart'; import 'package:gocast_mobile/views/chat_view/poll_view.dart'; + class PollViewState extends ConsumerState { Timer? _updateTimer; Map selectedOptions = {}; @@ -77,7 +78,6 @@ class PollViewState extends ConsumerState { ThemeData themeData = Theme.of(context); return Opacity( opacity: 0.5, - // You might want to adjust this value based on your design needs child: Card( elevation: 1, shadowColor: themeData.shadowColor, @@ -103,11 +103,10 @@ class PollViewState extends ConsumerState { GridView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - // to disable GridView's scrolling gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, childAspectRatio: - 3, // Adjust the aspect ratio to fit the content + 3, ), itemCount: poll.pollOptions.length, itemBuilder: (context, index) { @@ -127,20 +126,19 @@ class PollViewState extends ConsumerState { PollOption option, int? selectedOptionId,) { bool isSelected = option.id == selectedOptionId; return Container( - margin: const EdgeInsets.all(4.0), // Add some spacing around each button + margin: const EdgeInsets.all(4.0), decoration: BoxDecoration( color: isSelected ? Colors.grey : Colors.white, - // Use grey for the selected option, white for others borderRadius: BorderRadius.circular(8.0), border: - Border.all(color: Colors.grey), // Use grey border for all options + Border.all(color: Colors.grey), ), child: Center( child: Text( option.answer, style: const TextStyle( color: - Colors.black, // Text color remains black to ensure readability + Colors.black, ), ), ), @@ -173,11 +171,10 @@ class PollViewState extends ConsumerState { GridView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - // to disable GridView's scrolling gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, childAspectRatio: - 3, // Adjust the aspect ratio to fit the content + 3, ), itemCount: poll.pollOptions.length, itemBuilder: (context, index) { @@ -228,22 +225,19 @@ class PollViewState extends ConsumerState { return Padding( padding: const EdgeInsets.all(8.0), child: Row( - // Center the question since there's no subtitle or trailing widget children: [ Expanded( child: Text( poll.question, style: const TextStyle( - fontSize: 16.0, // Match the font size used in _buildHeader + fontSize: 16.0, fontWeight: FontWeight - .bold, // Match the font weight used in _buildHeader + .bold, ), textAlign: TextAlign.center, - // Keep text alignment to center as it's a question maxLines: 2, - // Optional: Use if you want to limit the number of lines for the question overflow: TextOverflow - .ellipsis, // Optional: Use to handle text overflow + .ellipsis, ), ), ], @@ -269,18 +263,18 @@ class PollViewState extends ConsumerState { } : null, style: ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).primaryColor, // Use the primary color of your theme - foregroundColor: Colors.white, // Text color is white for better contrast + backgroundColor: Theme.of(context).primaryColor, + foregroundColor: Colors.white, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8.0), // Less rounded corners for a more rectangular look + borderRadius: BorderRadius.circular(8.0), ), - padding: const EdgeInsets.symmetric(vertical: 14.0, horizontal: 30.0), // Adjust padding to control the button's shape - minimumSize: const Size(double.infinity, 48), // Ensuring full width and a consistent height - elevation: 2, // Slight elevation for a subtle shadow, adjust as needed + padding: const EdgeInsets.symmetric(vertical: 14.0, horizontal: 30.0), + minimumSize: const Size(double.infinity, 48), + elevation: 2, ), child: const Text( 'Submit', - style: TextStyle(fontSize: 16), // Adjust font size as needed + style: TextStyle(fontSize: 16), ), ), ); diff --git a/lib/views/components/custom_bottom_nav_bar.dart b/lib/views/components/custom_bottom_nav_bar.dart index e2432a7e..b3b70486 100644 --- a/lib/views/components/custom_bottom_nav_bar.dart +++ b/lib/views/components/custom_bottom_nav_bar.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:gocast_mobile/providers.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + class CustomBottomNavBar extends ConsumerWidget { const CustomBottomNavBar({super.key}); @@ -25,28 +27,28 @@ class CustomBottomNavBar extends ConsumerWidget { items: [ _buildNavigationBarItem( Icons.home, - 'Home', + AppLocalizations.of(context)!.home, context, currentIndex, 0, ), _buildNavigationBarItem( Icons.download, - 'Downloads', + AppLocalizations.of(context)!.downloads, context, currentIndex, 1, ), _buildNavigationBarItem( Icons.push_pin, - 'Pinned', + AppLocalizations.of(context)!.pinned, context, currentIndex, 2, ), _buildNavigationBarItem( Icons.notifications, - 'Notifications', + AppLocalizations.of(context)!.notifications, context, currentIndex, 3, diff --git a/lib/views/components/custom_search_filter_top_nav_bar.dart b/lib/views/components/custom_search_filter_top_nav_bar.dart index 03c1f593..78cbf464 100644 --- a/lib/views/components/custom_search_filter_top_nav_bar.dart +++ b/lib/views/components/custom_search_filter_top_nav_bar.dart @@ -1,4 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + class CustomSearchFilterTopNavBar extends StatelessWidget implements PreferredSizeWidget { @@ -32,11 +34,11 @@ class CustomSearchFilterTopNavBar extends StatelessWidget ), child: TextField( controller: searchController, - decoration: const InputDecoration( + decoration: InputDecoration( border: InputBorder.none, - hintText: 'Search', - prefixIcon: Icon(Icons.search, color: Color(0x993C3C43)), - hintStyle: TextStyle( + hintText: AppLocalizations.of(context)!.search, + prefixIcon: const Icon(Icons.search, color: Color(0x993C3C43)), + hintStyle: const TextStyle( color: Color(0x993C3C43), fontSize: 17, fontFamily: 'SF Pro Text', diff --git a/lib/views/components/custom_search_top_nav_bar.dart b/lib/views/components/custom_search_top_nav_bar.dart index 3a898f82..4411a5b5 100644 --- a/lib/views/components/custom_search_top_nav_bar.dart +++ b/lib/views/components/custom_search_top_nav_bar.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:gocast_mobile/views/components/filter_popup_menu_button.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + class CustomSearchTopNavBar extends ConsumerWidget implements PreferredSizeWidget { @@ -98,7 +100,7 @@ class CustomSearchTopNavBar extends ConsumerWidget onChanged: (value) {}, decoration: InputDecoration( border: InputBorder.none, - hintText: 'Search', + hintText: AppLocalizations.of(context)!.search, prefixIcon: Icon( Icons.search, color: Theme.of(context).inputDecorationTheme.hintStyle?.color, diff --git a/lib/views/components/custom_search_top_nav_bar_back_button.dart b/lib/views/components/custom_search_top_nav_bar_back_button.dart index e6fbae58..097603bf 100644 --- a/lib/views/components/custom_search_top_nav_bar_back_button.dart +++ b/lib/views/components/custom_search_top_nav_bar_back_button.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:gocast_mobile/views/components/filter_popup_menu_button.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + class CustomSearchTopNavBarWithBackButton extends ConsumerWidget implements PreferredSizeWidget { @@ -61,7 +63,7 @@ class CustomSearchTopNavBarWithBackButton extends ConsumerWidget controller: searchController, decoration: InputDecoration( border: InputBorder.none, - hintText: 'Search', + hintText: AppLocalizations.of(context)!.search, prefixIcon: Icon( Icons.search, color: Theme.of(context).inputDecorationTheme.hintStyle?.color, diff --git a/lib/views/login_view/internal_login_view.dart b/lib/views/login_view/internal_login_view.dart index 981c5d37..61ba4fad 100644 --- a/lib/views/login_view/internal_login_view.dart +++ b/lib/views/login_view/internal_login_view.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:gocast_mobile/providers.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + /// Internal login screen view. /// @@ -39,21 +41,21 @@ class InternalLoginScreenState extends ConsumerState { crossAxisAlignment: CrossAxisAlignment.stretch, mainAxisAlignment: MainAxisAlignment.center, children: [ - _buildWelcomeText(), + _buildWelcomeText(context), const SizedBox(height: 48), _buildTextField( - 'Username', + AppLocalizations.of(context)!.username, 'e.g. go42tum / example@tum.de', usernameController, ), const SizedBox(height: 24), _buildTextField( - 'Password', - 'Enter your password', + AppLocalizations.of(context)!.password, + AppLocalizations.of(context)!.enter_your_password, passwordController, obscureText: true, ), - _buildForgotPasswordButton(), + _buildForgotPasswordButton(context), const SizedBox(height: 24), _buildLoginButton(context, ref), ], @@ -64,9 +66,9 @@ class InternalLoginScreenState extends ConsumerState { ); } - Widget _buildWelcomeText() { + Widget _buildWelcomeText(BuildContext context) { return Text( - 'Welcome To GoCast!', + AppLocalizations.of(context)!.welcome_to_gocast, textAlign: TextAlign.center, style: TextStyle( color: Colors.blue[900], @@ -101,14 +103,14 @@ class InternalLoginScreenState extends ConsumerState { ); } - Widget _buildForgotPasswordButton() { + Widget _buildForgotPasswordButton(BuildContext context) { return TextButton( onPressed: () { // TODO: Forgot Password action }, - child: const Text( - 'Forgot Password?', - style: TextStyle(color: Colors.blue), + child: Text( + AppLocalizations.of(context)!.forgot_password, + style: const TextStyle(color: Colors.blue), ), ); } diff --git a/lib/views/notifications_view/notifications_overview.dart b/lib/views/notifications_view/notifications_overview.dart index 39632854..2a053b47 100644 --- a/lib/views/notifications_view/notifications_overview.dart +++ b/lib/views/notifications_view/notifications_overview.dart @@ -2,6 +2,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:gocast_mobile/providers.dart'; import 'notifications_screen_view.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + class MyNotifications extends ConsumerStatefulWidget { const MyNotifications({super.key}); @@ -33,7 +35,7 @@ class MyNotificationsState extends ConsumerState { final bannerAlerts = notificationState.bannerAlerts ?? []; return NotificationsScreen( - title: 'Notifications', + title: AppLocalizations.of(context)!.notifications, pushNotifications: pushNotifications, featureNotifications: featureNotifications, bannerAlerts: bannerAlerts, diff --git a/lib/views/notifications_view/notifications_screen_view.dart b/lib/views/notifications_view/notifications_screen_view.dart index 42c44bfb..00ce7c03 100644 --- a/lib/views/notifications_view/notifications_screen_view.dart +++ b/lib/views/notifications_view/notifications_screen_view.dart @@ -5,6 +5,8 @@ import 'package:gocast_mobile/base/networking/api/gocast/api_v2.pb.dart'; import 'package:gocast_mobile/models/notifications/push_notification.dart'; import 'package:gocast_mobile/utils/constants.dart'; import 'package:gocast_mobile/views/settings_view/settings_screen_view.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + class NotificationsScreen extends ConsumerWidget { final String title; @@ -39,12 +41,12 @@ class NotificationsScreen extends ConsumerWidget { physics: const AlwaysScrollableScrollPhysics(), scrollDirection: Axis.vertical, children: [ - _buildSectionHeader('Banner Alerts'), + _buildSectionHeader(AppLocalizations.of(context)!.banner_notification), for (var alert in bannerAlerts) _buildBannerAlert(alert), - _buildSectionHeader('Feature Notifications'), + _buildSectionHeader(AppLocalizations.of(context)!.feature_notifications), for (var notification in featureNotifications) _buildFeatureNotification(notification), - _buildSectionHeader('Recent Uploads'), + _buildSectionHeader(AppLocalizations.of(context)!.recent_uploads), for (var notification in pushNotifications) _buildPushNotification(notification), ], @@ -66,12 +68,12 @@ class NotificationsScreen extends ConsumerWidget { MediaQuery.of(context).padding.bottom - kToolbarHeight, ), - child: const IntrinsicHeight( + child: IntrinsicHeight( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( - child: Center(child: Text('No Notifications found.')), + child: Center(child: Text(AppLocalizations.of(context)!.no_notifications_found)), ), ], ), diff --git a/lib/views/on_boarding_view/enable_notification_view.dart b/lib/views/on_boarding_view/enable_notification_view.dart index 67765c99..e6b62868 100644 --- a/lib/views/on_boarding_view/enable_notification_view.dart +++ b/lib/views/on_boarding_view/enable_notification_view.dart @@ -1,4 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + class EnableNotificationscreen extends StatelessWidget { const EnableNotificationscreen({super.key}); @@ -20,20 +22,20 @@ class EnableNotificationscreen extends StatelessWidget { height: 200.0, ), const SizedBox(height: 24), - const Text( - 'Turn on Notifications ?', + Text( + AppLocalizations.of(context)!.turn_on_notifications, textAlign: TextAlign.center, - style: TextStyle( + style: const TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: Colors.black, ), ), const SizedBox(height: 8), - const Text( - "Receive instant updates on live lectures, upcoming quizzes, and important announcements. Never miss a beat in your academic journey.", + Text( + AppLocalizations.of(context)!.notifications_description, textAlign: TextAlign.center, - style: TextStyle( + style: const TextStyle( fontSize: 16, color: Colors.black54, ), @@ -49,16 +51,16 @@ class EnableNotificationscreen extends StatelessWidget { borderRadius: BorderRadius.circular(15.0), ), ), - child: const Text( - 'Enable notifications', - style: TextStyle(fontSize: 18), + child: Text( + AppLocalizations.of(context)!.enable_notifications, + style: const TextStyle(fontSize: 18), ), onPressed: () {}, ), const SizedBox(height: 12), TextButton( child: Text( - 'Skip', + AppLocalizations.of(context)!.skip, style: TextStyle(fontSize: 18, color: Colors.blue[900]), ), onPressed: () {}, diff --git a/lib/views/on_boarding_view/welcome_screen_view.dart b/lib/views/on_boarding_view/welcome_screen_view.dart index 12dafb31..bc96cbe3 100644 --- a/lib/views/on_boarding_view/welcome_screen_view.dart +++ b/lib/views/on_boarding_view/welcome_screen_view.dart @@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:gocast_mobile/providers.dart'; import 'package:gocast_mobile/utils/constants.dart'; import 'package:gocast_mobile/views/login_view/internal_login_view.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; /// Welcome screen view. /// This is the first screen that the user sees when the app is opened. @@ -44,9 +45,9 @@ class WelcomeScreen extends ConsumerWidget { const Spacer(), _buildLogo(screenSize), SizedBox(height: screenSize.height * 0.03), - _buildWelcomeText(), + _buildWelcomeText(context), const SizedBox(height: 8), - _buildOverviewText(), + _buildOverviewText(context), const Spacer(), _buildLoginButton(context, ref), const SizedBox(height: 12), @@ -73,9 +74,9 @@ class WelcomeScreen extends ConsumerWidget { children: [ _buildLogo(screenSize), const SizedBox(height: 24), - _buildWelcomeText(), + _buildWelcomeText(context), const SizedBox(height: 8), - _buildOverviewText(), + _buildOverviewText(context), const SizedBox(height: 48), _buildLoginButton(context, ref), const SizedBox(height: 12), @@ -103,11 +104,11 @@ class WelcomeScreen extends ConsumerWidget { ); } - Widget _buildWelcomeText() { - return const Text( - 'Welcome to Gocast', + Widget _buildWelcomeText(BuildContext context) { + return Text( + AppLocalizations.of(context)!.welcome_to_gocast, textAlign: TextAlign.center, - style: TextStyle( + style: const TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: Color(0xFF0D47A1), @@ -115,11 +116,11 @@ class WelcomeScreen extends ConsumerWidget { ); } - Widget _buildOverviewText() { - return const Text( - "Your Lectures on the Go", + Widget _buildOverviewText(BuildContext context) { + return Text( + AppLocalizations.of(context)!.your_lectures_on_the_go, textAlign: TextAlign.center, - style: TextStyle(fontSize: 16, color: Colors.black54), + style: const TextStyle(fontSize: 16, color: Colors.black54), ); } @@ -143,7 +144,7 @@ class WelcomeScreen extends ConsumerWidget { valueColor: AlwaysStoppedAnimation(Colors.white), ), ) - : const Text('TUM Login', style: TextStyle(fontSize: 18)), + : Text(AppLocalizations.of(context)!.tum_login, style: TextStyle(fontSize: 18)), onPressed: () => handleSSOLogin(context, ref), ); } @@ -159,9 +160,8 @@ class WelcomeScreen extends ConsumerWidget { shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.0)), ), - child: const Text('Continue without', style: TextStyle(fontSize: 18)), + child: Text(AppLocalizations.of(context)!.continue_without, style: TextStyle(fontSize: 18)), onPressed: () { - //TODO: Continue without login action Navigator.pushNamed(context, '/publiccourses'); }, ); @@ -173,10 +173,10 @@ class WelcomeScreen extends ConsumerWidget { context, MaterialPageRoute(builder: (context) => const InternalLoginScreen()), ), - child: const Center( + child: Center( child: Text( - 'Use an internal account', - style: TextStyle( + AppLocalizations.of(context)!.use_an_internal_account, + style: const TextStyle( decoration: TextDecoration.underline, color: Colors.grey, decorationColor: Colors.grey, diff --git a/lib/views/settings_view/custom_playback_speed_view.dart b/lib/views/settings_view/custom_playback_speed_view.dart index b5b0dae8..ce39776f 100644 --- a/lib/views/settings_view/custom_playback_speed_view.dart +++ b/lib/views/settings_view/custom_playback_speed_view.dart @@ -21,12 +21,12 @@ void showAddCustomSpeedDialog( List splitValue = value.split('.'); if ((splitValue[0].length > 1) || (splitValue.length > 1 && splitValue[1].length > 2)) { - errorMessage = 'Number is too long'; + errorMessage = AppLocalizations.of(context)!.number_too_long; } else { customSpeed = parsedValue; } } else { - errorMessage = 'Please enter a number between\n0.25 and 2.0'; + errorMessage = AppLocalizations.of(context)!.enter_number_between; } } } diff --git a/lib/views/settings_view/edit_profile_screen_view.dart b/lib/views/settings_view/edit_profile_screen_view.dart index c99e8afe..91da3ef3 100644 --- a/lib/views/settings_view/edit_profile_screen_view.dart +++ b/lib/views/settings_view/edit_profile_screen_view.dart @@ -78,7 +78,7 @@ class EditProfileScreenState extends ConsumerState { ), children: [ TextSpan( - text: AppLocalizations.of(context)!.change_limitation_detail, + text: AppLocalizations.of(context)!.name_change_limitation, style: const TextStyle( fontStyle: FontStyle.italic, fontWeight: FontWeight.bold, @@ -137,7 +137,7 @@ class EditProfileScreenState extends ConsumerState { isError = false; }); } else { - _showErrorDialog('Preferred name can only be changed every 3 months'); + _showErrorDialog('3 months'); } } catch (e) { _showErrorDialog('An error occurred'); @@ -151,7 +151,7 @@ class EditProfileScreenState extends ConsumerState { return AlertDialog( backgroundColor: Theme.of(context).colorScheme.onPrimary, title: const Text("Error"), - content: Text(errorMessage), + content: Text(errorMessage== '3 months' ? AppLocalizations.of(context)!.name_change_limitation : errorMessage), actions: [ TextButton( child: const Text("OK"), diff --git a/lib/views/settings_view/playback_speed_picker_view.dart b/lib/views/settings_view/playback_speed_picker_view.dart index 8bb39679..b13e0f82 100644 --- a/lib/views/settings_view/playback_speed_picker_view.dart +++ b/lib/views/settings_view/playback_speed_picker_view.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + void showPlaybackSpeedsPicker( BuildContext context, @@ -43,11 +45,11 @@ void showPlaybackSpeedsPicker( if (selectedSpeeds .any((speed) => !defaultSpeeds.contains(speed))) ...[ const Divider(), - const Padding( - padding: EdgeInsets.all(8.0), + Padding( + padding: const EdgeInsets.all(8.0), child: Text( - 'Custom Playback Speeds', - style: TextStyle(fontWeight: FontWeight.bold), + AppLocalizations.of(context)!.custom_playback_speed, + style: const TextStyle(fontWeight: FontWeight.bold), ), ), for (var speed in selectedSpeeds diff --git a/lib/views/settings_view/playback_speed_settings_view.dart b/lib/views/settings_view/playback_speed_settings_view.dart index 3280e963..5a96a4ac 100644 --- a/lib/views/settings_view/playback_speed_settings_view.dart +++ b/lib/views/settings_view/playback_speed_settings_view.dart @@ -5,6 +5,7 @@ import 'package:gocast_mobile/base/networking/api/gocast/api_v2.pb.dart'; import 'package:gocast_mobile/views/settings_view/playback_speed_picker_view.dart'; import 'package:gocast_mobile/views/settings_view/custom_playback_speed_view.dart'; import 'package:gocast_mobile/views/settings_view/authentication_error_card_view.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class PlaybackSpeedSettings extends ConsumerWidget { const PlaybackSpeedSettings({super.key}); @@ -29,7 +30,7 @@ class PlaybackSpeedSettings extends ConsumerWidget { List playbackSpeeds, ) { return ListTile( - title: const Text('Playback Speeds'), + title: Text(AppLocalizations.of(context)!.playback_speed), trailing: const Icon(Icons.arrow_forward_ios), onTap: () => showPlaybackSpeedsPicker( context, @@ -44,7 +45,7 @@ class PlaybackSpeedSettings extends ConsumerWidget { ListTile _buildCustomPlaybackSpeedsTile(BuildContext context, WidgetRef ref) { return ListTile( - title: const Text('Add Custom Playback Speed'), + title: Text(AppLocalizations.of(context)!.add_custom_playback_speed), onTap: () { showAddCustomSpeedDialog(context, (double customSpeed) { _updateSelectedSpeeds(context, ref, customSpeed, true); diff --git a/lib/views/settings_view/preferred_greeting_view.dart b/lib/views/settings_view/preferred_greeting_view.dart index f752c875..2c67a654 100644 --- a/lib/views/settings_view/preferred_greeting_view.dart +++ b/lib/views/settings_view/preferred_greeting_view.dart @@ -3,6 +3,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:gocast_mobile/providers.dart'; import 'package:gocast_mobile/base/networking/api/gocast/api_v2.pb.dart'; import 'package:gocast_mobile/views/settings_view/authentication_error_card_view.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + class PreferredGreetingView extends ConsumerWidget { const PreferredGreetingView({super.key}); @@ -19,7 +21,7 @@ class PreferredGreetingView extends ConsumerWidget { 'Default Greeting'; return ListTile( - title: const Text('Preferred Greeting'), + title: Text(AppLocalizations.of(context)!.preferred_greeting), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ diff --git a/lib/views/settings_view/settings_screen_view.dart b/lib/views/settings_view/settings_screen_view.dart index 54bf3e1b..ce3320e6 100644 --- a/lib/views/settings_view/settings_screen_view.dart +++ b/lib/views/settings_view/settings_screen_view.dart @@ -8,6 +8,8 @@ import 'package:gocast_mobile/views/settings_view/edit_profile_screen_view.dart' import 'package:gocast_mobile/base/networking/api/gocast/api_v2.pb.dart'; import 'package:gocast_mobile/views/settings_view/authentication_error_card_view.dart'; import 'package:url_launcher/url_launcher.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + class SettingsScreen extends ConsumerStatefulWidget { const SettingsScreen({super.key}); @@ -45,8 +47,8 @@ class _SettingsScreenState extends ConsumerState { children: [ _buildProfileTile(userState), const Divider(), - _buildSectionTitle('Account Settings'), - _buildEditableListTile('Edit profile', () async { + _buildSectionTitle(AppLocalizations.of(context)!.account_settings), + _buildEditableListTile(AppLocalizations.of(context)!.edit_profile, () async { bool isAuthenticated = await showAuthenticationErrorCard(context, ref); if (isAuthenticated && mounted) { @@ -59,7 +61,7 @@ class _SettingsScreenState extends ConsumerState { }), const PreferredGreetingView(), _buildSwitchListTile( - title: 'Push notifications', + title: AppLocalizations.of(context)!.push_notifications, value: settingState.isPushNotificationsEnabled, onChanged: (value) { ref @@ -70,7 +72,7 @@ class _SettingsScreenState extends ConsumerState { ), _buildThemeSelectionTile(context, ref), _buildSwitchListTile( - title: 'Download Over Wi-Fi only', + title: AppLocalizations.of(context)!.download_over_wifi_only, value: settingState.isDownloadWithWifiOnly, onChanged: (value) { ref @@ -79,18 +81,18 @@ class _SettingsScreenState extends ConsumerState { }, ref: ref, ), - _buildSectionTitle('Video Playback Speed'), + _buildSectionTitle(AppLocalizations.of(context)!.playback_speed), const PlaybackSpeedSettings(), _buildLogoutTile(context), const Divider(), - _buildSectionTitle('More'), - _buildNavigableListTile('About us', ""), + _buildSectionTitle(AppLocalizations.of(context)!.more), + _buildNavigableListTile(AppLocalizations.of(context)!.about_us, ""), _buildNavigableListTile( - 'Privacy policy', + AppLocalizations.of(context)!.privacy_policy, "https://live.rbg.tum.de/privacy", ), _buildNavigableListTile( - 'Terms and conditions', + AppLocalizations.of(context)!.terms_and_conditions, "https://live.rbg.tum.de/imprint", ), ], @@ -102,7 +104,7 @@ class _SettingsScreenState extends ConsumerState { AppBar _buildAppBar(BuildContext context) { return AppBar( - title: const Text('Settings'), + title: Text(AppLocalizations.of(context)!.settings), leading: IconButton( icon: !_isTablet(context) ? const Icon(Icons.arrow_back_ios) @@ -118,15 +120,15 @@ class _SettingsScreenState extends ConsumerState { String themeModeText; if (settingState.isDarkMode) { - themeModeText = 'Dark Mode'; + themeModeText = AppLocalizations.of(context)!.dark; } else if (settingState.isLightMode) { - themeModeText = 'Light Mode'; + themeModeText = AppLocalizations.of(context)!.light; } else { - themeModeText = 'System Default'; + themeModeText = AppLocalizations.of(context)!.system_default; } return ListTile( - title: const Text('Choose Theme'), + title: Text(AppLocalizations.of(context)!.choose_theme), subtitle: Text(themeModeText), trailing: const Icon(Icons.arrow_forward_ios), onTap: () => _showThemeSelectionSheet(context, ref), @@ -141,7 +143,7 @@ class _SettingsScreenState extends ConsumerState { child: Wrap( children: [ ListTile( - title: const Text('System Default'), + title: Text(AppLocalizations.of(context)!.system_default), onTap: () { ref .read(settingViewModelProvider.notifier) @@ -150,7 +152,7 @@ class _SettingsScreenState extends ConsumerState { }, ), ListTile( - title: const Text('Dark Mode'), + title: Text(AppLocalizations.of(context)!.dark), onTap: () { ref .read(settingViewModelProvider.notifier) @@ -159,7 +161,7 @@ class _SettingsScreenState extends ConsumerState { }, ), ListTile( - title: const Text('Light Mode'), + title: Text(AppLocalizations.of(context)!.light), onTap: () { ref .read(settingViewModelProvider.notifier) @@ -237,7 +239,7 @@ class _SettingsScreenState extends ConsumerState { ListTile _buildLogoutTile(BuildContext context) { return ListTile( title: Text( - 'Log out', + AppLocalizations.of(context)!.logout, style: TextStyle(color: Theme.of(context).colorScheme.error), ), onTap: () => _showLogoutDialog(context), @@ -252,18 +254,18 @@ class _SettingsScreenState extends ConsumerState { context: context, builder: (BuildContext context) { return AlertDialog( - title: const Text('Log Out'), - content: const Text('Would you like to delete all your downloads?'), + title: Text(AppLocalizations.of(context)!.logout), + content: Text(AppLocalizations.of(context)!.logout_message), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(false), // User chooses not to delete downloads - child: const Text('No'), + child: Text(AppLocalizations.of(context)!.no), ), TextButton( onPressed: () => Navigator.of(context).pop(true), // User chooses to delete downloads - child: const Text('Yes'), + child: Text(AppLocalizations.of(context)!.yes), ), ], );