Search code examples
flutterfirebase-authenticationlocalizationfirebaseui

Make flutterfire_ui show some screens in ltr direction rather than locale rtl direction?


I am using a flutterfire_ui package to manage the sign in process with phone authentication. When a user signs with phone he/she will be required to enter: a country code, a phone number and an OTP. The screens will use the default direction based on the app locale.

I am declaring the app locale as Arabic. Now although Arabic is an rtl language, still the country code, the phone numbers and the OTP will need to be displayed and entered in an ltr direction since they are all numbers. The screens that flutterfire_ui provides displays those in rtl direction.

What do you suggest as a minimalist approach to override this behaviour and specify a direction for those screens?

  1. Screen snapshots to show current behaviour:
    1. Screen for entering phone number with 'ar' as locale. Default direction set to rtl
    2. Screen for entering OTP with 'ar' as locale. Default direction set to rtl
  2. Screen snapshots to show desired behaviour:
    1. Screen for entering phone number with 'en' as locale. Default direction set to ltr
    2. Screen for entering OTP with 'en' as locale. Default direction set to ltr

Here is minimum code to reproduce the issue.

import 'package:flutter/material.dart';
import 'package:flutterfire_ui/auth.dart';
import 'package:flutterfire_ui/i10n.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'myapp',
      locale: const Locale('ar', 'SA'),
      supportedLocales: [const Locale('ar', 'SA')],
      localizationsDelegates: [
        FlutterFireUILocalizations.delegate,
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
      ],
      home: const LoginScreen(),
    );
  }
}

class LoginScreen extends StatelessWidget {
  const LoginScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const SignInScreen(
        providerConfigs: [
          PhoneProviderConfiguration(),
        ],
      );
  }
}

Solution

  • This doesn't totally solve the issue but it is an acceptable-ish workaround.

    I converted the locale back to 'en' and supplied the localizationsDelegates with overwritten labels in Arabic. This will make the sign-in screens look more acceptable.

    If you are applying this workaround just take an extra care as this change may impact the rest of your app. in my case it didn't have an overall impact on the rest of the app as each widget has its styles hardcoded.

    Here are the changes needed to be applied on the code:

    1. Change locale to 'en'
    locale: const Locale('en', 'SA'),
    supportedLocales: [const Locale('en', 'SA')],
    
    1. Modify localizationDelegates as follows
    localizationsDelegates: [
       FlutterFireUILocalizations.withDefaultOverrides(const LabelOverrides()),
       GlobalMaterialLocalizations.delegate,
       GlobalWidgetsLocalizations.delegate,
       FlutterFireUILocalizations.delegate,
    ],
    
    1. Added LabelOverrides
    class LabelOverrides extends DefaultLocalizations {
      @override
      final String emailInputLabel;
      @override
      final String passwordInputLabel;
      @override
      final String signInActionText;
      @override
      final String registerActionText;
      @override
      final String linkEmailButtonText;
      @override
      final String signInButtonText;
      @override
      final String registerButtonText;
      @override
      final String signInWithPhoneButtonText;
      @override
      final String signInWithGoogleButtonText;
      @override
      final String signInWithAppleButtonText;
      @override
      final String signInWithFacebookButtonText;
      @override
      final String signInWithTwitterButtonText;
      @override
      final String phoneVerificationViewTitleText;
      @override
      final String verifyPhoneNumberButtonText;
      @override
      final String verifyCodeButtonText;
      @override
      final String verifyingPhoneNumberViewTitle;
      @override
      final String unknownError;
      @override
      final String smsAutoresolutionFailedError;
      @override
      final String smsCodeSentText;
      @override
      final String sendingSMSCodeText;
      @override
      final String verifyingSMSCodeText;
      @override
      final String enterSMSCodeText;
      @override
      final String emailIsRequiredErrorText;
      @override
      final String isNotAValidEmailErrorText;
      @override
      final String userNotFoundErrorText;
      @override
      final String emailTakenErrorText;
      @override
      final String accessDisabledErrorText;
      @override
      final String wrongOrNoPasswordErrorText;
      @override
      final String signInText;
      @override
      final String registerText;
      @override
      final String registerHintText;
      @override
      final String signInHintText;
      @override
      final String signOutButtonText;
      @override
      final String phoneInputLabel;
      @override
      final String phoneNumberIsRequiredErrorText;
      @override
      final String phoneNumberInvalidErrorText;
      @override
      final String profile;
      @override
      final String name;
      @override
      final String deleteAccount;
      @override
      final String passwordIsRequiredErrorText;
      @override
      final String confirmPasswordIsRequiredErrorText;
      @override
      final String confirmPasswordDoesNotMatchErrorText;
      @override
      final String confirmPasswordInputLabel;
      @override
      final String forgotPasswordButtonLabel;
      @override
      final String forgotPasswordViewTitle;
      @override
      final String resetPasswordButtonLabel;
      @override
      final String verifyItsYouText;
      @override
      final String differentMethodsSignInTitleText;
      @override
      final String findProviderForEmailTitleText;
      @override
      final String continueText;
      @override
      final String countryCode;
      @override
      final String codeRequiredErrorText;
      @override
      final String invalidCountryCode;
      @override
      final String chooseACountry;
      @override
      final String enableMoreSignInMethods;
      @override
      final String signInMethods;
      @override
      final String provideEmail;
      @override
      final String goBackButtonLabel;
      @override
      final String passwordResetEmailSentText;
      @override
      final String forgotPasswordHintText;
      @override
      final String emailLinkSignInButtonLabel;
      @override
      final String signInWithEmailLinkViewTitleText;
      @override
      final String signInWithEmailLinkSentText;
      @override
      final String sendLinkButtonLabel;
      @override
      final String arrayLabel;
      @override
      final String booleanLabel;
      @override
      final String mapLabel;
      @override
      final String nullLabel;
      @override
      final String numberLabel;
      @override
      final String stringLabel;
      @override
      final String typeLabel;
      @override
      final String valueLabel;
      @override
      final String cancelLabel;
      @override
      final String updateLabel;
      @override
      final String northInitialLabel;
      @override
      final String southInitialLabel;
      @override
      final String westInitialLabel;
      @override
      final String eastInitialLabel;
      @override
      final String timestampLabel;
      @override
      final String latitudeLabel;
      @override
      final String longitudeLabel;
      @override
      final String geopointLabel;
      @override
      final String referenceLabel;
    
      const LabelOverrides({
        this.emailInputLabel = 'البريد الإلكتروني',
        this.passwordInputLabel = 'كلمة المرور',
        this.signInActionText = 'تسجيل الدخول',
        this.registerActionText = 'تسجيل جديد',
        this.signInButtonText = 'تسجيل الدخول',
        this.registerButtonText = 'تسجيل جديد',
        this.linkEmailButtonText = 'التالي',
        this.signInWithPhoneButtonText = 'تسجيل الدخول برقم الهاتف',
        this.signInWithGoogleButtonText = 'تسجيل الدخول باستخدام Google',
        this.signInWithAppleButtonText = 'تسجيل الدخول باستخدام Apple',
        this.signInWithTwitterButtonText = 'تسجيل الدخول باستخدام Twitter',
        this.signInWithFacebookButtonText = 'تسجيل الدخول باستخدام Facebook',
        this.phoneVerificationViewTitleText = 'أدخل رقم هاتفك',
        this.verifyPhoneNumberButtonText = 'التالي',
        this.verifyCodeButtonText = 'تحقق',
        this.verifyingPhoneNumberViewTitle = 'أدخل رمز التحقق المرسل برسالة نصية',
        this.unknownError = 'حدث خطأ غير متوقع',
        this.smsAutoresolutionFailedError = 'حدث خطأ أثناء محاولة قراءة الرمز تلقائياً. رجاءً قم بإدخاله يدوياً',
        this.smsCodeSentText = 'تم إرسال رمز التحقق برسالة نصية',
        this.sendingSMSCodeText = 'جاري إرسال الرمز برسالة نصية...',
        this.verifyingSMSCodeText = 'جاري التحقق من الرمز المرسل...',
        this.enterSMSCodeText = 'أدخل الرمز المرسل',
        this.emailIsRequiredErrorText = 'البريد الإلكتروني مطلوب',
        this.isNotAValidEmailErrorText = 'رجاء قم بإدخال بريد إلكتروني صالح',
        this.userNotFoundErrorText = 'هذا الحساب غير موجود',
        this.emailTakenErrorText = 'هذا البريد الإلكتروني مستخدم مسبقاً',
        this.accessDisabledErrorText = 'تم تعطيل الوصول إلى هذا الحساب مؤقتًا',
        this.wrongOrNoPasswordErrorText = 'كلمة المرور غير صالحة أو أن هذا المستخدم ليس لديه كلمة مرور',
        this.signInText = 'تسجيل الدخول',
        this.registerText = 'إنشاء حساب',
        this.registerHintText = 'ليس لديك حساب مسبقا؟',
        this.signInHintText = 'لديك حساب مسبقا؟',
        this.signOutButtonText = 'تسجيل الخروج',
        this.phoneInputLabel = 'رقم الهاتف',
        this.phoneNumberInvalidErrorText = 'رقم الهاتف المدخل غير صالح',
        this.phoneNumberIsRequiredErrorText = 'رقم الهاتف مطلوب',
        this.profile = 'الملف الشخصي',
        this.name = 'الاسم',
        this.deleteAccount = 'حذف الحساب',
        this.passwordIsRequiredErrorText = 'كلمة المرور مطلوبة',
        this.confirmPasswordIsRequiredErrorText = 'قم بتأكيد كلمة مرورك',
        this.confirmPasswordDoesNotMatchErrorText = 'كلمات المرور المدخلة غير متطابقة',
        this.confirmPasswordInputLabel = 'تأكيد كلمة المرور',
        this.forgotPasswordButtonLabel = 'نسيت كلمة المرور؟',
        this.forgotPasswordViewTitle = 'استرجاع كلمة المرور المنسية',
        this.resetPasswordButtonLabel = 'إعادة تعيين كلمة المرور',
        this.verifyItsYouText = 'تحقق من هويتك',
        this.differentMethodsSignInTitleText = 'استخدم إحدى الطرق التالية لتسجيل الدخول',
        this.findProviderForEmailTitleText = 'أدخل بريدك الإلكتروني للمتابعة',
        this.continueText = 'استمرار',
        this.countryCode = 'رمز الدولة',
        this.codeRequiredErrorText = 'رمز الدولة مطلوب',
        this.invalidCountryCode = 'رمز الدولة هذا غير صالح',
        this.chooseACountry = 'اختر الدولة',
        this.enableMoreSignInMethods = 'تفعيل المزيد من طرق تسجيل الدخول',
        this.signInMethods = 'طرق تسجيل الدخول',
        this.provideEmail = 'أدخل بريدك الإلكتروني وكلمة المرور',
        this.goBackButtonLabel = 'رجوع',
        this.passwordResetEmailSentText = 'لقد أرسلنا إليك بريدًا إلكترونيًا يحتوي على رابط لإعادة تعيين كلمة المرور الخاصة بك. من فضلك تفقد بريدك الالكتروني',
        this.forgotPasswordHintText = 'أدخل بريدك الإلكتروني وسنرسل لك رابطًا لإعادة تعيين كلمة مرورك',
        this.emailLinkSignInButtonLabel = 'تسجيل الدخول عن طريق الرابط',
        this.signInWithEmailLinkViewTitleText = 'تسجيل الدخول عن طريق الرابط',
        this.signInWithEmailLinkSentText = 'لقد أرسلنا رابط تسجيل الدخول إلى بريدك الإلكتروني. تفقد صندوق رسائلك واضغط على الرابط لتسجيل الدخول',
        this.sendLinkButtonLabel = 'أرسل رابط تسجيل الدخول',
        this.arrayLabel = 'مصفوفة',
        this.booleanLabel = 'قيمة منطقية',
        this.mapLabel = 'كائن',
        this.nullLabel = 'بدون قيمة',
        this.numberLabel = 'رقم',
        this.stringLabel = 'نص',
        this.typeLabel = 'نوع',
        this.valueLabel = 'قيمة',
        this.cancelLabel = 'إلغاء',
        this.updateLabel = 'تحديث',
        this.northInitialLabel = 'شمال',
        this.southInitialLabel = 'جنوب',
        this.westInitialLabel = 'غرب',
        this.eastInitialLabel = 'شرق',
        this.timestampLabel = 'طابع زمني',
        this.longitudeLabel = 'خط الطول',
        this.latitudeLabel = 'خط العرض',
        this.geopointLabel = 'نقطة جغرافية',
        this.referenceLabel = 'مرجع',
      });
    }