forked from baron/baron-sso
Merge feature/i18n into dev (userfront only)
This commit is contained in:
@@ -30,16 +30,14 @@ class ErrorScreen extends StatelessWidget {
|
||||
? (isWhitelisted && hasCode ? normalizedCode : 'unknown_error')
|
||||
: (hasCode ? normalizedCode : 'unknown_error');
|
||||
final title = isProd
|
||||
? tr('msg.userfront.error.title', fallback: '인증 과정에서 오류가 발생했습니다')
|
||||
? tr('msg.userfront.error.title')
|
||||
: (hasCode
|
||||
? tr(
|
||||
'msg.userfront.error.title_with_code',
|
||||
fallback: '오류: {{code}}',
|
||||
params: {'code': normalizedCode},
|
||||
)
|
||||
: tr(
|
||||
'msg.userfront.error.title_generic',
|
||||
fallback: '오류가 발생했습니다',
|
||||
));
|
||||
final detail = isProd
|
||||
? (isWhitelisted
|
||||
@@ -49,18 +47,15 @@ class ErrorScreen extends StatelessWidget {
|
||||
)
|
||||
: tr(
|
||||
'msg.userfront.error.detail_contact',
|
||||
fallback: '에러가 계속되면 관리자에게 문의해주세요',
|
||||
))
|
||||
: ((description?.isNotEmpty == true)
|
||||
? description!
|
||||
: (hasCode
|
||||
? tr(
|
||||
'msg.userfront.error.detail_generic',
|
||||
fallback: '오류가 발생했습니다.',
|
||||
)
|
||||
: tr(
|
||||
'msg.userfront.error.detail_request',
|
||||
fallback: '요청을 처리하는 중 문제가 발생했습니다.',
|
||||
)));
|
||||
|
||||
return Scaffold(
|
||||
@@ -100,7 +95,6 @@ class ErrorScreen extends StatelessWidget {
|
||||
Text(
|
||||
tr(
|
||||
'msg.userfront.error.type',
|
||||
fallback: '오류 종류: {{type}}',
|
||||
params: {'type': errorType},
|
||||
),
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
@@ -112,7 +106,6 @@ class ErrorScreen extends StatelessWidget {
|
||||
Text(
|
||||
tr(
|
||||
'msg.userfront.error.id',
|
||||
fallback: '오류 ID: {{id}}',
|
||||
params: {'id': errorId!},
|
||||
),
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
@@ -141,7 +134,6 @@ class ErrorScreen extends StatelessWidget {
|
||||
child: Text(
|
||||
tr(
|
||||
'ui.userfront.error.go_login',
|
||||
fallback: '로그인으로 이동',
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -159,7 +151,7 @@ class ErrorScreen extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
tr('ui.userfront.error.go_home', fallback: '홈으로 이동'),
|
||||
tr('ui.userfront.error.go_home'),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -28,7 +28,6 @@ class _ForgotPasswordScreenState extends State<ForgotPasswordScreen> {
|
||||
_showError(
|
||||
tr(
|
||||
'msg.userfront.forgot.input_required',
|
||||
fallback: '이메일 또는 휴대폰 번호를 입력해주세요.',
|
||||
),
|
||||
);
|
||||
return;
|
||||
@@ -56,7 +55,6 @@ class _ForgotPasswordScreenState extends State<ForgotPasswordScreen> {
|
||||
content: Text(
|
||||
tr(
|
||||
'msg.userfront.forgot.sent',
|
||||
fallback: '비밀번호 재설정 링크가 전송되었습니다. 이메일 또는 SMS를 확인해주세요.',
|
||||
),
|
||||
),
|
||||
backgroundColor: Colors.green,
|
||||
@@ -69,7 +67,6 @@ class _ForgotPasswordScreenState extends State<ForgotPasswordScreen> {
|
||||
_showError(
|
||||
tr(
|
||||
'msg.userfront.forgot.error',
|
||||
fallback: '전송에 실패했습니다: {{error}}',
|
||||
params: {'error': e.toString()},
|
||||
),
|
||||
);
|
||||
@@ -99,7 +96,7 @@ class _ForgotPasswordScreenState extends State<ForgotPasswordScreen> {
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(tr('ui.userfront.forgot.title', fallback: '비밀번호 재설정')),
|
||||
title: Text(tr('ui.userfront.forgot.title')),
|
||||
centerTitle: true,
|
||||
),
|
||||
body: Center(
|
||||
@@ -111,7 +108,7 @@ class _ForgotPasswordScreenState extends State<ForgotPasswordScreen> {
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text(
|
||||
tr('ui.userfront.forgot.heading', fallback: '비밀번호를 잊으셨나요?'),
|
||||
tr('ui.userfront.forgot.heading'),
|
||||
style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
@@ -138,7 +135,6 @@ class _ForgotPasswordScreenState extends State<ForgotPasswordScreen> {
|
||||
child: Text(
|
||||
tr(
|
||||
'msg.userfront.forgot.dry_send',
|
||||
fallback: 'drySend 모드: 실제 이메일/SMS는 발송되지 않습니다.',
|
||||
),
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF8A6D3B),
|
||||
@@ -154,8 +150,6 @@ class _ForgotPasswordScreenState extends State<ForgotPasswordScreen> {
|
||||
Text(
|
||||
tr(
|
||||
'msg.userfront.forgot.description',
|
||||
fallback:
|
||||
'계정과 연결된 이메일 주소 또는 휴대폰 번호를 입력하시면, 비밀번호를 재설정할 수 있는 링크를 보내드립니다.',
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(color: Colors.grey),
|
||||
@@ -166,7 +160,6 @@ class _ForgotPasswordScreenState extends State<ForgotPasswordScreen> {
|
||||
decoration: InputDecoration(
|
||||
labelText: tr(
|
||||
'ui.userfront.forgot.input_label',
|
||||
fallback: '이메일 또는 휴대폰 번호',
|
||||
),
|
||||
border: const OutlineInputBorder(),
|
||||
prefixIcon: const Icon(Icons.person_outline),
|
||||
@@ -189,7 +182,7 @@ class _ForgotPasswordScreenState extends State<ForgotPasswordScreen> {
|
||||
),
|
||||
)
|
||||
: Text(
|
||||
tr('ui.userfront.forgot.submit', fallback: '재설정 링크 전송'),
|
||||
tr('ui.userfront.forgot.submit'),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,14 +21,13 @@ class LoginSuccessScreen extends StatelessWidget {
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Text(
|
||||
tr('ui.userfront.login_success.title', fallback: '로그인 완료'),
|
||||
tr('ui.userfront.login_success.title'),
|
||||
style: TextStyle(fontSize: 32, fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
tr(
|
||||
'msg.userfront.login_success.subtitle',
|
||||
fallback: '성공적으로 로그인되었습니다.',
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(color: Colors.grey, fontSize: 16),
|
||||
@@ -44,7 +43,6 @@ class LoginSuccessScreen extends StatelessWidget {
|
||||
label: Text(
|
||||
tr(
|
||||
'ui.userfront.login_success.qr',
|
||||
fallback: 'QR 인증 (카메라 켜기)',
|
||||
),
|
||||
),
|
||||
style: FilledButton.styleFrom(
|
||||
@@ -67,7 +65,6 @@ class LoginSuccessScreen extends StatelessWidget {
|
||||
child: Text(
|
||||
tr(
|
||||
'ui.userfront.login_success.later',
|
||||
fallback: '나중에 하기 (대시보드로 이동)',
|
||||
),
|
||||
style: const TextStyle(color: Colors.grey),
|
||||
),
|
||||
|
||||
@@ -146,7 +146,6 @@ class _QRScanScreenState extends State<QRScanScreen> {
|
||||
_isSuccess = true;
|
||||
_resultMessage = tr(
|
||||
'msg.userfront.qr.approve_success',
|
||||
fallback: 'QR 승인 완료! PC 화면에서 로그인이 진행됩니다.',
|
||||
);
|
||||
_isProcessing = false;
|
||||
});
|
||||
@@ -158,7 +157,6 @@ class _QRScanScreenState extends State<QRScanScreen> {
|
||||
_isSuccess = false;
|
||||
_resultMessage = tr(
|
||||
'msg.userfront.qr.approve_error',
|
||||
fallback: 'QR 승인 실패: {{error}}',
|
||||
params: {'error': '$e'},
|
||||
);
|
||||
_isProcessing = false;
|
||||
@@ -193,7 +191,6 @@ class _QRScanScreenState extends State<QRScanScreen> {
|
||||
content: Text(
|
||||
tr(
|
||||
'msg.userfront.qr.permission_error',
|
||||
fallback: '카메라 권한 요청에 실패했습니다. 브라우저/OS 설정을 확인해주세요.',
|
||||
),
|
||||
),
|
||||
backgroundColor: Colors.red,
|
||||
@@ -212,8 +209,8 @@ class _QRScanScreenState extends State<QRScanScreen> {
|
||||
final icon = success ? Icons.check_circle_outline : Icons.error_outline;
|
||||
final color = success ? Colors.green : Colors.red;
|
||||
final title = success
|
||||
? tr('ui.userfront.qr.result_success', fallback: '승인 완료')
|
||||
: tr('ui.userfront.qr.result_failure', fallback: '승인 실패');
|
||||
? tr('ui.userfront.qr.result_success')
|
||||
: tr('ui.userfront.qr.result_failure');
|
||||
final message = _resultMessage ?? '';
|
||||
|
||||
return Center(
|
||||
@@ -242,12 +239,12 @@ class _QRScanScreenState extends State<QRScanScreen> {
|
||||
if (!success)
|
||||
FilledButton(
|
||||
onPressed: _resetScan,
|
||||
child: Text(tr('ui.userfront.qr.rescan', fallback: '다시 스캔')),
|
||||
child: Text(tr('ui.userfront.qr.rescan')),
|
||||
),
|
||||
if (success)
|
||||
FilledButton(
|
||||
onPressed: () => context.pop(),
|
||||
child: Text(tr('ui.common.close', fallback: '닫기')),
|
||||
child: Text(tr('ui.common.close')),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -285,11 +282,9 @@ class _QRScanScreenState extends State<QRScanScreen> {
|
||||
isPermissionDenied
|
||||
? tr(
|
||||
'msg.userfront.qr.permission_required',
|
||||
fallback: '카메라 권한이 필요합니다.',
|
||||
)
|
||||
: tr(
|
||||
'msg.userfront.qr.camera_error',
|
||||
fallback: '카메라 오류: {{error}}',
|
||||
params: {'error': '${error.errorCode}'},
|
||||
),
|
||||
),
|
||||
@@ -302,11 +297,9 @@ class _QRScanScreenState extends State<QRScanScreen> {
|
||||
_isRequestingCamera
|
||||
? tr(
|
||||
'ui.common.requesting',
|
||||
fallback: '요청 중...',
|
||||
)
|
||||
: tr(
|
||||
'ui.userfront.qr.request_permission',
|
||||
fallback: '카메라 권한 요청하기',
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -72,7 +72,6 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
_showError(
|
||||
tr(
|
||||
'msg.userfront.reset.invalid_link',
|
||||
fallback: '유효하지 않은 재설정 링크입니다. (loginId/token 누락)',
|
||||
),
|
||||
);
|
||||
return;
|
||||
@@ -93,7 +92,6 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
content: Text(
|
||||
tr(
|
||||
'msg.userfront.reset.success',
|
||||
fallback: '비밀번호가 성공적으로 변경되었습니다. 다시 로그인해주세요.',
|
||||
),
|
||||
),
|
||||
backgroundColor: Colors.green,
|
||||
@@ -106,7 +104,6 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
_showError(
|
||||
tr(
|
||||
'msg.userfront.reset.error.generic',
|
||||
fallback: '비밀번호 변경에 실패했습니다: {{error}}',
|
||||
params: {'error': e.toString()},
|
||||
),
|
||||
);
|
||||
@@ -128,7 +125,6 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
if (_isPolicyLoading) {
|
||||
return tr(
|
||||
'msg.userfront.reset.policy_loading',
|
||||
fallback: '비밀번호 정책을 불러오는 중입니다...',
|
||||
);
|
||||
}
|
||||
final minLength = (_policy?['minLength'] as int?) ?? 12;
|
||||
@@ -141,7 +137,6 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
final parts = <String>[
|
||||
tr(
|
||||
'msg.userfront.reset.policy.min_length',
|
||||
fallback: '최소 {{count}}자 이상',
|
||||
params: {'count': '$minLength'},
|
||||
),
|
||||
];
|
||||
@@ -149,27 +144,26 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
parts.add(
|
||||
tr(
|
||||
'msg.userfront.reset.policy.min_types',
|
||||
fallback: '영문 대/소문자/숫자/특수문자 중 {{count}}가지 이상',
|
||||
params: {'count': '$minTypes'},
|
||||
),
|
||||
);
|
||||
}
|
||||
if (requiresLower) {
|
||||
parts.add(
|
||||
tr('msg.userfront.reset.policy.lowercase', fallback: '소문자 1개 이상'),
|
||||
tr('msg.userfront.reset.policy.lowercase'),
|
||||
);
|
||||
}
|
||||
if (requiresUpper) {
|
||||
parts.add(
|
||||
tr('msg.userfront.reset.policy.uppercase', fallback: '대문자 1개 이상'),
|
||||
tr('msg.userfront.reset.policy.uppercase'),
|
||||
);
|
||||
}
|
||||
if (requiresNumber) {
|
||||
parts.add(tr('msg.userfront.reset.policy.number', fallback: '숫자 1개 이상'));
|
||||
parts.add(tr('msg.userfront.reset.policy.number'));
|
||||
}
|
||||
if (requiresSymbol) {
|
||||
parts.add(
|
||||
tr('msg.userfront.reset.policy.symbol', fallback: '특수문자 1개 이상'),
|
||||
tr('msg.userfront.reset.policy.symbol'),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -180,7 +174,7 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(tr('ui.userfront.reset.title', fallback: '새 비밀번호 설정')),
|
||||
title: Text(tr('ui.userfront.reset.title')),
|
||||
centerTitle: true,
|
||||
),
|
||||
body: Center(
|
||||
@@ -200,7 +194,6 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
Text(
|
||||
tr(
|
||||
'ui.userfront.reset.subtitle',
|
||||
fallback: '새로운 비밀번호 설정',
|
||||
),
|
||||
style: TextStyle(
|
||||
fontSize: 28,
|
||||
@@ -221,7 +214,6 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
decoration: InputDecoration(
|
||||
labelText: tr(
|
||||
'ui.userfront.reset.new_password',
|
||||
fallback: '새 비밀번호',
|
||||
),
|
||||
border: const OutlineInputBorder(),
|
||||
prefixIcon: const Icon(Icons.lock_outline),
|
||||
@@ -243,7 +235,6 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
if (val.isEmpty) {
|
||||
return tr(
|
||||
'msg.userfront.reset.error.empty_password',
|
||||
fallback: '비밀번호를 입력해주세요.',
|
||||
);
|
||||
}
|
||||
final minLength =
|
||||
@@ -251,7 +242,6 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
if (val.length < minLength) {
|
||||
return tr(
|
||||
'msg.userfront.reset.error.min_length',
|
||||
fallback: '비밀번호는 최소 {{count}}자 이상이어야 합니다.',
|
||||
params: {'count': '$minLength'},
|
||||
);
|
||||
}
|
||||
@@ -270,8 +260,6 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
if (minTypes > 0 && typeCount < minTypes) {
|
||||
return tr(
|
||||
'msg.userfront.reset.error.min_types',
|
||||
fallback:
|
||||
'비밀번호는 영문 대/소문자/숫자/특수문자 중 {{count}}가지 이상 포함해야 합니다.',
|
||||
params: {'count': '$minTypes'},
|
||||
);
|
||||
}
|
||||
@@ -279,26 +267,22 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
if ((_policy?['lowercase'] ?? true) && !hasLower) {
|
||||
return tr(
|
||||
'msg.userfront.reset.error.lowercase',
|
||||
fallback: '최소 1개 이상의 소문자를 포함해야 합니다.',
|
||||
);
|
||||
}
|
||||
if ((_policy?['uppercase'] ?? false) && !hasUpper) {
|
||||
return tr(
|
||||
'msg.userfront.reset.error.uppercase',
|
||||
fallback: '최소 1개 이상의 대문자를 포함해야 합니다.',
|
||||
);
|
||||
}
|
||||
if ((_policy?['number'] ?? true) && !hasNumber) {
|
||||
return tr(
|
||||
'msg.userfront.reset.error.number',
|
||||
fallback: '최소 1개 이상의 숫자를 포함해야 합니다.',
|
||||
);
|
||||
}
|
||||
if ((_policy?['nonAlphanumeric'] ?? true) &&
|
||||
!hasSymbol) {
|
||||
return tr(
|
||||
'msg.userfront.reset.error.symbol',
|
||||
fallback: '최소 1개 이상의 특수문자를 포함해야 합니다.',
|
||||
);
|
||||
}
|
||||
return null;
|
||||
@@ -311,7 +295,6 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
decoration: InputDecoration(
|
||||
labelText: tr(
|
||||
'ui.userfront.reset.confirm_password',
|
||||
fallback: '새 비밀번호 확인',
|
||||
),
|
||||
border: const OutlineInputBorder(),
|
||||
prefixIcon: const Icon(Icons.lock_outline),
|
||||
@@ -333,7 +316,6 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
if (value != _passwordController.text) {
|
||||
return tr(
|
||||
'msg.userfront.reset.error.mismatch',
|
||||
fallback: '비밀번호가 일치하지 않습니다.',
|
||||
);
|
||||
}
|
||||
return null;
|
||||
@@ -357,7 +339,6 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
: Text(
|
||||
tr(
|
||||
'ui.userfront.reset.submit',
|
||||
fallback: '비밀번호 변경',
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -377,7 +358,7 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
const Icon(Icons.error_outline, color: Colors.red, size: 60),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
tr('msg.userfront.reset.invalid_title', fallback: '유효하지 않은 링크입니다.'),
|
||||
tr('msg.userfront.reset.invalid_title'),
|
||||
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
@@ -385,7 +366,6 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
Text(
|
||||
tr(
|
||||
'msg.userfront.reset.invalid_body',
|
||||
fallback: '비밀번호 재설정 링크가 만료되었거나 잘못되었습니다. 다시 시도해주세요.',
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
|
||||
@@ -167,7 +167,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
setState(
|
||||
() => _emailError = tr(
|
||||
'msg.userfront.signup.email.invalid',
|
||||
fallback: '유효한 이메일 형식이 아닙니다.',
|
||||
),
|
||||
);
|
||||
return;
|
||||
@@ -182,7 +181,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
setState(
|
||||
() => _emailError = tr(
|
||||
'msg.userfront.signup.email.duplicate',
|
||||
fallback: '이미 가입된 이메일입니다.',
|
||||
),
|
||||
);
|
||||
return;
|
||||
@@ -193,7 +191,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
setState(
|
||||
() => _emailError = tr(
|
||||
'msg.userfront.signup.email.send_failed',
|
||||
fallback: '발송 실패: {{error}}',
|
||||
params: {'error': e.toString()},
|
||||
),
|
||||
);
|
||||
@@ -222,7 +219,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
setState(
|
||||
() => _emailError = tr(
|
||||
'msg.userfront.signup.email.code_mismatch',
|
||||
fallback: '인증코드가 일치하지 않습니다.',
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -230,7 +226,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
setState(
|
||||
() => _emailError = tr(
|
||||
'msg.userfront.signup.email.verify_failed',
|
||||
fallback: '인증 실패: {{error}}',
|
||||
params: {'error': e.toString()},
|
||||
),
|
||||
);
|
||||
@@ -251,7 +246,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
setState(
|
||||
() => _phoneError = tr(
|
||||
'msg.userfront.signup.phone.send_failed',
|
||||
fallback: '발송 실패: {{error}}',
|
||||
params: {'error': e.toString()},
|
||||
),
|
||||
);
|
||||
@@ -280,7 +274,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
setState(
|
||||
() => _phoneError = tr(
|
||||
'msg.userfront.signup.phone.code_mismatch',
|
||||
fallback: '인증코드가 일치하지 않습니다.',
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -288,7 +281,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
setState(
|
||||
() => _phoneError = tr(
|
||||
'msg.userfront.signup.phone.verify_failed',
|
||||
fallback: '인증 실패: {{error}}',
|
||||
params: {'error': e.toString()},
|
||||
),
|
||||
);
|
||||
@@ -300,7 +292,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
setState(
|
||||
() => _confirmPasswordError = tr(
|
||||
'msg.userfront.signup.password.mismatch',
|
||||
fallback: '비밀번호가 일치하지 않습니다.',
|
||||
),
|
||||
);
|
||||
return;
|
||||
@@ -332,32 +323,26 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
if (eStr.contains('uppercase')) {
|
||||
_passwordError = tr(
|
||||
'msg.userfront.signup.password.uppercase_required',
|
||||
fallback: '대문자가 최소 1개 이상 포함되어야 합니다.',
|
||||
);
|
||||
} else if (eStr.contains('lowercase')) {
|
||||
_passwordError = tr(
|
||||
'msg.userfront.signup.password.lowercase_required',
|
||||
fallback: '소문자가 최소 1개 이상 포함되어야 합니다.',
|
||||
);
|
||||
} else if (eStr.contains('digit') || eStr.contains('number')) {
|
||||
_passwordError = tr(
|
||||
'msg.userfront.signup.password.number_required',
|
||||
fallback: '숫자가 최소 1개 이상 포함되어야 합니다.',
|
||||
);
|
||||
} else if (eStr.contains('symbol') || eStr.contains('special')) {
|
||||
_passwordError = tr(
|
||||
'msg.userfront.signup.password.symbol_required',
|
||||
fallback: '특수문자가 최소 1개 이상 포함되어야 합니다.',
|
||||
);
|
||||
} else if (eStr.contains('length') || eStr.contains('12 characters')) {
|
||||
_passwordError = tr(
|
||||
'msg.userfront.signup.password.length_required',
|
||||
fallback: '비밀번호는 최소 12자 이상이어야 합니다.',
|
||||
);
|
||||
} else {
|
||||
_passwordError = tr(
|
||||
'msg.userfront.signup.failed',
|
||||
fallback: '가입 실패: {{error}}',
|
||||
params: {'error': e.toString()},
|
||||
);
|
||||
}
|
||||
@@ -373,16 +358,16 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
barrierDismissible: false,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text(
|
||||
tr('msg.userfront.signup.success.title', fallback: '회원가입 완료'),
|
||||
tr('msg.userfront.signup.success.title'),
|
||||
),
|
||||
content: Text(
|
||||
tr('msg.userfront.signup.success.body', fallback: '성공적으로 가입되었습니다.'),
|
||||
tr('msg.userfront.signup.success.body'),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => context.go('/signin'),
|
||||
child: Text(
|
||||
tr('ui.userfront.signup.success.action', fallback: '로그인하기'),
|
||||
tr('ui.userfront.signup.success.action'),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -399,22 +384,22 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
children: [
|
||||
_stepCircle(
|
||||
1,
|
||||
tr('ui.userfront.signup.steps.agreement', fallback: '약관동의'),
|
||||
tr('ui.userfront.signup.steps.agreement'),
|
||||
),
|
||||
_stepLine(1),
|
||||
_stepCircle(
|
||||
2,
|
||||
tr('ui.userfront.signup.steps.verify', fallback: '본인인증'),
|
||||
tr('ui.userfront.signup.steps.verify'),
|
||||
),
|
||||
_stepLine(2),
|
||||
_stepCircle(
|
||||
3,
|
||||
tr('ui.userfront.signup.steps.profile', fallback: '정보입력'),
|
||||
tr('ui.userfront.signup.steps.profile'),
|
||||
),
|
||||
_stepLine(3),
|
||||
_stepCircle(
|
||||
4,
|
||||
tr('ui.userfront.signup.steps.password', fallback: '비밀번호'),
|
||||
tr('ui.userfront.signup.steps.password'),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -471,7 +456,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
Text(
|
||||
tr(
|
||||
'msg.userfront.signup.agreement.title',
|
||||
fallback: '서비스 이용을 위해\n약관에 동의해주세요',
|
||||
),
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
@@ -489,7 +473,7 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
),
|
||||
child: CheckboxListTile(
|
||||
title: Text(
|
||||
tr('ui.userfront.signup.agreement.all', fallback: '모두 동의합니다'),
|
||||
tr('ui.userfront.signup.agreement.all'),
|
||||
style: const TextStyle(fontSize: 15, fontWeight: FontWeight.bold),
|
||||
),
|
||||
value: _termsAccepted && _privacyAccepted,
|
||||
@@ -507,7 +491,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
_agreementSection(
|
||||
title: tr(
|
||||
'ui.userfront.signup.agreement.tos_title',
|
||||
fallback: '바론 소프트웨어 이용약관 (필수)',
|
||||
),
|
||||
content: _tosText,
|
||||
value: _termsAccepted,
|
||||
@@ -517,7 +500,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
_agreementSection(
|
||||
title: tr(
|
||||
'ui.userfront.signup.agreement.privacy_title',
|
||||
fallback: '개인정보 수집 및 이용 동의 (필수)',
|
||||
),
|
||||
content: _privacyText,
|
||||
value: _privacyAccepted,
|
||||
@@ -765,7 +747,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
Text(
|
||||
tr(
|
||||
'msg.userfront.signup.auth.title',
|
||||
fallback: '본인 확인을 위해\n인증을 진행해주세요',
|
||||
),
|
||||
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
|
||||
),
|
||||
@@ -785,7 +766,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
child: Text(
|
||||
tr(
|
||||
'msg.userfront.signup.auth.affiliate_notice',
|
||||
fallback: '가족사 회원의 경우 반드시 회사 공식 이메일을 입력해주세요.',
|
||||
),
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
@@ -799,7 +779,7 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Text(
|
||||
tr('ui.userfront.signup.auth.email.title', fallback: '이메일 인증'),
|
||||
tr('ui.userfront.signup.auth.email.title'),
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
@@ -812,7 +792,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
decoration: InputDecoration(
|
||||
labelText: tr(
|
||||
'ui.userfront.signup.auth.email.label',
|
||||
fallback: '이메일 주소',
|
||||
),
|
||||
border: const OutlineInputBorder(),
|
||||
errorText: _emailError,
|
||||
@@ -835,10 +814,9 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
),
|
||||
child: Text(
|
||||
_emailSeconds > 0
|
||||
? tr('ui.common.resend', fallback: '재발송')
|
||||
? tr('ui.common.resend')
|
||||
: tr(
|
||||
'ui.userfront.signup.auth.request_code',
|
||||
fallback: '인증요청',
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -852,7 +830,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
decoration: InputDecoration(
|
||||
labelText: tr(
|
||||
'ui.userfront.signup.auth.code_label',
|
||||
fallback: '인증코드 6자리',
|
||||
),
|
||||
suffixText: _formatTime(_emailSeconds),
|
||||
border: const OutlineInputBorder(),
|
||||
@@ -873,7 +850,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
child: Text(
|
||||
tr(
|
||||
'msg.userfront.signup.email.verified',
|
||||
fallback: '✅ 이메일 인증 완료',
|
||||
),
|
||||
style: const TextStyle(
|
||||
color: Colors.green,
|
||||
@@ -884,7 +860,7 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Text(
|
||||
tr('ui.userfront.signup.phone.title', fallback: '휴대폰 인증'),
|
||||
tr('ui.userfront.signup.phone.title'),
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
@@ -896,7 +872,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
decoration: InputDecoration(
|
||||
labelText: tr(
|
||||
'ui.userfront.signup.phone.label',
|
||||
fallback: '휴대폰 번호 (-없이)',
|
||||
),
|
||||
border: const OutlineInputBorder(),
|
||||
errorText: _phoneError,
|
||||
@@ -919,10 +894,9 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
),
|
||||
child: Text(
|
||||
_phoneSeconds > 0
|
||||
? tr('ui.common.resend', fallback: '재발송')
|
||||
? tr('ui.common.resend')
|
||||
: tr(
|
||||
'ui.userfront.signup.auth.request_code',
|
||||
fallback: '인증요청',
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -936,7 +910,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
decoration: InputDecoration(
|
||||
labelText: tr(
|
||||
'ui.userfront.signup.auth.code_label',
|
||||
fallback: '인증코드 6자리',
|
||||
),
|
||||
suffixText: _formatTime(_phoneSeconds),
|
||||
border: const OutlineInputBorder(),
|
||||
@@ -957,7 +930,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
child: Text(
|
||||
tr(
|
||||
'msg.userfront.signup.phone.verified',
|
||||
fallback: '✅ 휴대폰 인증 완료',
|
||||
),
|
||||
style: const TextStyle(
|
||||
color: Colors.green,
|
||||
@@ -977,7 +949,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
Text(
|
||||
tr(
|
||||
'msg.userfront.signup.profile.title',
|
||||
fallback: '회원님의\n소속 정보를 알려주세요',
|
||||
),
|
||||
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
|
||||
),
|
||||
@@ -986,7 +957,7 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
controller: _nameController,
|
||||
onChanged: (_) => setState(() {}),
|
||||
decoration: InputDecoration(
|
||||
labelText: tr('ui.userfront.signup.profile.name', fallback: '이름'),
|
||||
labelText: tr('ui.userfront.signup.profile.name'),
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
),
|
||||
@@ -1002,13 +973,11 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
decoration: InputDecoration(
|
||||
labelText: tr(
|
||||
'ui.userfront.signup.profile.affiliation_type',
|
||||
fallback: '소속 유형',
|
||||
),
|
||||
border: const OutlineInputBorder(),
|
||||
helperText: _isAffiliateEmail
|
||||
? tr(
|
||||
'msg.userfront.signup.profile.affiliate_hint',
|
||||
fallback: '가족사 이메일 사용 시 자동으로 선택됩니다.',
|
||||
)
|
||||
: null,
|
||||
),
|
||||
@@ -1016,13 +985,13 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
DropdownMenuItem(
|
||||
value: 'GENERAL',
|
||||
child: Text(
|
||||
tr('domain.affiliation.general', fallback: '일반 사용자'),
|
||||
tr('domain.affiliation.general'),
|
||||
),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
value: 'AFFILIATE',
|
||||
child: Text(
|
||||
tr('domain.affiliation.affiliate', fallback: '가족사 임직원'),
|
||||
tr('domain.affiliation.affiliate'),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -1052,18 +1021,17 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
decoration: InputDecoration(
|
||||
labelText: tr(
|
||||
'ui.userfront.signup.profile.company',
|
||||
fallback: '가족사 선택',
|
||||
),
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
items: [
|
||||
DropdownMenuItem(
|
||||
value: 'HANMAC',
|
||||
child: Text(tr('domain.company.hanmac', fallback: '한맥')),
|
||||
child: Text(tr('domain.company.hanmac')),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
value: 'SAMAN',
|
||||
child: Text(tr('domain.company.saman', fallback: '삼안')),
|
||||
child: Text(tr('domain.company.saman')),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
value: 'PTC',
|
||||
@@ -1071,15 +1039,15 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
),
|
||||
DropdownMenuItem(
|
||||
value: 'JANGHEON',
|
||||
child: Text(tr('domain.company.jangheon', fallback: '장헌')),
|
||||
child: Text(tr('domain.company.jangheon')),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
value: 'BARON',
|
||||
child: Text(tr('domain.company.baron', fallback: '바론')),
|
||||
child: Text(tr('domain.company.baron')),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
value: 'HALLA',
|
||||
child: Text(tr('domain.company.halla', fallback: '한라')),
|
||||
child: Text(tr('domain.company.halla')),
|
||||
),
|
||||
],
|
||||
onChanged: _isAffiliateEmail
|
||||
@@ -1095,10 +1063,9 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
onChanged: (_) => setState(() {}),
|
||||
decoration: InputDecoration(
|
||||
labelText: _affiliationType == 'AFFILIATE'
|
||||
? tr('ui.userfront.signup.profile.department', fallback: '부서명')
|
||||
? tr('ui.userfront.signup.profile.department')
|
||||
: tr(
|
||||
'ui.userfront.signup.profile.department_optional',
|
||||
fallback: '소속 정보 (선택)',
|
||||
),
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
@@ -1111,7 +1078,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
if (_isPolicyLoading) {
|
||||
return tr(
|
||||
'msg.userfront.signup.policy.loading',
|
||||
fallback: '비밀번호 정책을 불러오는 중입니다...',
|
||||
);
|
||||
}
|
||||
final minLength = (_policy?['minLength'] as int?) ?? 12;
|
||||
@@ -1124,7 +1090,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
final parts = <String>[
|
||||
tr(
|
||||
'msg.userfront.signup.policy.min_length',
|
||||
fallback: '최소 {{count}}자 이상',
|
||||
params: {'count': minLength.toString()},
|
||||
),
|
||||
];
|
||||
@@ -1132,27 +1097,25 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
parts.add(
|
||||
tr(
|
||||
'msg.userfront.signup.policy.min_types',
|
||||
fallback: '영문 대/소문자/숫자/특수문자 중 {{count}}가지 이상',
|
||||
params: {'count': minTypes.toString()},
|
||||
),
|
||||
);
|
||||
}
|
||||
if (requiresUpper) {
|
||||
parts.add(tr('msg.userfront.signup.policy.uppercase', fallback: '대문자'));
|
||||
parts.add(tr('msg.userfront.signup.policy.uppercase'));
|
||||
}
|
||||
if (requiresLower) {
|
||||
parts.add(tr('msg.userfront.signup.policy.lowercase', fallback: '소문자'));
|
||||
parts.add(tr('msg.userfront.signup.policy.lowercase'));
|
||||
}
|
||||
if (requiresNumber) {
|
||||
parts.add(tr('msg.userfront.signup.policy.number', fallback: '숫자'));
|
||||
parts.add(tr('msg.userfront.signup.policy.number'));
|
||||
}
|
||||
if (requiresSymbol) {
|
||||
parts.add(tr('msg.userfront.signup.policy.symbol', fallback: '특수문자'));
|
||||
parts.add(tr('msg.userfront.signup.policy.symbol'));
|
||||
}
|
||||
|
||||
return tr(
|
||||
'msg.userfront.signup.policy.summary',
|
||||
fallback: '보안 정책: {{rules}}',
|
||||
params: {'rules': parts.join(', ')},
|
||||
);
|
||||
}
|
||||
@@ -1186,7 +1149,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
Text(
|
||||
tr(
|
||||
'msg.userfront.signup.password.title',
|
||||
fallback: '마지막으로\n비밀번호를 설정해주세요',
|
||||
),
|
||||
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
|
||||
),
|
||||
@@ -1223,7 +1185,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
decoration: InputDecoration(
|
||||
labelText: tr(
|
||||
'ui.userfront.signup.password.label',
|
||||
fallback: '비밀번호',
|
||||
),
|
||||
border: const OutlineInputBorder(),
|
||||
errorText: _passwordError,
|
||||
@@ -1236,7 +1197,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
_cryptoCheck(
|
||||
tr(
|
||||
'msg.userfront.signup.password.rule.min_length',
|
||||
fallback: '{{count}}자 이상',
|
||||
params: {'count': minLength.toString()},
|
||||
),
|
||||
hasLength,
|
||||
@@ -1245,7 +1205,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
_cryptoCheck(
|
||||
tr(
|
||||
'msg.userfront.signup.password.rule.min_types',
|
||||
fallback: '문자 유형 {{count}}가지 이상',
|
||||
params: {'count': minTypes.toString()},
|
||||
),
|
||||
hasTypeCount,
|
||||
@@ -1254,7 +1213,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
_cryptoCheck(
|
||||
tr(
|
||||
'msg.userfront.signup.password.rule.uppercase',
|
||||
fallback: '대문자',
|
||||
),
|
||||
hasUpper,
|
||||
),
|
||||
@@ -1262,20 +1220,18 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
_cryptoCheck(
|
||||
tr(
|
||||
'msg.userfront.signup.password.rule.lowercase',
|
||||
fallback: '소문자',
|
||||
),
|
||||
hasLower,
|
||||
),
|
||||
if (requiresNumber)
|
||||
_cryptoCheck(
|
||||
tr('msg.userfront.signup.password.rule.number', fallback: '숫자'),
|
||||
tr('msg.userfront.signup.password.rule.number'),
|
||||
hasDigit,
|
||||
),
|
||||
if (requiresSymbol)
|
||||
_cryptoCheck(
|
||||
tr(
|
||||
'msg.userfront.signup.password.rule.symbol',
|
||||
fallback: '특수문자',
|
||||
),
|
||||
hasSpecial,
|
||||
),
|
||||
@@ -1290,7 +1246,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
_confirmPasswordError = (val != _passwordController.text)
|
||||
? tr(
|
||||
'msg.userfront.signup.password.mismatch',
|
||||
fallback: '비밀번호가 일치하지 않습니다.',
|
||||
)
|
||||
: null;
|
||||
});
|
||||
@@ -1298,7 +1253,6 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
decoration: InputDecoration(
|
||||
labelText: tr(
|
||||
'ui.userfront.signup.password.confirm_label',
|
||||
fallback: '비밀번호 확인',
|
||||
),
|
||||
border: const OutlineInputBorder(),
|
||||
errorText: _confirmPasswordError,
|
||||
@@ -1352,7 +1306,7 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
backgroundColor: Colors.white,
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
tr('ui.userfront.signup.title', fallback: '회원가입'),
|
||||
tr('ui.userfront.signup.title'),
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
elevation: 0,
|
||||
@@ -1394,7 +1348,7 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
side: const BorderSide(color: Colors.black),
|
||||
),
|
||||
child: Text(
|
||||
tr('ui.common.prev', fallback: '이전'),
|
||||
tr('ui.common.prev'),
|
||||
style: const TextStyle(color: Colors.black),
|
||||
),
|
||||
),
|
||||
@@ -1425,11 +1379,9 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
_currentStep < 4
|
||||
? tr(
|
||||
'ui.userfront.signup.next_step',
|
||||
fallback: '다음 단계',
|
||||
)
|
||||
: tr(
|
||||
'ui.userfront.signup.complete',
|
||||
fallback: '가입 완료',
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user