@@ -24,6 +24,9 @@ abstract class AssetLoader {
24
24
/// default used is RootBundleAssetLoader which uses flutter's assetloader
25
25
///
26
26
class RootBundleAssetLoader extends AssetLoader {
27
+ // Place inside class RootBundleAssetLoader
28
+ static const int _maxLinkedDepth = 32 ;
29
+
27
30
const RootBundleAssetLoader ();
28
31
29
32
String getLocalePath (String basePath, Locale locale) {
@@ -35,28 +38,48 @@ class RootBundleAssetLoader extends AssetLoader {
35
38
}
36
39
37
40
Future <Map <String , dynamic >> _getLinkedTranslationFileDataFromBaseJson (
38
- String basePath, Locale locale, Map <String , dynamic > baseJson,
39
- {List <String > fileLoaded = const []}) async {
40
- Map <String , dynamic > fullJson = Map <String , dynamic >.from (baseJson);
41
+ String basePath,
42
+ Locale locale,
43
+ Map <String , dynamic > baseJson, {
44
+ required Set <String > visited,
45
+ int depth = 0 ,
46
+ }) async {
47
+ if (depth > _maxLinkedDepth) {
48
+ throw StateError ('Maximum linked files depth ($_maxLinkedDepth ) exceeded for $locale at $basePath .' );
49
+ }
50
+
51
+ final Map <String , dynamic > fullJson = Map <String , dynamic >.from (baseJson);
41
52
42
- for (var entry in baseJson.entries) {
43
- var key = entry.key;
53
+ for (final entry in baseJson.entries) {
54
+ final key = entry.key;
44
55
var value = entry.value;
45
56
46
57
if (value is String && value.startsWith (':/' )) {
47
- String filePath = value.substring (2 );
58
+ final rawPath = value.substring (2 ).trim ();
59
+ final linkedAssetPath = _getLinkedLocalePath (basePath, rawPath, locale);
48
60
49
- if (fileLoaded .contains (filePath )) {
50
- throw Exception ( 'Circular reference detected: $ filePath is loaded multiple times ' );
61
+ if (visited .contains (linkedAssetPath )) {
62
+ throw StateError ( 'Cyclic linked files detected at "$ linkedAssetPath " (key: "$ key "). ' );
51
63
}
52
64
53
- fileLoaded.add (filePath);
54
- value = json.decode (await rootBundle.loadString (_getLinkedLocalePath (basePath, filePath, locale)));
55
- }
65
+ final Map <String , dynamic > linkedJson =
66
+ json.decode (await rootBundle.loadString (linkedAssetPath)) as Map <String , dynamic >;
56
67
57
- if (value is Map <String , dynamic >) {
58
- fullJson[key] =
59
- await _getLinkedTranslationFileDataFromBaseJson (basePath, locale, value, fileLoaded: fileLoaded);
68
+ visited.add (linkedAssetPath);
69
+ try {
70
+ final resolved = await _getLinkedTranslationFileDataFromBaseJson (
71
+ basePath,
72
+ locale,
73
+ linkedJson,
74
+ visited: visited,
75
+ depth: depth + 1 ,
76
+ );
77
+ fullJson[key] = resolved;
78
+ } catch (e) {
79
+ throw StateError (
80
+ 'Error resolving linked file "$linkedAssetPath " for key "$key ": $e ' ,
81
+ );
82
+ }
60
83
}
61
84
}
62
85
@@ -69,6 +92,11 @@ class RootBundleAssetLoader extends AssetLoader {
69
92
EasyLocalization .logger.debug ('Load asset from $path ' );
70
93
71
94
Map <String , dynamic > baseJson = json.decode (await rootBundle.loadString (localePath));
72
- return await _getLinkedTranslationFileDataFromBaseJson (path, locale, baseJson);
95
+ return await _getLinkedTranslationFileDataFromBaseJson (
96
+ path,
97
+ locale,
98
+ baseJson,
99
+ visited: < String > {},
100
+ );
73
101
}
74
102
}
0 commit comments