Skip to content

Commit 9fa05fb

Browse files
committed
feat: split switch block into smaller blocks
1 parent 57b6f14 commit 9fa05fb

16 files changed

+215
-70
lines changed

slang/example/lib/i18n/strings_de.g.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,15 @@ class _TranslationsMainScreenDe implements TranslationsMainScreenEn {
6161

6262
/// The flat map containing all translations for locale <de>.
6363
/// Only for edge cases! For simple maps, use the map function of this library.
64+
///
65+
/// The Dart AOT compiler has issues with very large switch statements,
66+
/// so the map is split into smaller functions (1024 entries each).
6467
extension on TranslationsDe {
6568
dynamic _flatMapFunction(String path) {
69+
return _flatMapFunction$0(path);
70+
}
71+
72+
dynamic _flatMapFunction$0(String path) {
6673
switch (path) {
6774
case 'mainScreen.title': return 'Ein deutscher Titel';
6875
case 'mainScreen.counter': return ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('de'))(n,

slang/example/lib/i18n/strings_en.g.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,15 @@ class TranslationsMainScreenEn {
7070

7171
/// The flat map containing all translations for locale <en>.
7272
/// Only for edge cases! For simple maps, use the map function of this library.
73+
///
74+
/// The Dart AOT compiler has issues with very large switch statements,
75+
/// so the map is split into smaller functions (1024 entries each).
7376
extension on Translations {
7477
dynamic _flatMapFunction(String path) {
78+
return _flatMapFunction$0(path);
79+
}
80+
81+
dynamic _flatMapFunction$0(String path) {
7582
switch (path) {
7683
case 'mainScreen.title': return 'An English Title';
7784
case 'mainScreen.counter': return ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n,

slang/example/lib/i18n/strings_fr_FR.g.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,15 @@ class _TranslationsMainScreenFrFr implements TranslationsMainScreenEn {
6161

6262
/// The flat map containing all translations for locale <fr-FR>.
6363
/// Only for edge cases! For simple maps, use the map function of this library.
64+
///
65+
/// The Dart AOT compiler has issues with very large switch statements,
66+
/// so the map is split into smaller functions (1024 entries each).
6467
extension on TranslationsFrFr {
6568
dynamic _flatMapFunction(String path) {
69+
return _flatMapFunction$0(path);
70+
}
71+
72+
dynamic _flatMapFunction$0(String path) {
6673
switch (path) {
6774
case 'mainScreen.title': return 'Le titre français';
6875
case 'mainScreen.counter': return ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('fr'))(n,
Lines changed: 116 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
part of 'generate_translations.dart';
22

3+
const _maxSwitchCasesPerBlock = 1024;
4+
35
/// Generates the flat map(s) containing all translations for one locale.
46
String generateTranslationMap(
57
GenerateConfig config,
@@ -11,98 +13,142 @@ String generateTranslationMap(
1113
'/// The flat map containing all translations for locale <${localeData.locale.languageTag}>.');
1214
buffer.writeln(
1315
'/// Only for edge cases! For simple maps, use the map function of this library.');
14-
16+
buffer.writeln('///');
17+
buffer.writeln(
18+
'/// The Dart AOT compiler has issues with very large switch statements,');
19+
buffer.writeln(
20+
'/// so the map is split into smaller functions ($_maxSwitchCasesPerBlock entries each).');
1521
buffer.writeln(
1622
'extension on ${localeData.base ? config.className : getClassNameRoot(className: config.className, locale: localeData.locale)} {');
17-
buffer.writeln('\tdynamic _flatMapFunction(String path) {');
18-
buffer.writeln('\t\tswitch (path) {');
1923

20-
_generateTranslationMapRecursive(
21-
buffer: buffer,
22-
curr: localeData.root,
23-
config: config,
24-
language: localeData.locale.language,
25-
);
24+
final flatList = _toFlatList(localeData.root);
25+
final flatListSplits = <List<Node>>[];
26+
for (var i = 0; i < flatList.length; i += _maxSwitchCasesPerBlock) {
27+
flatListSplits.add(flatList.sublist(
28+
i,
29+
min(i + _maxSwitchCasesPerBlock, flatList.length),
30+
));
31+
}
2632

27-
buffer.writeln('\t\t\tdefault: return null;');
28-
buffer.writeln('\t\t}');
33+
buffer.writeln('\tdynamic _flatMapFunction(String path) {');
34+
buffer.write('\t\treturn ');
35+
for (var i = 0; i < flatListSplits.length; i++) {
36+
if (i == 0) {
37+
buffer.write('_flatMapFunction\$$i(path)');
38+
} else {
39+
buffer.write('\n\t\t\t?? _flatMapFunction\$$i(path)');
40+
}
41+
}
42+
buffer.writeln(';');
2943
buffer.writeln('\t}');
44+
45+
// Generate split functions
46+
for (var i = 0; i < flatListSplits.length; i++) {
47+
buffer.writeln();
48+
buffer.writeln('\tdynamic _flatMapFunction\$$i(String path) {');
49+
buffer.writeln('\t\tswitch (path) {');
50+
51+
_generateTranslationMap(
52+
buffer: buffer,
53+
flatMap: flatListSplits[i],
54+
config: config,
55+
language: localeData.locale.language,
56+
);
57+
58+
buffer.writeln('\t\t\tdefault: return null;');
59+
buffer.writeln('\t\t}');
60+
buffer.writeln('\t}');
61+
}
62+
3063
buffer.writeln('}');
3164

3265
return buffer.toString();
3366
}
3467

35-
void _generateTranslationMapRecursive({
68+
void _generateTranslationMap({
3669
required StringBuffer buffer,
37-
required Node curr,
70+
required Iterable<Node> flatMap,
3871
required GenerateConfig config,
3972
required String language,
4073
}) {
41-
if (curr is StringTextNode) {
42-
final translationOverrides = config.translationOverrides
43-
? 'TranslationOverrides.string(_root.\$meta, \'${curr.path}\', ${_toParameterMap(curr.params)}) ?? '
44-
: '';
45-
final stringLiteral =
46-
getStringLiteral(curr.content, curr.links.length, config.obfuscation);
47-
if (curr.params.isEmpty) {
48-
buffer.writeln(
49-
'\t\t\tcase \'${curr.path}\': return $translationOverrides$stringLiteral;');
50-
} else {
51-
buffer.writeln(
52-
'\t\t\tcase \'${curr.path}\': return ${_toParameterList(curr.params, curr.paramTypeMap)} => $translationOverrides$stringLiteral;');
53-
}
54-
} else if (curr is RichTextNode) {
55-
buffer.write('\t\t\tcase \'${curr.path}\': return ');
56-
_addRichTextCall(
57-
buffer: buffer,
58-
config: config,
59-
node: curr,
60-
includeParameters: true,
61-
variableNameResolver: null,
62-
forceArrow: false,
63-
depth: 2,
64-
forceSemicolon: true,
65-
);
66-
} else if (curr is ListNode) {
67-
// recursive
68-
for (final child in curr.entries) {
69-
_generateTranslationMapRecursive(
74+
for (final curr in flatMap) {
75+
if (curr is StringTextNode) {
76+
final translationOverrides = config.translationOverrides
77+
? 'TranslationOverrides.string(_root.\$meta, \'${curr.path}\', ${_toParameterMap(curr.params)}) ?? '
78+
: '';
79+
final stringLiteral =
80+
getStringLiteral(curr.content, curr.links.length, config.obfuscation);
81+
if (curr.params.isEmpty) {
82+
buffer.writeln(
83+
'\t\t\tcase \'${curr.path}\': return $translationOverrides$stringLiteral;');
84+
} else {
85+
buffer.writeln(
86+
'\t\t\tcase \'${curr.path}\': return ${_toParameterList(curr.params, curr.paramTypeMap)} => $translationOverrides$stringLiteral;');
87+
}
88+
} else if (curr is RichTextNode) {
89+
buffer.write('\t\t\tcase \'${curr.path}\': return ');
90+
_addRichTextCall(
7091
buffer: buffer,
71-
curr: child,
92+
config: config,
93+
node: curr,
94+
includeParameters: true,
95+
variableNameResolver: null,
96+
forceArrow: false,
97+
depth: 2,
98+
forceSemicolon: true,
99+
);
100+
} else if (curr is ListNode) {
101+
_generateTranslationMap(
102+
buffer: buffer,
103+
flatMap: curr.entries,
72104
config: config,
73105
language: language,
74106
);
75-
}
76-
} else if (curr is ObjectNode) {
77-
// recursive
78-
for (final child in curr.entries.values) {
79-
_generateTranslationMapRecursive(
107+
} else if (curr is PluralNode) {
108+
buffer.write('\t\t\tcase \'${curr.path}\': return ');
109+
_addPluralCall(
80110
buffer: buffer,
81-
curr: child,
82111
config: config,
83112
language: language,
113+
node: curr,
114+
depth: 2,
115+
forceSemicolon: true,
116+
);
117+
} else if (curr is ContextNode) {
118+
buffer.write('\t\t\tcase \'${curr.path}\': return ');
119+
_addContextCall(
120+
buffer: buffer,
121+
config: config,
122+
node: curr,
123+
depth: 2,
124+
forceSemicolon: true,
84125
);
126+
} else {
127+
throw 'This should not happen';
85128
}
86-
} else if (curr is PluralNode) {
87-
buffer.write('\t\t\tcase \'${curr.path}\': return ');
88-
_addPluralCall(
89-
buffer: buffer,
90-
config: config,
91-
language: language,
92-
node: curr,
93-
depth: 2,
94-
forceSemicolon: true,
95-
);
96-
} else if (curr is ContextNode) {
97-
buffer.write('\t\t\tcase \'${curr.path}\': return ');
98-
_addContextCall(
99-
buffer: buffer,
100-
config: config,
101-
node: curr,
102-
depth: 2,
103-
forceSemicolon: true,
104-
);
105-
} else {
106-
throw 'This should not happen';
107129
}
108130
}
131+
132+
List<Node> _toFlatList(ObjectNode root) {
133+
final result = <Node>[];
134+
135+
void flatten(Node node) {
136+
if (node is ListNode) {
137+
for (final entry in node.entries) {
138+
flatten(entry);
139+
}
140+
} else if (node is ObjectNode) {
141+
for (final value in node.values) {
142+
flatten(value);
143+
}
144+
} else {
145+
result.add(node);
146+
}
147+
}
148+
149+
for (final value in root.values) {
150+
flatten(value);
151+
}
152+
153+
return result;
154+
}

slang/lib/src/builder/generator/generate_translations.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'dart:collection';
2+
import 'dart:math';
23

34
import 'package:collection/collection.dart';
45
import 'package:slang/src/builder/generator/helper.dart';

slang/test/integration/resources/main/_expected_de.output

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,15 @@ class _TranslationsOnboarding$modifierPages$0i1$De with MPage implements Transla
184184

185185
/// The flat map containing all translations for locale <de>.
186186
/// Only for edge cases! For simple maps, use the map function of this library.
187+
///
188+
/// The Dart AOT compiler has issues with very large switch statements,
189+
/// so the map is split into smaller functions (1024 entries each).
187190
extension on TranslationsDe {
188191
dynamic _flatMapFunction(String path) {
192+
return _flatMapFunction$0(path);
193+
}
194+
195+
dynamic _flatMapFunction$0(String path) {
189196
switch (path) {
190197
case 'onboarding.welcome': return ({required Object fullName}) => 'Willkommen ${fullName}';
191198
case 'onboarding.welcomeAlias': return ({required Object fullName}) => _root.onboarding.welcome(fullName: fullName);

slang/test/integration/resources/main/_expected_en.output

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,8 +229,15 @@ class TranslationsOnboarding$modifierPages$0i1$En with MPage {
229229

230230
/// The flat map containing all translations for locale <en>.
231231
/// Only for edge cases! For simple maps, use the map function of this library.
232+
///
233+
/// The Dart AOT compiler has issues with very large switch statements,
234+
/// so the map is split into smaller functions (1024 entries each).
232235
extension on Translations {
233236
dynamic _flatMapFunction(String path) {
237+
return _flatMapFunction$0(path);
238+
}
239+
240+
dynamic _flatMapFunction$0(String path) {
234241
switch (path) {
235242
case 'onboarding.welcome': return ({required Object fullName}) => 'Welcome ${fullName}';
236243
case 'onboarding.welcomeAlias': return ({required Object fullName}) => _root.onboarding.welcome(fullName: fullName);

slang/test/integration/resources/main/_expected_fallback_base_locale_de.output

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,15 @@ class _TranslationsOnboarding$modifierPages$0i1$De extends TranslationsOnboardin
186186

187187
/// The flat map containing all translations for locale <de>.
188188
/// Only for edge cases! For simple maps, use the map function of this library.
189+
///
190+
/// The Dart AOT compiler has issues with very large switch statements,
191+
/// so the map is split into smaller functions (1024 entries each).
189192
extension on TranslationsDe {
190193
dynamic _flatMapFunction(String path) {
194+
return _flatMapFunction$0(path);
195+
}
196+
197+
dynamic _flatMapFunction$0(String path) {
191198
switch (path) {
192199
case 'onboarding.welcome': return ({required Object fullName}) => 'Willkommen ${fullName}';
193200
case 'onboarding.welcomeAlias': return ({required Object fullName}) => _root.onboarding.welcome(fullName: fullName);

slang/test/integration/resources/main/_expected_fallback_base_locale_en.output

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,8 +229,15 @@ class TranslationsOnboarding$modifierPages$0i1$En with MPage {
229229

230230
/// The flat map containing all translations for locale <en>.
231231
/// Only for edge cases! For simple maps, use the map function of this library.
232+
///
233+
/// The Dart AOT compiler has issues with very large switch statements,
234+
/// so the map is split into smaller functions (1024 entries each).
232235
extension on Translations {
233236
dynamic _flatMapFunction(String path) {
237+
return _flatMapFunction$0(path);
238+
}
239+
240+
dynamic _flatMapFunction$0(String path) {
234241
switch (path) {
235242
case 'onboarding.welcome': return ({required Object fullName}) => 'Welcome ${fullName}';
236243
case 'onboarding.welcomeAlias': return ({required Object fullName}) => _root.onboarding.welcome(fullName: fullName);

slang/test/integration/resources/main/_expected_fallback_base_locale_special_de.output

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,15 @@ class TranslationsDe extends Translations {
5050

5151
/// The flat map containing all translations for locale <de>.
5252
/// Only for edge cases! For simple maps, use the map function of this library.
53+
///
54+
/// The Dart AOT compiler has issues with very large switch statements,
55+
/// so the map is split into smaller functions (1024 entries each).
5356
extension on TranslationsDe {
5457
dynamic _flatMapFunction(String path) {
58+
return _flatMapFunction$0(path);
59+
}
60+
61+
dynamic _flatMapFunction$0(String path) {
5562
switch (path) {
5663
case 'greet': return ({required Gender context}) {
5764
switch (context) {

0 commit comments

Comments
 (0)