import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; const _translationAssetPrefix = 'assets/translations/'; const _templateFileName = 'template.toml'; const _safeFallbackLocaleCode = 'en'; List extractSupportedLocaleCodesFromAssets(Iterable assets) { final localeCodes = {}; 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 _localeCodes = {}; static bool _initialized = false; static void primeWithDefaults({ Iterable localeCodes = const ['en', 'ko'], }) { if (_localeCodes.isNotEmpty) { return; } _localeCodes.addAll( localeCodes .map((code) => code.toLowerCase().replaceAll('_', '-')) .where(_isValidLocaleCode), ); if (_localeCodes.isEmpty) { _localeCodes.add(_safeFallbackLocaleCode); } } static Future 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 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 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); }