From 06b3894249c14610c71d565cff1634b4ebb75326 Mon Sep 17 00:00:00 2001 From: fufesou Date: Fri, 19 Jan 2024 23:36:32 -0800 Subject: [PATCH] Refact/verification code input check (#6924) * Refact, login verification code, input check Signed-off-by: fufesou * Refact, settings, enable 2fa, dialog input Signed-off-by: fufesou * Refact. Connect, 2fa code, input check Signed-off-by: fufesou * refact, 2Fa text field, input formatter, only digits Signed-off-by: fufesou * refact, error message Signed-off-by: fufesou --------- Signed-off-by: fufesou --- flutter/lib/common/widgets/dialog.dart | 332 +++++++++++++++++++++---- flutter/lib/common/widgets/login.dart | 53 ++-- src/lang/ar.rs | 2 + src/lang/ca.rs | 2 + src/lang/cn.rs | 2 + src/lang/cs.rs | 2 + src/lang/da.rs | 2 + src/lang/de.rs | 2 + src/lang/el.rs | 2 + src/lang/eo.rs | 2 + src/lang/es.rs | 2 + src/lang/et.rs | 2 + src/lang/fa.rs | 2 + src/lang/fr.rs | 2 + src/lang/hu.rs | 2 + src/lang/id.rs | 2 + src/lang/it.rs | 2 + src/lang/ja.rs | 2 + src/lang/ko.rs | 2 + src/lang/kz.rs | 2 + src/lang/lt.rs | 2 + src/lang/lv.rs | 2 + src/lang/nb.rs | 2 + src/lang/nl.rs | 2 + src/lang/pl.rs | 2 + src/lang/pt_PT.rs | 2 + src/lang/ptbr.rs | 2 + src/lang/ro.rs | 2 + src/lang/ru.rs | 2 + src/lang/sk.rs | 2 + src/lang/sl.rs | 2 + src/lang/sq.rs | 2 + src/lang/sr.rs | 2 + src/lang/sv.rs | 2 + src/lang/template.rs | 2 + src/lang/th.rs | 2 + src/lang/tr.rs | 2 + src/lang/tw.rs | 2 + src/lang/ua.rs | 2 + src/lang/vn.rs | 2 + 40 files changed, 374 insertions(+), 87 deletions(-) diff --git a/flutter/lib/common/widgets/dialog.dart b/flutter/lib/common/widgets/dialog.dart index 95877cbfd..5fe3bdefb 100644 --- a/flutter/lib/common/widgets/dialog.dart +++ b/flutter/lib/common/widgets/dialog.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:io'; +import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -362,6 +363,7 @@ class DialogTextField extends StatelessWidget { final Widget? suffixIcon; final TextEditingController controller; final FocusNode? focusNode; + final List? inputFormatters; static const kUsernameTitle = 'Username'; static const kUsernameIcon = Icon(Icons.account_circle_outlined); @@ -377,6 +379,7 @@ class DialogTextField extends StatelessWidget { this.prefixIcon, this.suffixIcon, this.hintText, + this.inputFormatters, required this.title, required this.controller}) : super(key: key); @@ -401,6 +404,7 @@ class DialogTextField extends StatelessWidget { focusNode: focusNode, autofocus: true, obscureText: obscureText, + inputFormatters: inputFormatters, ), ), ], @@ -408,6 +412,241 @@ class DialogTextField extends StatelessWidget { } } +abstract class ValidationField extends StatelessWidget { + ValidationField({Key? key}) : super(key: key); + + String? validate(); + bool get isReady; +} + +class Dialog2FaField extends ValidationField { + Dialog2FaField({ + Key? key, + required this.controller, + this.autoFocus = true, + this.reRequestFocus = false, + this.title, + this.helperText, + this.hintText, + this.errorText, + this.readyCallback, + this.onChanged, + }) : super(key: key); + + final TextEditingController controller; + final bool autoFocus; + final bool reRequestFocus; + final String? title; + final String? helperText; + final String? hintText; + final String? errorText; + final VoidCallback? readyCallback; + final VoidCallback? onChanged; + final errMsg = translate('2FA code must be 6 digits.'); + + @override + Widget build(BuildContext context) { + return DialogVerificationCodeField( + title: title ?? translate('2FA code'), + controller: controller, + errorText: errorText, + autoFocus: autoFocus, + reRequestFocus: reRequestFocus, + hintText: hintText, + readyCallback: readyCallback, + helperText: helperText ?? translate('2fa_tip'), + onChanged: _onChanged, + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp(r'[0-9]')), + ], + ); + } + + String get text => controller.text; + bool get isAllDigits => text.codeUnits.every((e) => e >= 48 && e <= 57); + + @override + bool get isReady => text.length == 6 && isAllDigits; + + @override + String? validate() => isReady ? null : errMsg; + + _onChanged(StateSetter setState, SimpleWrapper errText) { + onChanged?.call(); + + if (text.length > 6) { + setState(() => errText.value = errMsg); + return; + } + + if (!isAllDigits) { + setState(() => errText.value = errMsg); + return; + } + + if (isReady) { + readyCallback?.call(); + return; + } + + if (errText.value != null) { + setState(() => errText.value = null); + } + } +} + +class DialogEmailCodeField extends ValidationField { + DialogEmailCodeField({ + Key? key, + required this.controller, + this.autoFocus = true, + this.reRequestFocus = false, + this.hintText, + this.errorText, + this.readyCallback, + this.onChanged, + }) : super(key: key); + + final TextEditingController controller; + final bool autoFocus; + final bool reRequestFocus; + final String? hintText; + final String? errorText; + final VoidCallback? readyCallback; + final VoidCallback? onChanged; + final errMsg = translate('Email verification code must be 6 characters.'); + + @override + Widget build(BuildContext context) { + return DialogVerificationCodeField( + title: translate('Verification code'), + controller: controller, + errorText: errorText, + autoFocus: autoFocus, + reRequestFocus: reRequestFocus, + hintText: hintText, + readyCallback: readyCallback, + helperText: translate('verification_tip'), + onChanged: _onChanged, + ); + } + + String get text => controller.text; + + @override + bool get isReady => text.length == 6; + + @override + String? validate() => isReady ? null : errMsg; + + _onChanged(StateSetter setState, SimpleWrapper errText) { + onChanged?.call(); + + if (text.length > 6) { + setState(() => errText.value = errMsg); + return; + } + + if (isReady) { + readyCallback?.call(); + return; + } + + if (errText.value != null) { + setState(() => errText.value = null); + } + } +} + +class DialogVerificationCodeField extends StatefulWidget { + DialogVerificationCodeField({ + Key? key, + required this.controller, + required this.title, + this.autoFocus = true, + this.reRequestFocus = false, + this.helperText, + this.hintText, + this.errorText, + this.textLength, + this.readyCallback, + this.onChanged, + this.inputFormatters, + }) : super(key: key); + + final TextEditingController controller; + final bool autoFocus; + final bool reRequestFocus; + final String title; + final String? helperText; + final String? hintText; + final String? errorText; + final int? textLength; + final VoidCallback? readyCallback; + final Function(StateSetter setState, SimpleWrapper errText)? + onChanged; + final List? inputFormatters; + + @override + State createState() => + _DialogVerificationCodeField(); +} + +class _DialogVerificationCodeField extends State { + final _focusNode = FocusNode(); + Timer? _timer; + Timer? _timerReRequestFocus; + SimpleWrapper errorText = SimpleWrapper(null); + + @override + void initState() { + super.initState(); + if (widget.autoFocus) { + _timer = + Timer(Duration(milliseconds: 50), () => _focusNode.requestFocus()); + + if (widget.onChanged != null) { + widget.controller.addListener(() { + widget.onChanged!(setState, errorText); + }); + } + } + + // software secure keyboard will take the focus since flutter 3.13 + // request focus again when android account password obtain focus + if (Platform.isAndroid && widget.reRequestFocus) { + _focusNode.addListener(() { + if (_focusNode.hasFocus) { + _timerReRequestFocus?.cancel(); + _timerReRequestFocus = Timer( + Duration(milliseconds: 100), () => _focusNode.requestFocus()); + } + }); + } + } + + @override + void dispose() { + _timer?.cancel(); + _timerReRequestFocus?.cancel(); + _focusNode.unfocus(); + _focusNode.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return DialogTextField( + title: widget.title, + controller: widget.controller, + errorText: widget.errorText ?? errorText.value, + focusNode: _focusNode, + helperText: widget.helperText, + inputFormatters: widget.inputFormatters, + ); + } +} + class PasswordWidget extends StatefulWidget { PasswordWidget({ Key? key, @@ -1512,9 +1751,31 @@ void change2fa({Function()? callback}) async { var new2fa = (await bind.mainGenerate2Fa()); final secretRegex = RegExp(r'secret=([^&]+)'); final secret = secretRegex.firstMatch(new2fa)?.group(1); - var msg = ''.obs; - final RxString code = "".obs; + String? errorText; + final controller = TextEditingController(); gFFI.dialogManager.show((setState, close, context) { + onVerify() async { + if (await bind.mainVerify2Fa(code: controller.text.trim())) { + callback?.call(); + close(); + } else { + errorText = translate('wrong-2fa-code'); + } + } + + final codeField = Dialog2FaField( + controller: controller, + errorText: errorText, + onChanged: () => setState(() => errorText = null), + title: translate('Verification code'), + readyCallback: () { + onVerify(); + setState(() {}); + }, + ); + + getOnSubmit() => codeField.isReady ? onVerify : null; + return CustomAlertDialog( title: Text(translate("enable-2fa-title")), content: Column( @@ -1535,36 +1796,12 @@ void change2fa({Function()? callback}) async { )).marginOnly(bottom: 6), SelectableText(secret ?? '', style: TextStyle(fontSize: 12)) .marginOnly(bottom: 12), - Row(children: [ - Expanded( - child: Obx(() => TextField( - decoration: InputDecoration( - errorText: - msg.value.isEmpty ? null : translate(msg.value), - hintText: translate("Verification code")), - onChanged: (value) { - code.value = value; - msg.value = ''; - }, - autofocus: true))) - ]), + Row(children: [Expanded(child: codeField)]), ], ), actions: [ dialogButton("Cancel", onPressed: close, isOutline: true), - Obx(() => dialogButton( - "OK", - onPressed: code.value.trim().length == 6 - ? () async { - if (await bind.mainVerify2Fa(code: code.value.trim())) { - callback?.call(); - close(); - } else { - msg.value = translate('wrong-2fa-code'); - } - } - : null, - )), + dialogButton("OK", onPressed: getOnSubmit()), ], onCancel: close, ); @@ -1573,7 +1810,9 @@ void change2fa({Function()? callback}) async { void enter2FaDialog( SessionID sessionId, OverlayDialogManager dialogManager) async { - final RxString code = "".obs; + final controller = TextEditingController(); + final RxBool submitReady = false.obs; + dialogManager.dismissAll(); dialogManager.show((setState, close, context) { cancel() { @@ -1582,34 +1821,23 @@ void enter2FaDialog( } submit() { - if (code.value.trim().length != 6) { - return; - } - gFFI.send2FA(sessionId, code.value.trim()); + gFFI.send2FA(sessionId, controller.text.trim()); close(); dialogManager.showLoading(translate('Logging in...'), onCancel: closeConnection); } + late Dialog2FaField codeField; + + codeField = Dialog2FaField( + controller: controller, + title: translate('Verification code'), + onChanged: () => submitReady.value = codeField.isReady, + ); + return CustomAlertDialog( - title: Text(translate("enter-2fa-title")), - content: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row(children: [ - Expanded( - child: TextField( - decoration: InputDecoration( - hintText: translate("Verification code")), - onChanged: (value) { - code.value = value; - }, - autofocus: true)) - ]), - ], - ), - onSubmit: submit, - onCancel: cancel, + title: Text(translate('enter-2fa-title')), + content: codeField, actions: [ dialogButton( 'Cancel', @@ -1618,7 +1846,7 @@ void enter2FaDialog( ), Obx(() => dialogButton( 'OK', - onPressed: code.value.trim().length == 6 ? submit : null, + onPressed: submitReady.isTrue ? submit : null, )), ]); }); diff --git a/flutter/lib/common/widgets/login.dart b/flutter/lib/common/widgets/login.dart index fc4f80e96..64ea188a0 100644 --- a/flutter/lib/common/widgets/login.dart +++ b/flutter/lib/common/widgets/login.dart @@ -615,23 +615,11 @@ Future verificationCodeDialog( var autoLogin = true; var isInProgress = false; String? errorText; - String preCode = ''; final code = TextEditingController(); - final focusNode = FocusNode()..requestFocus(); - Timer(Duration(milliseconds: 100), () => focusNode..requestFocus()); final res = await gFFI.dialogManager.show((setState, close, context) { - bool validate() { - return code.text.length >= 6; - } - void onVerify() async { - if (!validate()) { - setState( - () => errorText = translate('Too short, at least 6 characters.')); - return; - } setState(() => isInProgress = true); try { @@ -666,18 +654,21 @@ Future verificationCodeDialog( setState(() => isInProgress = false); } - code.addListener(() { - if (errorText != null) { - setState(() => errorText = null); - } - if (preCode.length != 6 && code.text.length == 6) { - onVerify(); - } - if (!isEmailVerification && preCode.length != 10 && code.text.length == 10) { - onVerify(); - } - preCode = code.text; - }); + final codeField = isEmailVerification + ? DialogEmailCodeField( + controller: code, + errorText: errorText, + readyCallback: onVerify, + onChanged: () => errorText = null, + ) + : Dialog2FaField( + controller: code, + errorText: errorText, + readyCallback: onVerify, + onChanged: () => errorText = null, + ); + + getOnSubmit() => codeField.isReady ? onVerify : null; return CustomAlertDialog( title: Text(translate("Verification code")), @@ -693,15 +684,7 @@ Future verificationCodeDialog( controller: TextEditingController(text: user?.email), )), isEmailVerification ? const SizedBox(height: 8) : const Offstage(), - DialogTextField( - title: - '${translate(isEmailVerification ? "Verification code" : "2FA code")}:', - controller: code, - errorText: errorText, - focusNode: focusNode, - helperText: translate( - isEmailVerification ? 'verification_tip' : '2fa_tip'), - ), + codeField, /* CheckboxListTile( contentPadding: const EdgeInsets.all(0), @@ -722,10 +705,10 @@ Future verificationCodeDialog( ], ), onCancel: close, - onSubmit: onVerify, + onSubmit: getOnSubmit(), actions: [ dialogButton("Cancel", onPressed: close, isOutline: true), - dialogButton("Verify", onPressed: onVerify), + dialogButton("Verify", onPressed: getOnSubmit()), ]); }); diff --git a/src/lang/ar.rs b/src/lang/ar.rs index 50de78042..c32ab5648 100644 --- a/src/lang/ar.rs +++ b/src/lang/ar.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ca.rs b/src/lang/ca.rs index ed41ccb95..8cf0b3839 100644 --- a/src/lang/ca.rs +++ b/src/lang/ca.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/cn.rs b/src/lang/cn.rs index d63d79c74..2182a0b0a 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", "Email 验证码必须是 6 个字符。"), + ("2FA code must be 6 digits.", "2FA 码必须是6位数字。"), ].iter().cloned().collect(); } diff --git a/src/lang/cs.rs b/src/lang/cs.rs index 1e44600c7..447284bec 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/da.rs b/src/lang/da.rs index 60d07b397..a925bcc39 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/de.rs b/src/lang/de.rs index 879a97308..e6a70b75e 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", "Bitte richten Sie jetzt Ihren Authentifikator ein. Sie können eine Authentifizierungs-App wie Authy, Microsoft oder Google Authenticator auf Ihrem Telefon oder Desktop verwenden.\n\nScannen Sie den QR-Code mit Ihrer App und geben Sie den Code ein, den Ihre App anzeigt, um die Zwei-Faktor-Authentifizierung zu aktivieren."), ("wrong-2fa-code", "Der Code kann nicht verifiziert werden. Prüfen Sie, ob der Code und die lokalen Zeiteinstellungen korrekt sind."), ("enter-2fa-title", "Zwei-Faktor-Authentifizierung"), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/el.rs b/src/lang/el.rs index f25e75d27..093e3ac25 100644 --- a/src/lang/el.rs +++ b/src/lang/el.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index 87eef532c..2d1980ffd 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/es.rs b/src/lang/es.rs index b602b689d..fad514506 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/et.rs b/src/lang/et.rs index c3da54797..5614da975 100644 --- a/src/lang/et.rs +++ b/src/lang/et.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fa.rs b/src/lang/fa.rs index a6b083f4c..df8d1a222 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index 4defde37d..60f9eb989 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/hu.rs b/src/lang/hu.rs index 71490f6bf..c3b1ebd04 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/id.rs b/src/lang/id.rs index f7493b50c..bb2ccecc2 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/it.rs b/src/lang/it.rs index 793dd7849..c3a272bd0 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ja.rs b/src/lang/ja.rs index 76f4a35b4..96ac8c417 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ko.rs b/src/lang/ko.rs index e065e8d76..e5aefadef 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/kz.rs b/src/lang/kz.rs index e021f9799..96205d401 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/lt.rs b/src/lang/lt.rs index 8fcb4d49e..1bec420e3 100644 --- a/src/lang/lt.rs +++ b/src/lang/lt.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/lv.rs b/src/lang/lv.rs index fca516707..4da64b45f 100644 --- a/src/lang/lv.rs +++ b/src/lang/lv.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/nb.rs b/src/lang/nb.rs index 99a0ba9c7..7be99f637 100644 --- a/src/lang/nb.rs +++ b/src/lang/nb.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/nl.rs b/src/lang/nl.rs index 8ec4e48a0..1552ac422 100644 --- a/src/lang/nl.rs +++ b/src/lang/nl.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pl.rs b/src/lang/pl.rs index a5d53208f..8f77d1039 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index 3f8818fbb..6d753ffd1 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index 12220b7ac..caead766c 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ro.rs b/src/lang/ro.rs index 2bca2b7b6..52b7e45f6 100644 --- a/src/lang/ro.rs +++ b/src/lang/ro.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ru.rs b/src/lang/ru.rs index cae965d8e..aa5cba5f4 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 604c082df..6cf4cda6e 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sl.rs b/src/lang/sl.rs index 7e6716ce1..c5295637e 100755 --- a/src/lang/sl.rs +++ b/src/lang/sl.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sq.rs b/src/lang/sq.rs index cf539bc08..480bf5510 100644 --- a/src/lang/sq.rs +++ b/src/lang/sq.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sr.rs b/src/lang/sr.rs index 33d12e8a5..f50ddd0a6 100644 --- a/src/lang/sr.rs +++ b/src/lang/sr.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sv.rs b/src/lang/sv.rs index e7577d85b..e30d2ed3b 100644 --- a/src/lang/sv.rs +++ b/src/lang/sv.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/template.rs b/src/lang/template.rs index b76845b01..eb5855e82 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/th.rs b/src/lang/th.rs index 2d3e9d54d..59723a266 100644 --- a/src/lang/th.rs +++ b/src/lang/th.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tr.rs b/src/lang/tr.rs index 32e6a6eb8..0a57843f4 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tw.rs b/src/lang/tw.rs index 6e50bfd36..5a84be551 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ua.rs b/src/lang/ua.rs index 0dd3a9e50..7f46929dd 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); } diff --git a/src/lang/vn.rs b/src/lang/vn.rs index 55e72c570..d2eb11a3d 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -585,5 +585,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("enable-2fa-desc", ""), ("wrong-2fa-code", ""), ("enter-2fa-title", ""), + ("Email verification code must be 6 characters.", ""), + ("2FA code must be 6 digits.", ""), ].iter().cloned().collect(); }