Skip to content

Commit

Permalink
feat: add lazy config
Browse files Browse the repository at this point in the history
  • Loading branch information
Tienisto committed Oct 18, 2024
1 parent 65d5833 commit f6fab72
Show file tree
Hide file tree
Showing 16 changed files with 143 additions and 120 deletions.
57 changes: 17 additions & 40 deletions slang/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,10 @@ dart run slang migrate arb src.arb dest.json # migrate arb to json
- [Dependency Injection](#-dependency-injection)
- [Structuring Features](#structuring-features)
- [Namespaces](#-namespaces)
- [Output Format](#-output-format)
- [Compact CSV](#-compact-csv)
- [Other Features](#other-features)
- [Fallback](#-fallback)
- [Lazy Loading](#-lazy-loading)
- [Comments](#-comments)
- [Recasing](#-recasing)
- [Obfuscation](#-obfuscation)
Expand Down Expand Up @@ -288,7 +288,7 @@ input_directory: lib/i18n
input_file_pattern: .i18n.json
output_directory: lib/i18n
output_file_name: translations.g.dart
output_format: single_file
lazy: true
locale_handling: true
flutter_integration: true
namespaces: false
Expand Down Expand Up @@ -317,11 +317,6 @@ pluralization:
- someKey.place
contexts:
GenderContext:
enum:
- male
- female
paths:
- my.path.to.greet
default_parameter: gender
generate_enum: true
interfaces:
Expand Down Expand Up @@ -359,7 +354,7 @@ targets:
input_file_pattern: .i18n.json
output_directory: lib/i18n
output_file_name: translations.g.dart
output_format: single_file
lazy: true
locale_handling: true
flutter_integration: true
namespaces: false
Expand Down Expand Up @@ -388,11 +383,6 @@ targets:
- someKey.place
contexts:
GenderContext:
enum:
- male
- female
paths:
- my.path.to.greet
default_parameter: gender
generate_enum: true
interfaces:
Expand Down Expand Up @@ -421,7 +411,7 @@ targets:
| `input_file_pattern` | `String` | input file pattern, must end with .json, .yaml, .csv, .arb | `.i18n.json` |
| `output_directory` | `String` | path to output directory | `null` |
| `output_file_name` | `String` | output file name | `null` |
| `output_format` | `single_file`, `multiple_files` | split output files [(i)](#-output-format) | `single_file` |
| `lazy` | `Boolean` | load translations lazily [(i)](#-lazy-loading) | `true` |
| `locale_handling` | `Boolean` | generate locale handling logic [(i)](#-dependency-injection) | `true` |
| `flutter_integration` | `Boolean` | generate flutter features [(i)](#-dart-only) | `true` |
| `namespaces` | `Boolean` | split input files [(i)](#-namespaces) | `false` |
Expand Down Expand Up @@ -1174,32 +1164,6 @@ String a = t.widgets.welcomeCard.title;
String b = t.errorDialogs.login.wrongPassword;
```

### ➤ Output Format

By default, a single `.g.dart` file will be generated.

You can split this file into multiple ones to improve readability and IDE performance.

```yaml
# Config
output_file_name: translations.g.dart
output_format: multiple_files # set this
```

This will generate the following files:

```text
lib/
└── i18n/
└── translations.g.dart <-- main file
└── translations_en.g.dart <-- translation classes
└── translations_de.g.dart <-- translation classes
└── ...
└── translations_map.g.dart <-- translations stored in flat maps
```

You only need to import the main file!

### ➤ Compact CSV

Normally, you would create a new csv file for each locale:
Expand Down Expand Up @@ -1263,6 +1227,19 @@ fallback_strategy: base_locale # add this

To also treat empty strings as missing translations, set `fallback_strategy: base_locale_empty_string`.

### ➤ Lazy Loading

By default, secondary translations are loaded lazily if [Deferred loading](https://dart.dev/language/libraries#lazily-loading-a-library) is supported.

This reduces the initial startup time.

Disable this feature by setting `lazy: false`.

```yaml
# Config
lazy: false
```

### ➤ Comments

You can add comments in your translation files.
Expand Down
11 changes: 7 additions & 4 deletions slang/example/lib/i18n/strings.g.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
/// Generated file. Do not edit.
///
/// Original: lib/i18n
/// Source: lib/i18n
/// To regenerate, run: `dart run slang`
///
/// Locales: 3
/// Strings: 21 (7 per locale)
///
/// Built on 2024-10-18 at 00:05 UTC
/// Built on 2024-10-18 at 01:08 UTC
// coverage:ignore-file
// ignore_for_file: type=lint, unused_import
Expand All @@ -20,7 +20,7 @@ import 'strings_de.g.dart' deferred as _$de;
import 'strings_fr_FR.g.dart' deferred as _$fr_FR;
part 'strings_en.g.dart';

/// Supported locales, see extension methods below.
/// Supported locales.
///
/// Usage:
/// - LocaleSettings.setLocale(AppLocale.en) // set locale
Expand Down Expand Up @@ -146,7 +146,10 @@ extension BuildContextTranslationsExtension on BuildContext {

/// Manages all translation instances and the current locale
class LocaleSettings extends BaseFlutterLocaleSettings<AppLocale, Translations> {
LocaleSettings._() : super(utils: AppLocaleUtils.instance);
LocaleSettings._() : super(
utils: AppLocaleUtils.instance,
lazy: true,
);

static final instance = LocaleSettings._();

Expand Down
11 changes: 8 additions & 3 deletions slang/lib/src/api/singleton.dart
Original file line number Diff line number Diff line change
Expand Up @@ -254,9 +254,14 @@ abstract class BaseLocaleSettings<E extends BaseAppLocale<E, T>,

BaseLocaleSettings({
required this.utils,
}) : translationMap = {
utils.baseLocale: utils.baseLocale.buildSync(),
};
required bool lazy,
}) : translationMap = lazy
? {
utils.baseLocale: utils.baseLocale.buildSync(),
}
: {
for (final locale in utils.locales) locale: locale.buildSync(),
};

/// Updates the provider state and therefore triggers a rebuild
/// on all widgets listening to this provider.
Expand Down
1 change: 1 addition & 0 deletions slang/lib/src/builder/builder/generate_config_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class GenerateConfigBuilder {
baseLocale: config.baseLocale,
fallbackStrategy: config.fallbackStrategy.toGenerateFallbackStrategy(),
outputFileName: config.outputFileName,
lazy: config.lazy,
localeHandling: config.localeHandling,
flutterIntegration: config.flutterIntegration,
translateVariable: config.translateVar,
Expand Down
1 change: 1 addition & 0 deletions slang/lib/src/builder/builder/raw_config_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class RawConfigBuilder {
RawConfig.defaultOutputDirectory,
outputFileName:
map['output_file_name'] ?? RawConfig.defaultOutputFileName,
lazy: map['lazy'] ?? RawConfig.defaultLazy,
localeHandling: map['locale_handling'] ?? RawConfig.defaultLocaleHandling,
flutterIntegration:
map['flutter_integration'] ?? RawConfig.defaultFlutterIntegration,
Expand Down
70 changes: 42 additions & 28 deletions slang/lib/src/builder/generator/generate_header.dart
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ void _generateHeaderComment({
buffer.writeln('''
/// Generated file. Do not edit.
///
/// Original: ${config.inputDirectoryHint}
/// Source: ${config.inputDirectoryHint}
/// To regenerate, run: `dart run slang`$statisticsStr$timestampStr
// coverage:ignore-file
Expand Down Expand Up @@ -159,8 +159,9 @@ void _generateLocaleImports({
final localeImportName = getImportName(
locale: locale.locale,
);
final deferred = config.lazy ? ' deferred' : '';
buffer.writeln(
'import \'${BuildResultPaths.localePath(outputPath: config.outputFileName, locale: locale.locale)}\' deferred as $localeImportName;');
'import \'${BuildResultPaths.localePath(outputPath: config.outputFileName, locale: locale.locale)}\'$deferred as $localeImportName;');
}
buffer.writeln(
'part \'${BuildResultPaths.localePath(outputPath: config.outputFileName, locale: locales.first.locale)}\';');
Expand Down Expand Up @@ -213,7 +214,7 @@ void _generateEnum({
'$enumName.${config.baseLocale.enumConstant}';

buffer.writeln();
buffer.writeln('/// Supported locales, see extension methods below.');
buffer.writeln('/// Supported locales.');
buffer.writeln('///');
buffer.writeln('/// Usage:');
buffer.writeln(
Expand Down Expand Up @@ -257,7 +258,8 @@ void _generateEnum({
buffer.writeln('\t@override final String? scriptCode;');
buffer.writeln('\t@override final String? countryCode;');

void generateBuildMethod(StringBuffer buffer, bool sync) {
void generateBuildMethod(StringBuffer buffer,
{required bool sync, required bool proxySync}) {
buffer.writeln();
buffer.writeln('\t@override');
buffer.writeln(
Expand All @@ -266,33 +268,43 @@ void _generateEnum({
buffer.writeln('\t\tPluralResolver? cardinalResolver,');
buffer.writeln('\t\tPluralResolver? ordinalResolver,');
buffer.writeln('\t}) ${sync ? '' : 'async '}{');
buffer.writeln('\t\tswitch (this) {');
for (final locale in allLocales) {
final localeImportName = getImportName(
locale: locale.locale,
);
final className = getClassNameRoot(
className: config.className,
locale: locale.locale,
);

buffer.writeln('\t\t\tcase $enumName.${locale.locale.enumConstant}:');
if (!locale.base && !sync) {
buffer.writeln('\t\t\t\tawait $localeImportName.loadLibrary();');

if (proxySync) {
buffer.writeln('\t\treturn buildSync(');
buffer.writeln('\t\t\toverrides: overrides,');
buffer.writeln('\t\t\tcardinalResolver: cardinalResolver,');
buffer.writeln('\t\t\tordinalResolver: ordinalResolver,');
buffer.writeln('\t\t);');
} else {
buffer.writeln('\t\tswitch (this) {');
for (final locale in allLocales) {
final localeImportName = getImportName(
locale: locale.locale,
);
final className = getClassNameRoot(
className: config.className,
locale: locale.locale,
);

buffer.writeln('\t\t\tcase $enumName.${locale.locale.enumConstant}:');
if (!locale.base && !sync) {
buffer.writeln('\t\t\t\tawait $localeImportName.loadLibrary();');
}
buffer.writeln(
'\t\t\t\treturn ${locale.base ? '' : '$localeImportName.'}$className(');
buffer.writeln('\t\t\t\t\toverrides: overrides,');
buffer.writeln('\t\t\t\t\tcardinalResolver: cardinalResolver,');
buffer.writeln('\t\t\t\t\tordinalResolver: ordinalResolver,');
buffer.writeln('\t\t\t\t);');
}
buffer.writeln(
'\t\t\t\treturn ${locale.base ? '' : '$localeImportName.'}$className(');
buffer.writeln('\t\t\t\t\toverrides: overrides,');
buffer.writeln('\t\t\t\t\tcardinalResolver: cardinalResolver,');
buffer.writeln('\t\t\t\t\tordinalResolver: ordinalResolver,');
buffer.writeln('\t\t\t\t);');
buffer.writeln('\t\t}');
}
buffer.writeln('\t\t}');

buffer.writeln('\t}');
}

generateBuildMethod(buffer, false);
generateBuildMethod(buffer, true);
generateBuildMethod(buffer, sync: false, proxySync: !config.lazy);
generateBuildMethod(buffer, sync: true, proxySync: false);

if (config.localeHandling) {
buffer.writeln();
Expand Down Expand Up @@ -399,8 +411,10 @@ void _generateLocaleSettings({
.writeln('/// Manages all translation instances and the current locale');
buffer.writeln(
'class $settingsClass extends $baseClass<$enumName, ${config.className}> {');
buffer
.writeln('\t$settingsClass._() : super(utils: AppLocaleUtils.instance);');
buffer.writeln('\t$settingsClass._() : super(');
buffer.writeln('\t\tutils: AppLocaleUtils.instance,');
buffer.writeln('\t\tlazy: ${config.lazy},');
buffer.writeln('\t);');
buffer.writeln();
buffer.writeln('\tstatic final instance = $settingsClass._();');

Expand Down
2 changes: 2 additions & 0 deletions slang/lib/src/builder/model/generate_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class GenerateConfig {
final I18nLocale baseLocale; // defaults to 'en'
final GenerateFallbackStrategy fallbackStrategy;
final String outputFileName;
final bool lazy;
final bool localeHandling;
final bool flutterIntegration;
final String translateVariable;
Expand All @@ -34,6 +35,7 @@ class GenerateConfig {
required this.baseLocale,
required this.fallbackStrategy,
required this.outputFileName,
required this.lazy,
required this.localeHandling,
required this.flutterIntegration,
required this.translateVariable,
Expand Down
7 changes: 7 additions & 0 deletions slang/lib/src/builder/model/raw_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class RawConfig {
static const String defaultInputFilePattern = '.i18n.json';
static const String? defaultOutputDirectory = null;
static const String defaultOutputFileName = 'strings.g.dart';
static const bool defaultLazy = true;
static const bool defaultLocaleHandling = true;
static const bool defaultFlutterIntegration = true;
static const bool defaultNamespaces = false;
Expand Down Expand Up @@ -47,6 +48,7 @@ class RawConfig {
final String inputFilePattern;
final String? outputDirectory;
final String outputFileName;
final bool lazy;
final bool localeHandling;
final bool flutterIntegration;
final bool namespaces;
Expand Down Expand Up @@ -82,6 +84,7 @@ class RawConfig {
required this.inputFilePattern,
required this.outputDirectory,
required this.outputFileName,
required this.lazy,
required this.localeHandling,
required this.flutterIntegration,
required this.namespaces,
Expand Down Expand Up @@ -118,6 +121,7 @@ class RawConfig {
FallbackStrategy? fallbackStrategy,
String? inputFilePattern,
String? outputFileName,
bool? lazy,
bool? localeHandling,
bool? flutterIntegration,
bool? namespaces,
Expand All @@ -143,6 +147,7 @@ class RawConfig {
inputFilePattern: inputFilePattern ?? this.inputFilePattern,
outputDirectory: outputDirectory,
outputFileName: outputFileName ?? this.outputFileName,
lazy: lazy ?? this.lazy,
localeHandling: localeHandling ?? this.localeHandling,
flutterIntegration: flutterIntegration ?? this.flutterIntegration,
namespaces: namespaces ?? this.namespaces,
Expand Down Expand Up @@ -201,6 +206,7 @@ class RawConfig {
print(
' -> outputDirectory: ${outputDirectory ?? 'null (directory of input)'}');
print(' -> outputFileName: $outputFileName');
print(' -> lazy: $lazy');
print(' -> localeHandling: $localeHandling');
print(' -> flutterIntegration: $flutterIntegration');
print(' -> namespaces: $namespaces');
Expand Down Expand Up @@ -256,6 +262,7 @@ class RawConfig {
inputFilePattern: RawConfig.defaultInputFilePattern,
outputDirectory: RawConfig.defaultOutputDirectory,
outputFileName: RawConfig.defaultOutputFileName,
lazy: RawConfig.defaultLazy,
localeHandling: RawConfig.defaultLocaleHandling,
flutterIntegration: RawConfig.defaultFlutterIntegration,
namespaces: RawConfig.defaultNamespaces,
Expand Down
2 changes: 1 addition & 1 deletion slang/test/unit/api/locale_settings_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,5 @@ class _AppLocaleUtils

class _LocaleSettings
extends BaseLocaleSettings<FakeAppLocale, FakeTranslations> {
_LocaleSettings() : super(utils: _AppLocaleUtils());
_LocaleSettings() : super(utils: _AppLocaleUtils(), lazy: false);
}
1 change: 1 addition & 0 deletions slang_flutter/lib/slang_flutter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class BaseFlutterLocaleSettings<E extends BaseAppLocale<E, T>,
T extends BaseTranslations<E, T>> extends BaseLocaleSettings<E, T> {
BaseFlutterLocaleSettings({
required super.utils,
required super.lazy,
});

@override
Expand Down
Loading

0 comments on commit f6fab72

Please sign in to comment.