diff --git a/mobile/bin/generate_keys.dart b/mobile/bin/generate_keys.dart new file mode 100644 index 000000000..8353b1c6f --- /dev/null +++ b/mobile/bin/generate_keys.dart @@ -0,0 +1,63 @@ +// ignore_for_file: avoid_print + +import 'dart:convert'; +import 'dart:io'; + +const _kReservedWords = ['continue']; + +void main() async { + final sourceFile = File('../i18n/en.json'); + if (!await sourceFile.exists()) { + stderr.writeln('Source file does not exist'); + return; + } + + final outputDir = Directory('lib/generated'); + await outputDir.create(recursive: true); + + final outputFile = File('lib/generated/intl_keys.g.dart'); + await _generate(sourceFile, outputFile); + print('Generated ${outputFile.path}'); +} + +Future _generate(File source, File output) async { + final content = await source.readAsString(); + final translations = json.decode(content) as Map; + + final buffer = StringBuffer(''' +// DO NOT EDIT. This is code generated via generate_keys.dart + +abstract class IntlKeys { +'''); + + _writeKeys(buffer, translations); + buffer.writeln('}'); + + await output.writeAsString(buffer.toString()); +} + +void _writeKeys( + StringBuffer buffer, + Map map, [ + String prefix = '', +]) { + for (final entry in map.entries) { + final key = entry.key; + final value = entry.value; + + if (value is Map) { + _writeKeys(buffer, value, prefix.isEmpty ? key : '${prefix}_$key'); + } else { + final name = _cleanName(prefix.isEmpty ? key : '${prefix}_$key'); + final path = prefix.isEmpty ? key : '$prefix.$key'.replaceAll('_', '.'); + buffer.writeln(' static const $name = \'$path\';'); + } + } +} + +String _cleanName(String name) { + name = name.replaceAll(RegExp(r'[^a-zA-Z0-9_]'), '_'); + if (RegExp(r'^[0-9]').hasMatch(name)) name = 'k_$name'; + if (_kReservedWords.contains(name)) name = '${name}_'; + return name; +} diff --git a/mobile/lib/generated/intl_keys.g.dart b/mobile/lib/generated/intl_keys.g.dart new file mode 100644 index 000000000..d8d472b1d Binary files /dev/null and b/mobile/lib/generated/intl_keys.g.dart differ diff --git a/mobile/lib/pages/library/library.page.dart b/mobile/lib/pages/library/library.page.dart index 50126ed1a..37b5e2879 100644 --- a/mobile/lib/pages/library/library.page.dart +++ b/mobile/lib/pages/library/library.page.dart @@ -5,6 +5,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/domain/models/user.model.dart'; import 'package:immich_mobile/extensions/asyncvalue_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; +import 'package:immich_mobile/generated/intl_keys.g.dart'; import 'package:immich_mobile/providers/album/album.provider.dart'; import 'package:immich_mobile/providers/partner.provider.dart'; import 'package:immich_mobile/providers/search/people.provider.dart'; @@ -41,13 +42,13 @@ class LibraryPage extends ConsumerWidget { ActionButton( onPressed: () => context.pushRoute(const FavoritesRoute()), icon: Icons.favorite_outline_rounded, - label: 'favorites'.tr(), + label: IntlKeys.favorites.tr(), ), const SizedBox(width: 8), ActionButton( onPressed: () => context.pushRoute(const ArchiveRoute()), icon: Icons.archive_outlined, - label: 'archived'.tr(), + label: IntlKeys.archived.tr(), ), ], ), @@ -58,14 +59,14 @@ class LibraryPage extends ConsumerWidget { ActionButton( onPressed: () => context.pushRoute(const SharedLinkRoute()), icon: Icons.link_outlined, - label: 'shared_links'.tr(), + label: IntlKeys.shared_links.tr(), ), SizedBox(width: trashEnabled ? 8 : 0), trashEnabled ? ActionButton( onPressed: () => context.pushRoute(const TrashRoute()), icon: Icons.delete_outline_rounded, - label: 'trash'.tr(), + label: IntlKeys.trash.tr(), ) : const SizedBox.shrink(), ], @@ -133,7 +134,7 @@ class QuickAccessButtons extends ConsumerWidget { size: 26, ), title: Text( - 'folders'.tr(), + IntlKeys.folders.tr(), style: context.textTheme.titleSmall?.copyWith( fontWeight: FontWeight.w500, ), @@ -146,7 +147,7 @@ class QuickAccessButtons extends ConsumerWidget { size: 26, ), title: Text( - 'locked_folder'.tr(), + IntlKeys.locked_folder.tr(), style: context.textTheme.titleSmall?.copyWith( fontWeight: FontWeight.w500, ), @@ -159,7 +160,7 @@ class QuickAccessButtons extends ConsumerWidget { size: 26, ), title: Text( - 'partners'.tr(), + IntlKeys.partners.tr(), style: context.textTheme.titleSmall?.copyWith( fontWeight: FontWeight.w500, ), @@ -275,7 +276,7 @@ class PeopleCollectionCard extends ConsumerWidget { Padding( padding: const EdgeInsets.all(8.0), child: Text( - 'people'.tr(), + IntlKeys.people.tr(), style: context.textTheme.titleSmall?.copyWith( color: context.colorScheme.onSurface, fontWeight: FontWeight.w500, @@ -343,7 +344,7 @@ class LocalAlbumsCollectionCard extends HookConsumerWidget { Padding( padding: const EdgeInsets.all(8.0), child: Text( - 'on_this_device'.tr(), + IntlKeys.on_this_device.tr(), style: context.textTheme.titleSmall?.copyWith( color: context.colorScheme.onSurface, fontWeight: FontWeight.w500, @@ -404,7 +405,7 @@ class PlacesCollectionCard extends StatelessWidget { Padding( padding: const EdgeInsets.all(8.0), child: Text( - 'places'.tr(), + IntlKeys.places.tr(), style: context.textTheme.titleSmall?.copyWith( color: context.colorScheme.onSurface, fontWeight: FontWeight.w500, diff --git a/mobile/makefile b/mobile/makefile index ec0d08f08..64992ec94 100644 --- a/mobile/makefile +++ b/mobile/makefile @@ -26,4 +26,6 @@ migration: translation: dart run easy_localization:generate -S ../i18n - dart format lib/generated/codegen_loader.g.dart \ No newline at end of file + dart run bin/generate_keys.dart + dart format lib/generated/codegen_loader.g.dart + dart format lib/generated/intl_keys.g.dart \ No newline at end of file