forked from baron/baron-sso
#269 진행. 리다이렉트 등 파라미터 전체 전달
This commit is contained in:
99
userfront/lib/core/i18n/locale_registry.dart
Normal file
99
userfront/lib/core/i18n/locale_registry.dart
Normal file
@@ -0,0 +1,99 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
const _translationAssetPrefix = 'assets/translations/';
|
||||
const _templateFileName = 'template.toml';
|
||||
const _safeFallbackLocaleCode = 'en';
|
||||
|
||||
List<String> extractSupportedLocaleCodesFromAssets(Iterable<String> assets) {
|
||||
final localeCodes = <String>{};
|
||||
for (final asset in assets) {
|
||||
if (!asset.startsWith(_translationAssetPrefix) ||
|
||||
!asset.endsWith('.toml')) {
|
||||
continue;
|
||||
}
|
||||
final fileName = asset.substring(_translationAssetPrefix.length);
|
||||
if (fileName.contains('/') || fileName == _templateFileName) {
|
||||
continue;
|
||||
}
|
||||
final rawCode = fileName.substring(0, fileName.length - '.toml'.length);
|
||||
final normalized = rawCode.toLowerCase().replaceAll('_', '-');
|
||||
if (_isValidLocaleCode(normalized)) {
|
||||
localeCodes.add(normalized);
|
||||
}
|
||||
}
|
||||
|
||||
final sorted = localeCodes.toList()..sort();
|
||||
return sorted;
|
||||
}
|
||||
|
||||
class LocaleRegistry {
|
||||
static final Set<String> _localeCodes = <String>{};
|
||||
static bool _initialized = false;
|
||||
|
||||
static Future<void> initialize({AssetBundle? assetBundle}) async {
|
||||
if (_initialized) {
|
||||
return;
|
||||
}
|
||||
final bundle = assetBundle ?? rootBundle;
|
||||
try {
|
||||
final manifest = await AssetManifest.loadFromAssetBundle(bundle);
|
||||
final extracted = extractSupportedLocaleCodesFromAssets(
|
||||
manifest.listAssets(),
|
||||
);
|
||||
_localeCodes.addAll(extracted);
|
||||
} catch (_) {
|
||||
// manifest 로딩 실패 시 안전 fallback으로 계속 진행합니다.
|
||||
}
|
||||
|
||||
if (_localeCodes.isEmpty) {
|
||||
_localeCodes.add(_safeFallbackLocaleCode);
|
||||
}
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
static List<String> get supportedLocaleCodes {
|
||||
final sorted = _localeCodes.toList()..sort();
|
||||
return List.unmodifiable(sorted);
|
||||
}
|
||||
|
||||
static String get fallbackLocaleCode {
|
||||
final supported = supportedLocaleCodes;
|
||||
if (supported.isEmpty) {
|
||||
return _safeFallbackLocaleCode;
|
||||
}
|
||||
if (supported.contains('en')) {
|
||||
return 'en';
|
||||
}
|
||||
return supported.first;
|
||||
}
|
||||
|
||||
static bool contains(String code) {
|
||||
return _localeCodes.contains(code.toLowerCase());
|
||||
}
|
||||
|
||||
@visibleForTesting
|
||||
static void setSupportedLocaleCodesForTest(Iterable<String> localeCodes) {
|
||||
_localeCodes
|
||||
..clear()
|
||||
..addAll(
|
||||
localeCodes
|
||||
.map((code) => code.toLowerCase().replaceAll('_', '-'))
|
||||
.where(_isValidLocaleCode),
|
||||
);
|
||||
if (_localeCodes.isEmpty) {
|
||||
_localeCodes.add(_safeFallbackLocaleCode);
|
||||
}
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
@visibleForTesting
|
||||
static void resetForTest() {
|
||||
_localeCodes.clear();
|
||||
_initialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool _isValidLocaleCode(String value) {
|
||||
return RegExp(r'^[a-z]{2,3}$').hasMatch(value);
|
||||
}
|
||||
@@ -1,34 +1,46 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'locale_storage.dart';
|
||||
import 'locale_registry.dart';
|
||||
|
||||
const supportedLocaleCodes = ['en', 'ko'];
|
||||
const defaultLocaleCode = 'en';
|
||||
String get defaultLocaleCode => LocaleRegistry.fallbackLocaleCode;
|
||||
|
||||
String normalizeLocaleCode(String? code) {
|
||||
final supportedLocaleCodes = LocaleRegistry.supportedLocaleCodes;
|
||||
final fallbackLocaleCode = LocaleRegistry.fallbackLocaleCode;
|
||||
|
||||
if (code == null || code.isEmpty) {
|
||||
return defaultLocaleCode;
|
||||
return fallbackLocaleCode;
|
||||
}
|
||||
final normalized = code.toLowerCase();
|
||||
if (normalized == 'ko' || normalized.startsWith('ko-')) {
|
||||
return 'ko';
|
||||
final normalized = code.toLowerCase().replaceAll('_', '-');
|
||||
if (supportedLocaleCodes.contains(normalized)) {
|
||||
return normalized;
|
||||
}
|
||||
if (normalized == 'en' || normalized.startsWith('en-')) {
|
||||
return 'en';
|
||||
final languageCode = normalized.split('-').first;
|
||||
if (supportedLocaleCodes.contains(languageCode)) {
|
||||
return languageCode;
|
||||
}
|
||||
return defaultLocaleCode;
|
||||
return fallbackLocaleCode;
|
||||
}
|
||||
|
||||
String resolvePreferredLocaleCode() {
|
||||
final stored = LocaleStorage.read();
|
||||
if (stored != null && supportedLocaleCodes.contains(stored)) {
|
||||
return stored;
|
||||
if (stored != null && stored.isNotEmpty) {
|
||||
final normalizedStored = normalizeLocaleCode(stored);
|
||||
if (LocaleRegistry.contains(normalizedStored)) {
|
||||
return normalizedStored;
|
||||
}
|
||||
}
|
||||
final deviceLocale = PlatformDispatcher.instance.locale;
|
||||
return normalizeLocaleCode(deviceLocale.languageCode);
|
||||
final languageTag =
|
||||
deviceLocale.countryCode == null || deviceLocale.countryCode!.isEmpty
|
||||
? deviceLocale.languageCode
|
||||
: '${deviceLocale.languageCode}-${deviceLocale.countryCode}';
|
||||
return normalizeLocaleCode(languageTag);
|
||||
}
|
||||
|
||||
String? extractLocaleFromPath(Uri uri) {
|
||||
final supportedLocaleCodes = LocaleRegistry.supportedLocaleCodes;
|
||||
if (uri.pathSegments.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
@@ -40,8 +52,10 @@ String? extractLocaleFromPath(Uri uri) {
|
||||
}
|
||||
|
||||
String stripLocalePath(Uri uri) {
|
||||
final supportedLocaleCodes = LocaleRegistry.supportedLocaleCodes;
|
||||
final segments = uri.pathSegments;
|
||||
if (segments.isNotEmpty && supportedLocaleCodes.contains(segments.first)) {
|
||||
if (segments.isNotEmpty &&
|
||||
supportedLocaleCodes.contains(segments.first.toLowerCase())) {
|
||||
final rest = segments.skip(1).join('/');
|
||||
if (rest.isEmpty) {
|
||||
return '/';
|
||||
@@ -52,18 +66,23 @@ String stripLocalePath(Uri uri) {
|
||||
}
|
||||
|
||||
String buildLocalizedPath(String localeCode, Uri uri) {
|
||||
final supportedLocaleCodes = LocaleRegistry.supportedLocaleCodes;
|
||||
final segments = uri.pathSegments;
|
||||
Iterable<String> restSegments = segments;
|
||||
if (segments.isNotEmpty) {
|
||||
final head = segments.first.toLowerCase();
|
||||
if (supportedLocaleCodes.contains(head) || head.length == 2) {
|
||||
if (supportedLocaleCodes.contains(head)) {
|
||||
restSegments = segments.skip(1);
|
||||
}
|
||||
}
|
||||
final newSegments = [localeCode, ...restSegments];
|
||||
final path = '/${newSegments.join('/')}';
|
||||
if (uri.queryParameters.isEmpty) {
|
||||
return path;
|
||||
}
|
||||
return Uri(path: path, queryParameters: uri.queryParameters).toString();
|
||||
final queryPart = uri.hasQuery ? '?${uri.query}' : '';
|
||||
final fragmentPart = uri.fragment.isNotEmpty ? '#${uri.fragment}' : '';
|
||||
return '$path$queryPart$fragmentPart';
|
||||
}
|
||||
|
||||
String buildSigninRedirectPath(String localeCode, Uri uri) {
|
||||
final queryPart = uri.hasQuery ? '?${uri.query}' : '';
|
||||
return '/$localeCode/signin$queryPart';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user