forked from baron/baron-sso
i18n 경로 오류 및 placeholder 표시 수정
This commit is contained in:
@@ -1,22 +1,59 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:toml/toml.dart';
|
||||
|
||||
import '../../i18n_data.dart';
|
||||
|
||||
class TomlAssetLoader extends AssetLoader {
|
||||
const TomlAssetLoader();
|
||||
|
||||
@override
|
||||
Future<Map<String, dynamic>> load(String path, Locale locale) async {
|
||||
final assetPath = '$path/${locale.languageCode}.toml';
|
||||
try {
|
||||
final content = await rootBundle.loadString(assetPath);
|
||||
final document = TomlDocument.parse(content);
|
||||
return document.toMap();
|
||||
} catch (e) {
|
||||
// 로딩 실패 시 빈 맵을 반환해 렌더링을 지속합니다.
|
||||
return {};
|
||||
}
|
||||
final languageCode = locale.languageCode.toLowerCase();
|
||||
final source = switch (languageCode) {
|
||||
'ko' => koStrings,
|
||||
'en' => enStrings,
|
||||
_ => enStrings,
|
||||
};
|
||||
return _expandFlatTranslations(source);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, dynamic> _expandFlatTranslations(Map<String, String> flatMap) {
|
||||
final nested = <String, dynamic>{};
|
||||
for (final entry in flatMap.entries) {
|
||||
final key = entry.key;
|
||||
if (key.isEmpty) {
|
||||
continue;
|
||||
}
|
||||
final segments = key.split('.');
|
||||
Map<String, dynamic> cursor = nested;
|
||||
for (var index = 0; index < segments.length; index++) {
|
||||
final segment = segments[index];
|
||||
if (segment.isEmpty) {
|
||||
continue;
|
||||
}
|
||||
final isLeaf = index == segments.length - 1;
|
||||
if (isLeaf) {
|
||||
cursor[segment] = _normalizeLocalizationValue(entry.value);
|
||||
continue;
|
||||
}
|
||||
final next = cursor.putIfAbsent(segment, () => <String, dynamic>{});
|
||||
if (next is Map<String, dynamic>) {
|
||||
cursor = next;
|
||||
continue;
|
||||
}
|
||||
final replacement = <String, dynamic>{};
|
||||
cursor[segment] = replacement;
|
||||
cursor = replacement;
|
||||
}
|
||||
}
|
||||
return nested;
|
||||
}
|
||||
|
||||
String _normalizeLocalizationValue(String value) {
|
||||
return value.replaceAllMapped(
|
||||
RegExp(r'\{\{[[:space:]]*([a-zA-Z0-9_]+)[[:space:]]*\}\}'),
|
||||
(match) => '{${match.group(1)}}',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -57,6 +57,40 @@ class _ConsentScreenState extends State<ConsentScreen> {
|
||||
};
|
||||
}
|
||||
|
||||
String _renderConsentText(String key, {String? fallback}) {
|
||||
return tr(key, fallback: fallback)
|
||||
.replaceAll(r'\\n', '\n')
|
||||
.replaceAll(r'\n', '\n')
|
||||
.replaceAll('\\\n', '\n');
|
||||
}
|
||||
|
||||
String _renderScopeCountLabel(int count) {
|
||||
return tr(
|
||||
'msg.userfront.consent.scope_count',
|
||||
fallback: 'Total {{count}}',
|
||||
params: {'count': '$count'},
|
||||
).replaceAll('{$count}', '$count');
|
||||
}
|
||||
|
||||
String _scopeDisplayLabel(String scope) {
|
||||
if (scope == 'offline_access') {
|
||||
return 'offline access';
|
||||
}
|
||||
return scope.replaceAll('_', ' ');
|
||||
}
|
||||
|
||||
String _renderClientIdLabel(String clientId) {
|
||||
final raw = tr(
|
||||
'msg.userfront.consent.client_id',
|
||||
fallback: 'Client ID: {{id}}',
|
||||
);
|
||||
final normalized = raw
|
||||
.replaceAll('{{id}}', '')
|
||||
.replaceAll('{id}', '')
|
||||
.trimRight();
|
||||
return '$normalized $clientId';
|
||||
}
|
||||
|
||||
Future<void> _fetchConsentInfo() async {
|
||||
try {
|
||||
final info = await AuthProxyService.getConsentInfo(
|
||||
@@ -271,7 +305,7 @@ class _ConsentScreenState extends State<ConsentScreen> {
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
tr('msg.userfront.consent.description'),
|
||||
_renderConsentText('msg.userfront.consent.description'),
|
||||
style: TextStyle(fontSize: 14, color: Colors.grey[600]),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
@@ -318,11 +352,7 @@ class _ConsentScreenState extends State<ConsentScreen> {
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
tr(
|
||||
'msg.userfront.consent.client_id',
|
||||
fallback: 'Client ID: {{id}}',
|
||||
params: {'id': clientId},
|
||||
),
|
||||
_renderClientIdLabel(clientId),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.grey[500],
|
||||
@@ -349,11 +379,7 @@ class _ConsentScreenState extends State<ConsentScreen> {
|
||||
),
|
||||
),
|
||||
Text(
|
||||
tr(
|
||||
'msg.userfront.consent.scope_count',
|
||||
fallback: 'Total {{count}}',
|
||||
params: {'count': '${requestedScopes.length}'},
|
||||
),
|
||||
_renderScopeCountLabel(requestedScopes.length),
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).primaryColor,
|
||||
@@ -371,7 +397,7 @@ class _ConsentScreenState extends State<ConsentScreen> {
|
||||
|
||||
return CheckboxListTile(
|
||||
title: Text(
|
||||
scope, // 스코프 키 (예: openid)
|
||||
_scopeDisplayLabel(scope),
|
||||
style: const TextStyle(fontWeight: FontWeight.w500),
|
||||
),
|
||||
subtitle: Text(description),
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user