1
0
forked from baron/baron-sso

userfront i18n placeholder 치환과 번역 렌더링 오류 수정

This commit is contained in:
2026-04-06 17:48:07 +09:00
parent beae6bb4b1
commit d086b7ea3c
4 changed files with 88 additions and 30 deletions

View File

@@ -26,6 +26,18 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
Map<String, dynamic>? _policy; Map<String, dynamic>? _policy;
bool _isPolicyLoading = false; bool _isPolicyLoading = false;
String _renderTranslatedText(
String key, {
String? fallback,
Map<String, String> values = const {},
}) {
var text = tr(key, fallback: fallback);
values.forEach((name, value) {
text = text.replaceAll('{{$name}}', value).replaceAll('{$name}', value);
});
return text;
}
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@@ -123,16 +135,16 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
final requiresSymbol = _policy?['nonAlphanumeric'] ?? true; final requiresSymbol = _policy?['nonAlphanumeric'] ?? true;
final parts = <String>[ final parts = <String>[
tr( _renderTranslatedText(
'msg.userfront.reset.policy.min_length', 'msg.userfront.reset.policy.min_length',
params: {'count': '$minLength'}, values: {'count': '$minLength'},
), ),
]; ];
if (minTypes > 0) { if (minTypes > 0) {
parts.add( parts.add(
tr( _renderTranslatedText(
'msg.userfront.reset.policy.min_types', 'msg.userfront.reset.policy.min_types',
params: {'count': '$minTypes'}, values: {'count': '$minTypes'},
), ),
); );
} }

View File

@@ -76,6 +76,18 @@ class _SignupScreenState extends State<SignupScreen> {
'baroncs.co.kr': 'BARON', 'baroncs.co.kr': 'BARON',
}; };
String _renderTranslatedText(
String key, {
String? fallback,
Map<String, String> values = const {},
}) {
var text = tr(key, fallback: fallback);
values.forEach((name, value) {
text = text.replaceAll('{{$name}}', value).replaceAll('{$name}', value);
});
return text;
}
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@@ -1729,16 +1741,16 @@ class _SignupScreenState extends State<SignupScreen> {
final requiresSymbol = _policy?['nonAlphanumeric'] ?? true; final requiresSymbol = _policy?['nonAlphanumeric'] ?? true;
final parts = <String>[ final parts = <String>[
tr( _renderTranslatedText(
'msg.userfront.signup.policy.min_length', 'msg.userfront.signup.policy.min_length',
params: {'count': minLength.toString()}, values: {'count': minLength.toString()},
), ),
]; ];
if (minTypes > 0) { if (minTypes > 0) {
parts.add( parts.add(
tr( _renderTranslatedText(
'msg.userfront.signup.policy.min_types', 'msg.userfront.signup.policy.min_types',
params: {'count': minTypes.toString()}, values: {'count': minTypes.toString()},
), ),
); );
} }
@@ -1755,9 +1767,9 @@ class _SignupScreenState extends State<SignupScreen> {
parts.add(tr('msg.userfront.signup.policy.symbol')); parts.add(tr('msg.userfront.signup.policy.symbol'));
} }
return tr( return _renderTranslatedText(
'msg.userfront.signup.policy.summary', 'msg.userfront.signup.policy.summary',
params: {'rules': parts.join(', ')}, values: {'rules': parts.join(', ')},
); );
} }

View File

@@ -55,6 +55,18 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
bool _showAllActivities = false; bool _showAllActivities = false;
final Set<String> _revokedClientIds = {}; final Set<String> _revokedClientIds = {};
String _renderTranslatedText(
String key, {
String? fallback,
Map<String, String> values = const {},
}) {
var text = tr(key, fallback: fallback);
values.forEach((name, value) {
text = text.replaceAll('{{$name}}', value).replaceAll('{$name}', value);
});
return text;
}
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@@ -700,10 +712,10 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
final clientId = log.clientId; final clientId = log.clientId;
final tooltip = clientId.isEmpty final tooltip = clientId.isEmpty
? tr('msg.userfront.dashboard.client_id_missing') ? tr('msg.userfront.dashboard.client_id_missing')
: tr( : _renderTranslatedText(
'msg.userfront.dashboard.client_id', 'msg.userfront.dashboard.client_id',
fallback: 'Client ID: {{id}}', fallback: 'Client ID: {{id}}',
params: {'id': clientId}, values: {'id': clientId},
); );
final baseStyle = style ?? const TextStyle(); final baseStyle = style ?? const TextStyle();
final emphasisStyle = clientId.isEmpty final emphasisStyle = clientId.isEmpty
@@ -891,7 +903,11 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
tr('msg.userfront.greeting', params: {'name': userName}), _renderTranslatedText(
'msg.userfront.greeting',
fallback: 'Hello, {{name}}.',
values: {'name': userName},
),
style: const TextStyle( style: const TextStyle(
fontSize: 22, fontSize: 22,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@@ -1122,18 +1138,18 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
const SizedBox(height: 12), const SizedBox(height: 12),
if (browserLabel.isNotEmpty) if (browserLabel.isNotEmpty)
Text( Text(
tr( _renderTranslatedText(
'msg.userfront.dashboard.sessions.browser', 'msg.userfront.dashboard.sessions.browser',
params: {'value': browserLabel}, values: {'value': browserLabel},
), ),
style: TextStyle(fontSize: 13, color: Colors.grey[700]), style: TextStyle(fontSize: 13, color: Colors.grey[700]),
), ),
if (osLabel.isNotEmpty) ...[ if (osLabel.isNotEmpty) ...[
const SizedBox(height: 4), const SizedBox(height: 4),
Text( Text(
tr( _renderTranslatedText(
'msg.userfront.dashboard.sessions.os', 'msg.userfront.dashboard.sessions.os',
params: {'value': osLabel}, values: {'value': osLabel},
), ),
style: TextStyle(fontSize: 13, color: Colors.grey[700]), style: TextStyle(fontSize: 13, color: Colors.grey[700]),
), ),
@@ -1142,18 +1158,20 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
if (session.clientId.trim().isNotEmpty) ...[ if (session.clientId.trim().isNotEmpty) ...[
const SizedBox(height: 6), const SizedBox(height: 6),
Text( Text(
tr( _renderTranslatedText(
'msg.userfront.dashboard.client_id', 'msg.userfront.dashboard.client_id',
params: {'id': session.clientId}, fallback: 'Client ID: {{id}}',
values: {'id': session.clientId},
), ),
style: TextStyle(fontSize: 12, color: Colors.grey[600]), style: TextStyle(fontSize: 12, color: Colors.grey[600]),
), ),
], ],
const SizedBox(height: 8), const SizedBox(height: 8),
Text( Text(
tr( _renderTranslatedText(
'msg.userfront.dashboard.sessions.session_id', 'msg.userfront.dashboard.sessions.session_id',
params: {'id': _compactSessionId(session.sessionId)}, fallback: 'Session ID: {{id}}',
values: {'id': _compactSessionId(session.sessionId)},
), ),
style: TextStyle(fontSize: 12, color: Colors.grey[600]), style: TextStyle(fontSize: 12, color: Colors.grey[600]),
), ),
@@ -1956,10 +1974,10 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
), ),
const SizedBox(height: 6), const SizedBox(height: 6),
_selectableText( _selectableText(
tr( _renderTranslatedText(
'msg.userfront.audit.session_id', 'msg.userfront.audit.session_id',
fallback: 'Session ID: {{value}}', fallback: 'Session ID: {{value}}',
params: { values: {
'value': log.sessionId.isEmpty 'value': log.sessionId.isEmpty
? tr('ui.common.hyphen', fallback: '-') ? tr('ui.common.hyphen', fallback: '-')
: log.sessionId, : log.sessionId,

View File

@@ -57,6 +57,18 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
Map<String, dynamic>? _passwordPolicy; Map<String, dynamic>? _passwordPolicy;
bool _isPasswordPolicyLoading = false; bool _isPasswordPolicyLoading = false;
String _renderTranslatedText(
String key, {
String? fallback,
Map<String, String> values = const {},
}) {
var text = tr(key, fallback: fallback);
values.forEach((name, value) {
text = text.replaceAll('{{$name}}', value).replaceAll('{$name}', value);
});
return text;
}
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@@ -98,16 +110,16 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
final requiresSymbol = _passwordPolicy?['nonAlphanumeric'] ?? true; final requiresSymbol = _passwordPolicy?['nonAlphanumeric'] ?? true;
final parts = <String>[ final parts = <String>[
tr( _renderTranslatedText(
'msg.userfront.signup.policy.min_length', 'msg.userfront.signup.policy.min_length',
params: {'count': '$minLength'}, values: {'count': '$minLength'},
), ),
]; ];
if (minTypes > 0) { if (minTypes > 0) {
parts.add( parts.add(
tr( _renderTranslatedText(
'msg.userfront.signup.policy.min_types', 'msg.userfront.signup.policy.min_types',
params: {'count': '$minTypes'}, values: {'count': '$minTypes'},
), ),
); );
} }
@@ -124,9 +136,9 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
parts.add(tr('msg.userfront.signup.policy.symbol')); parts.add(tr('msg.userfront.signup.policy.symbol'));
} }
return tr( return _renderTranslatedText(
'msg.userfront.signup.policy.summary', 'msg.userfront.signup.policy.summary',
params: {'rules': parts.join(", ")}, values: {'rules': parts.join(", ")},
); );
} }
@@ -688,7 +700,11 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
tr('msg.userfront.profile.greeting', params: {'name': name}), _renderTranslatedText(
'msg.userfront.profile.greeting',
fallback: 'Hello, {{name}}.',
values: {'name': name},
),
style: const TextStyle( style: const TextStyle(
fontSize: 20, fontSize: 20,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,