Skip to content

Commit 076e26e

Browse files
authored
feat: add localizations (#76)
* feat: add localizations * fix: use BuildContext across asynchronous gaps
1 parent e8a9204 commit 076e26e

13 files changed

+203
-55
lines changed

lib/src/components/supa_email_auth.dart

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'package:email_validator/email_validator.dart';
22
import 'package:flutter/material.dart';
3+
import 'package:supabase_auth_ui/src/localizations/supa_email_auth_localization.dart';
34
import 'package:supabase_auth_ui/src/utils/constants.dart';
45
import 'package:supabase_flutter/supabase_flutter.dart';
56

@@ -79,6 +80,9 @@ class SupaEmailAuth extends StatefulWidget {
7980
/// Additional properties for user_metadata on signup
8081
final Map<String, dynamic>? extraMetadata;
8182

83+
/// Localization for the form
84+
final SupaEmailAuthLocalization localization;
85+
8286
/// {@macro supa_email_auth}
8387
const SupaEmailAuth({
8488
Key? key,
@@ -89,6 +93,7 @@ class SupaEmailAuth extends StatefulWidget {
8993
this.onError,
9094
this.metadataFields,
9195
this.extraMetadata,
96+
this.localization = const SupaEmailAuthLocalization(),
9297
}) : super(key: key);
9398

9499
@override
@@ -127,6 +132,7 @@ class _SupaEmailAuthState extends State<SupaEmailAuth> {
127132

128133
@override
129134
Widget build(BuildContext context) {
135+
final localization = widget.localization;
130136
return Form(
131137
key: _formKey,
132138
child: Column(
@@ -139,13 +145,13 @@ class _SupaEmailAuthState extends State<SupaEmailAuth> {
139145
if (value == null ||
140146
value.isEmpty ||
141147
!EmailValidator.validate(_emailController.text)) {
142-
return 'Please enter a valid email address';
148+
return localization.validEmailError;
143149
}
144150
return null;
145151
},
146-
decoration: const InputDecoration(
147-
prefixIcon: Icon(Icons.email),
148-
label: Text('Enter your email'),
152+
decoration: InputDecoration(
153+
prefixIcon: const Icon(Icons.email),
154+
label: Text(localization.enterEmail),
149155
),
150156
controller: _emailController,
151157
),
@@ -157,13 +163,13 @@ class _SupaEmailAuthState extends State<SupaEmailAuth> {
157163
: [AutofillHints.newPassword],
158164
validator: (value) {
159165
if (value == null || value.isEmpty || value.length < 6) {
160-
return 'Please enter a password that is at least 6 characters long';
166+
return localization.passwordLengthError;
161167
}
162168
return null;
163169
},
164-
decoration: const InputDecoration(
165-
prefixIcon: Icon(Icons.lock),
166-
label: Text('Enter your password'),
170+
decoration: InputDecoration(
171+
prefixIcon: const Icon(Icons.lock),
172+
label: Text(localization.enterPassword),
167173
),
168174
obscureText: true,
169175
controller: _passwordController,
@@ -193,7 +199,8 @@ class _SupaEmailAuthState extends State<SupaEmailAuth> {
193199
strokeWidth: 1.5,
194200
),
195201
)
196-
: Text(_isSigningIn ? 'Sign In' : 'Sign Up'),
202+
: Text(
203+
_isSigningIn ? localization.signIn : localization.signUp),
197204
onPressed: () async {
198205
if (!_formKey.currentState!.validate()) {
199206
return;
@@ -226,7 +233,7 @@ class _SupaEmailAuthState extends State<SupaEmailAuth> {
226233
} catch (error) {
227234
if (widget.onError == null && context.mounted) {
228235
context.showErrorSnackBar(
229-
'Unexpected error has occurred: $error');
236+
'${localization.unexpectedError}: $error');
230237
} else {
231238
widget.onError?.call(error);
232239
}
@@ -246,7 +253,7 @@ class _SupaEmailAuthState extends State<SupaEmailAuth> {
246253
_forgotPassword = true;
247254
});
248255
},
249-
child: const Text('Forgot your password?'),
256+
child: Text(localization.forgotPassword),
250257
),
251258
],
252259
TextButton(
@@ -258,8 +265,8 @@ class _SupaEmailAuthState extends State<SupaEmailAuth> {
258265
});
259266
},
260267
child: Text(_isSigningIn
261-
? 'Don\'t have an account? Sign up'
262-
: 'Already have an account? Sign in'),
268+
? localization.dontHaveAccount
269+
: localization.haveAccount),
263270
),
264271
],
265272
if (_isSigningIn && _forgotPassword) ...[
@@ -283,7 +290,7 @@ class _SupaEmailAuthState extends State<SupaEmailAuth> {
283290
widget.onError?.call(error);
284291
}
285292
},
286-
child: const Text('Send password reset email'),
293+
child: Text(localization.sendPasswordReset),
287294
),
288295
spacer(16),
289296
TextButton(
@@ -292,7 +299,7 @@ class _SupaEmailAuthState extends State<SupaEmailAuth> {
292299
_forgotPassword = false;
293300
});
294301
},
295-
child: const Text('Back to sign in'),
302+
child: Text(localization.backToSignIn),
296303
),
297304
],
298305
spacer(16),

lib/src/components/supa_magic_auth.dart

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'dart:async';
22

33
import 'package:email_validator/email_validator.dart';
44
import 'package:flutter/material.dart';
5+
import 'package:supabase_auth_ui/src/localizations/supa_magic_auth_localization.dart';
56
import 'package:supabase_auth_ui/src/utils/constants.dart';
67
import 'package:supabase_flutter/supabase_flutter.dart';
78

@@ -18,11 +19,15 @@ class SupaMagicAuth extends StatefulWidget {
1819
/// Method to be called when the auth action threw an excepction
1920
final void Function(Object error)? onError;
2021

22+
/// Localization for the form
23+
final SupaMagicAuthLocalization localization;
24+
2125
const SupaMagicAuth({
2226
Key? key,
2327
this.redirectUrl,
2428
required this.onSuccess,
2529
this.onError,
30+
this.localization = const SupaMagicAuthLocalization(),
2631
}) : super(key: key);
2732

2833
@override
@@ -57,6 +62,7 @@ class _SupaMagicAuthState extends State<SupaMagicAuth> {
5762

5863
@override
5964
Widget build(BuildContext context) {
65+
final localization = widget.localization;
6066
return Form(
6167
key: _formKey,
6268
child: Column(
@@ -69,13 +75,13 @@ class _SupaMagicAuthState extends State<SupaMagicAuth> {
6975
if (value == null ||
7076
value.isEmpty ||
7177
!EmailValidator.validate(_email.text)) {
72-
return 'Please enter a valid email address';
78+
return localization.validEmailError;
7379
}
7480
return null;
7581
},
76-
decoration: const InputDecoration(
77-
prefixIcon: Icon(Icons.email),
78-
label: Text('Enter your email'),
82+
decoration: InputDecoration(
83+
prefixIcon: const Icon(Icons.email),
84+
label: Text(localization.enterEmail),
7985
),
8086
controller: _email,
8187
),
@@ -90,9 +96,9 @@ class _SupaMagicAuthState extends State<SupaMagicAuth> {
9096
strokeWidth: 1.5,
9197
),
9298
)
93-
: const Text(
94-
'Continue with magic Link',
95-
style: TextStyle(fontWeight: FontWeight.bold),
99+
: Text(
100+
localization.continueWithMagicLink,
101+
style: const TextStyle(fontWeight: FontWeight.bold),
96102
),
97103
onPressed: () async {
98104
if (!_formKey.currentState!.validate()) {
@@ -106,8 +112,8 @@ class _SupaMagicAuthState extends State<SupaMagicAuth> {
106112
email: _email.text,
107113
emailRedirectTo: widget.redirectUrl,
108114
);
109-
if (mounted) {
110-
context.showSnackBar('Check your email inbox!');
115+
if (context.mounted) {
116+
context.showSnackBar(localization.checkYourEmail);
111117
}
112118
} on AuthException catch (error) {
113119
if (widget.onError == null && context.mounted) {
@@ -118,7 +124,7 @@ class _SupaMagicAuthState extends State<SupaMagicAuth> {
118124
} catch (error) {
119125
if (widget.onError == null && context.mounted) {
120126
context.showErrorSnackBar(
121-
'Unexpected error has occurred: $error');
127+
'${localization.unexpectedError}: $error');
122128
} else {
123129
widget.onError?.call(error);
124130
}

lib/src/components/supa_phone_auth.dart

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,15 @@ class SupaPhoneAuth extends StatefulWidget {
1313
/// Method to be called when the auth action threw an excepction
1414
final void Function(Object error)? onError;
1515

16+
/// Localization for the form
17+
final SupaPhoneAuthLocalization localization;
18+
1619
const SupaPhoneAuth({
1720
Key? key,
1821
required this.authAction,
1922
required this.onSuccess,
2023
this.onError,
24+
this.localization = const SupaPhoneAuthLocalization(),
2125
}) : super(key: key);
2226

2327
@override
@@ -43,6 +47,7 @@ class _SupaPhoneAuthState extends State<SupaPhoneAuth> {
4347

4448
@override
4549
Widget build(BuildContext context) {
50+
final localization = widget.localization;
4651
final isSigningIn = widget.authAction == SupaAuthAction.signIn;
4752
return Form(
4853
key: _formKey,
@@ -53,13 +58,13 @@ class _SupaPhoneAuthState extends State<SupaPhoneAuth> {
5358
autofillHints: const [AutofillHints.telephoneNumber],
5459
validator: (value) {
5560
if (value == null || value.isEmpty) {
56-
return 'Please enter a valid phone number';
61+
return localization.validPhoneNumberError;
5762
}
5863
return null;
5964
},
60-
decoration: const InputDecoration(
61-
prefixIcon: Icon(Icons.phone),
62-
label: Text('Enter your phone number'),
65+
decoration: InputDecoration(
66+
prefixIcon: const Icon(Icons.phone),
67+
label: Text(localization.enterPhoneNumber),
6368
),
6469
controller: _phone,
6570
),
@@ -70,21 +75,21 @@ class _SupaPhoneAuthState extends State<SupaPhoneAuth> {
7075
: [AutofillHints.newPassword],
7176
validator: (value) {
7277
if (value == null || value.isEmpty || value.length < 6) {
73-
return 'Please enter a password that is at least 6 characters long';
78+
return localization.passwordLengthError;
7479
}
7580
return null;
7681
},
77-
decoration: const InputDecoration(
78-
prefixIcon: Icon(Icons.lock),
79-
label: Text('Enter your password'),
82+
decoration: InputDecoration(
83+
prefixIcon: const Icon(Icons.lock),
84+
label: Text(localization.enterPassword),
8085
),
8186
obscureText: true,
8287
controller: _password,
8388
),
8489
spacer(16),
8590
ElevatedButton(
8691
child: Text(
87-
isSigningIn ? 'Sign In' : 'Sign Up',
92+
isSigningIn ? localization.signIn : localization.signUp,
8893
style: const TextStyle(fontWeight: FontWeight.bold),
8994
),
9095
onPressed: () async {
@@ -113,7 +118,7 @@ class _SupaPhoneAuthState extends State<SupaPhoneAuth> {
113118
} catch (error) {
114119
if (widget.onError == null && context.mounted) {
115120
context.showErrorSnackBar(
116-
'Unexpected error has occurred: $error');
121+
'${localization.unexpectedError}: $error');
117122
} else {
118123
widget.onError?.call(error);
119124
}

lib/src/components/supa_reset_password.dart

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:flutter/material.dart';
2+
import 'package:supabase_auth_ui/src/localizations/supa_reset_password_localization.dart';
23
import 'package:supabase_auth_ui/src/utils/constants.dart';
34
import 'package:supabase_flutter/supabase_flutter.dart';
45

@@ -13,11 +14,15 @@ class SupaResetPassword extends StatefulWidget {
1314
/// Method to be called when the auth action threw an excepction
1415
final void Function(Object error)? onError;
1516

17+
/// Localization for the form
18+
final SupaResetPasswordLocalization localization;
19+
1620
const SupaResetPassword({
1721
Key? key,
1822
this.accessToken,
1923
required this.onSuccess,
2024
this.onError,
25+
this.localization = const SupaResetPasswordLocalization(),
2126
}) : super(key: key);
2227

2328
@override
@@ -36,6 +41,7 @@ class _SupaResetPasswordState extends State<SupaResetPassword> {
3641

3742
@override
3843
Widget build(BuildContext context) {
44+
final localization = widget.localization;
3945
return Form(
4046
key: _formKey,
4147
child: Column(
@@ -45,21 +51,21 @@ class _SupaResetPasswordState extends State<SupaResetPassword> {
4551
autofillHints: const [AutofillHints.newPassword],
4652
validator: (value) {
4753
if (value == null || value.isEmpty || value.length < 6) {
48-
return 'Please enter a password that is at least 6 characters long';
54+
return localization.passwordLengthError;
4955
}
5056
return null;
5157
},
52-
decoration: const InputDecoration(
53-
prefixIcon: Icon(Icons.lock),
54-
label: Text('Enter your password'),
58+
decoration: InputDecoration(
59+
prefixIcon: const Icon(Icons.lock),
60+
label: Text(localization.enterPassword),
5561
),
5662
controller: _password,
5763
),
5864
spacer(16),
5965
ElevatedButton(
60-
child: const Text(
61-
'Update Password',
62-
style: TextStyle(fontWeight: FontWeight.bold),
66+
child: Text(
67+
localization.updatePassword,
68+
style: const TextStyle(fontWeight: FontWeight.bold),
6369
),
6470
onPressed: () async {
6571
if (!_formKey.currentState!.validate()) {
@@ -81,7 +87,7 @@ class _SupaResetPasswordState extends State<SupaResetPassword> {
8187
} catch (error) {
8288
if (widget.onError == null && context.mounted) {
8389
context.showErrorSnackBar(
84-
'Unexpected error has occurred: $error');
90+
'${localization.passwordLengthError}: $error');
8591
} else {
8692
widget.onError?.call(error);
8793
}

0 commit comments

Comments
 (0)