From 3fd32ca5fa27e7fdc48632be65df4ffecb527e7e Mon Sep 17 00:00:00 2001 From: Juan Gilsanz Polo Date: Thu, 22 Feb 2024 00:52:07 +0100 Subject: [PATCH] Added translations library --- ios/Runner/Info.plist | 97 +++---- lib/i18n/strings.g.dart | 252 ++++++++++++++++++ lib/i18n/strings_en.i18n.json | 10 + lib/i18n/strings_es.i18n.json | 10 + lib/main.dart | 21 +- .../connect/provider/connect_provider.dart | 8 +- lib/screens/links/ui/links.dart | 4 +- macos/Podfile.lock | 35 +++ macos/Runner.xcodeproj/project.pbxproj | 98 ++++++- .../contents.xcworkspacedata | 3 + macos/Runner/Info.plist | 63 +++-- pubspec.lock | 53 ++++ pubspec.yaml | 5 + 13 files changed, 571 insertions(+), 88 deletions(-) create mode 100644 lib/i18n/strings.g.dart create mode 100644 lib/i18n/strings_en.i18n.json create mode 100644 lib/i18n/strings_es.i18n.json create mode 100644 macos/Podfile.lock diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 089d44c..7fcc9e8 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -1,49 +1,54 @@ - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - My Linkding - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - my_linkding - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - - - + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + My Linkding + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + my_linkding + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + CFBundleLocalizations + + en + es + + + \ No newline at end of file diff --git a/lib/i18n/strings.g.dart b/lib/i18n/strings.g.dart new file mode 100644 index 0000000..9b2692a --- /dev/null +++ b/lib/i18n/strings.g.dart @@ -0,0 +1,252 @@ +/// Generated file. Do not edit. +/// +/// Original: lib/i18n +/// To regenerate, run: `dart run slang` +/// +/// Locales: 2 +/// Strings: 8 (4 per locale) +/// +/// Built on 2024-02-21 at 23:50 UTC + +// coverage:ignore-file +// ignore_for_file: type=lint + +import 'package:flutter/widgets.dart'; +import 'package:slang/builder/model/node.dart'; +import 'package:slang_flutter/slang_flutter.dart'; +export 'package:slang_flutter/slang_flutter.dart'; + +const AppLocale _baseLocale = AppLocale.en; + +/// Supported locales, see extension methods below. +/// +/// Usage: +/// - LocaleSettings.setLocale(AppLocale.en) // set locale +/// - Locale locale = AppLocale.en.flutterLocale // get flutter locale from enum +/// - if (LocaleSettings.currentLocale == AppLocale.en) // locale check +enum AppLocale with BaseAppLocale { + en(languageCode: 'en', build: Translations.build), + es(languageCode: 'es', build: _StringsEs.build); + + const AppLocale({required this.languageCode, this.scriptCode, this.countryCode, required this.build}); // ignore: unused_element + + @override final String languageCode; + @override final String? scriptCode; + @override final String? countryCode; + @override final TranslationBuilder build; + + /// Gets current instance managed by [LocaleSettings]. + Translations get translations => LocaleSettings.instance.translationMap[this]!; +} + +/// Method A: Simple +/// +/// No rebuild after locale change. +/// Translation happens during initialization of the widget (call of t). +/// Configurable via 'translate_var'. +/// +/// Usage: +/// String a = t.someKey.anotherKey; +/// String b = t['someKey.anotherKey']; // Only for edge cases! +Translations get t => LocaleSettings.instance.currentTranslations; + +/// Method B: Advanced +/// +/// All widgets using this method will trigger a rebuild when locale changes. +/// Use this if you have e.g. a settings page where the user can select the locale during runtime. +/// +/// Step 1: +/// wrap your App with +/// TranslationProvider( +/// child: MyApp() +/// ); +/// +/// Step 2: +/// final t = Translations.of(context); // Get t variable. +/// String a = t.someKey.anotherKey; // Use t variable. +/// String b = t['someKey.anotherKey']; // Only for edge cases! +class TranslationProvider extends BaseTranslationProvider { + TranslationProvider({required super.child}) : super(settings: LocaleSettings.instance); + + static InheritedLocaleData of(BuildContext context) => InheritedLocaleData.of(context); +} + +/// Method B shorthand via [BuildContext] extension method. +/// Configurable via 'translate_var'. +/// +/// Usage (e.g. in a widget's build method): +/// context.t.someKey.anotherKey +extension BuildContextTranslationsExtension on BuildContext { + Translations get t => TranslationProvider.of(this).translations; +} + +/// Manages all translation instances and the current locale +class LocaleSettings extends BaseFlutterLocaleSettings { + LocaleSettings._() : super(utils: AppLocaleUtils.instance); + + static final instance = LocaleSettings._(); + + // static aliases (checkout base methods for documentation) + static AppLocale get currentLocale => instance.currentLocale; + static Stream getLocaleStream() => instance.getLocaleStream(); + static AppLocale setLocale(AppLocale locale, {bool? listenToDeviceLocale = false}) => instance.setLocale(locale, listenToDeviceLocale: listenToDeviceLocale); + static AppLocale setLocaleRaw(String rawLocale, {bool? listenToDeviceLocale = false}) => instance.setLocaleRaw(rawLocale, listenToDeviceLocale: listenToDeviceLocale); + static AppLocale useDeviceLocale() => instance.useDeviceLocale(); + @Deprecated('Use [AppLocaleUtils.supportedLocales]') static List get supportedLocales => instance.supportedLocales; + @Deprecated('Use [AppLocaleUtils.supportedLocalesRaw]') static List get supportedLocalesRaw => instance.supportedLocalesRaw; + static void setPluralResolver({String? language, AppLocale? locale, PluralResolver? cardinalResolver, PluralResolver? ordinalResolver}) => instance.setPluralResolver( + language: language, + locale: locale, + cardinalResolver: cardinalResolver, + ordinalResolver: ordinalResolver, + ); +} + +/// Provides utility functions without any side effects. +class AppLocaleUtils extends BaseAppLocaleUtils { + AppLocaleUtils._() : super(baseLocale: _baseLocale, locales: AppLocale.values); + + static final instance = AppLocaleUtils._(); + + // static aliases (checkout base methods for documentation) + static AppLocale parse(String rawLocale) => instance.parse(rawLocale); + static AppLocale parseLocaleParts({required String languageCode, String? scriptCode, String? countryCode}) => instance.parseLocaleParts(languageCode: languageCode, scriptCode: scriptCode, countryCode: countryCode); + static AppLocale findDeviceLocale() => instance.findDeviceLocale(); + static List get supportedLocales => instance.supportedLocales; + static List get supportedLocalesRaw => instance.supportedLocalesRaw; +} + +// translations + +// Path: +class Translations implements BaseTranslations { + /// Returns the current translations of the given [context]. + /// + /// Usage: + /// final t = Translations.of(context); + static Translations of(BuildContext context) => InheritedLocaleData.of(context).translations; + + /// You can call this constructor and build your own translation instance of this locale. + /// Constructing via the enum [AppLocale.build] is preferred. + Translations.build({Map? overrides, PluralResolver? cardinalResolver, PluralResolver? ordinalResolver}) + : assert(overrides == null, 'Set "translation_overrides: true" in order to enable this feature.'), + $meta = TranslationMetadata( + locale: AppLocale.en, + overrides: overrides ?? {}, + cardinalResolver: cardinalResolver, + ordinalResolver: ordinalResolver, + ) { + $meta.setFlatMapFunction(_flatMapFunction); + } + + /// Metadata for the translations of . + @override final TranslationMetadata $meta; + + /// Access flat map + dynamic operator[](String key) => $meta.getTranslation(key); + + late final Translations _root = this; // ignore: unused_field + + // Translations + late final _StringsConnectEn connect = _StringsConnectEn._(_root); + late final _StringsLinksEn links = _StringsLinksEn._(_root); +} + +// Path: connect +class _StringsConnectEn { + _StringsConnectEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get connect => 'Connect'; + String get connecting => 'Connecting...'; + String get cannotConnectToServer => 'Cannot connect to the server.'; +} + +// Path: links +class _StringsLinksEn { + _StringsLinksEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get links => 'Links'; +} + +// Path: +class _StringsEs implements Translations { + /// You can call this constructor and build your own translation instance of this locale. + /// Constructing via the enum [AppLocale.build] is preferred. + _StringsEs.build({Map? overrides, PluralResolver? cardinalResolver, PluralResolver? ordinalResolver}) + : assert(overrides == null, 'Set "translation_overrides: true" in order to enable this feature.'), + $meta = TranslationMetadata( + locale: AppLocale.es, + overrides: overrides ?? {}, + cardinalResolver: cardinalResolver, + ordinalResolver: ordinalResolver, + ) { + $meta.setFlatMapFunction(_flatMapFunction); + } + + /// Metadata for the translations of . + @override final TranslationMetadata $meta; + + /// Access flat map + @override dynamic operator[](String key) => $meta.getTranslation(key); + + @override late final _StringsEs _root = this; // ignore: unused_field + + // Translations + @override late final _StringsConnectEs connect = _StringsConnectEs._(_root); + @override late final _StringsLinksEs links = _StringsLinksEs._(_root); +} + +// Path: connect +class _StringsConnectEs implements _StringsConnectEn { + _StringsConnectEs._(this._root); + + @override final _StringsEs _root; // ignore: unused_field + + // Translations + @override String get connect => 'Conectar'; + @override String get connecting => 'Conectando...'; + @override String get cannotConnectToServer => 'No se puede conectar con el servidor.'; +} + +// Path: links +class _StringsLinksEs implements _StringsLinksEn { + _StringsLinksEs._(this._root); + + @override final _StringsEs _root; // ignore: unused_field + + // Translations + @override String get links => 'Enlaces'; +} + +/// Flat map(s) containing all translations. +/// Only for edge cases! For simple maps, use the map function of this library. + +extension on Translations { + dynamic _flatMapFunction(String path) { + switch (path) { + case 'connect.connect': return 'Connect'; + case 'connect.connecting': return 'Connecting...'; + case 'connect.cannotConnectToServer': return 'Cannot connect to the server.'; + case 'links.links': return 'Links'; + default: return null; + } + } +} + +extension on _StringsEs { + dynamic _flatMapFunction(String path) { + switch (path) { + case 'connect.connect': return 'Conectar'; + case 'connect.connecting': return 'Conectando...'; + case 'connect.cannotConnectToServer': return 'No se puede conectar con el servidor.'; + case 'links.links': return 'Enlaces'; + default: return null; + } + } +} diff --git a/lib/i18n/strings_en.i18n.json b/lib/i18n/strings_en.i18n.json new file mode 100644 index 0000000..92b6646 --- /dev/null +++ b/lib/i18n/strings_en.i18n.json @@ -0,0 +1,10 @@ +{ + "connect": { + "connect": "Connect", + "connecting": "Connecting...", + "cannotConnectToServer": "Cannot connect to the server." + }, + "links": { + "links": "Links" + } +} \ No newline at end of file diff --git a/lib/i18n/strings_es.i18n.json b/lib/i18n/strings_es.i18n.json new file mode 100644 index 0000000..12a0edc --- /dev/null +++ b/lib/i18n/strings_es.i18n.json @@ -0,0 +1,10 @@ +{ + "connect": { + "connect": "Conectar", + "connecting": "Conectando...", + "cannotConnectToServer": "No se puede conectar con el servidor." + }, + "links": { + "links": "Enlaces" + } +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index fb86979..8ae3c29 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,31 +2,37 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:my_linkding/constants/global_keys.dart'; import 'package:dynamic_color/dynamic_color.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:my_linkding/config/theme.dart'; import 'package:my_linkding/constants/colors.dart'; +import 'package:my_linkding/i18n/strings.g.dart'; import 'package:my_linkding/providers/router_provider.dart'; import 'package:my_linkding/providers/shared_preferences_provider.dart'; import 'package:my_linkding/utils/http_overrides.dart'; -import 'package:shared_preferences/shared_preferences.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); + LocaleSettings.useDeviceLocale(); + HttpOverrides.global = MyHttpOverrides(); final sharedPreferences = await SharedPreferences.getInstance(); runApp( - ProviderScope( - overrides: [ - sharedPreferencesProvider.overrideWithValue(sharedPreferences), - ], - child: const MyApp(), + TranslationProvider( + child: ProviderScope( + overrides: [ + sharedPreferencesProvider.overrideWithValue(sharedPreferences), + ], + child: const MyApp(), + ), ), ); } @@ -41,6 +47,9 @@ class MyApp extends ConsumerWidget { title: 'My Linkding', theme: lightDynamic != null ? lightTheme(lightDynamic) : lightThemeOldVersions(colors[0]), darkTheme: darkDynamic != null ? darkTheme(darkDynamic) : darkThemeOldVersions(colors[0]), + locale: TranslationProvider.of(context).flutterLocale, + supportedLocales: AppLocaleUtils.supportedLocales, + localizationsDelegates: GlobalMaterialLocalizations.delegates, debugShowCheckedModeBanner: false, scaffoldMessengerKey: scaffoldMessengerGlobalKey, routerConfig: ref.watch(routerProvider), diff --git a/lib/screens/connect/provider/connect_provider.dart b/lib/screens/connect/provider/connect_provider.dart index 28df05f..9ed2ca9 100644 --- a/lib/screens/connect/provider/connect_provider.dart +++ b/lib/screens/connect/provider/connect_provider.dart @@ -1,15 +1,13 @@ import 'package:flutter/material.dart'; -import 'package:my_linkding/providers/shared_preferences_provider.dart'; import 'package:uuid/uuid.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:my_linkding/screens/connect/model/connect_model.dart'; import 'package:my_linkding/providers/server_instances_provider.dart'; +import 'package:my_linkding/i18n/strings.g.dart'; import 'package:my_linkding/constants/enums.dart'; import 'package:my_linkding/utils/process_modal.dart'; -import 'package:my_linkding/providers/router_provider.dart'; -import 'package:my_linkding/router/paths.dart'; import 'package:my_linkding/utils/snackbar.dart'; import 'package:my_linkding/models/server_instance.dart'; import 'package:my_linkding/providers/api_client_provider.dart'; @@ -89,7 +87,7 @@ FutureOr connectToServer(ConnectToServerRef ref) async { final apiClient = ApiClient(serverInstance: serverInstance); final processModal = ProcessModal(); - processModal.open("Connecting..."); + processModal.open(t.connect.connecting); final result = await apiClient.checkConnectionInstance(); @@ -99,7 +97,7 @@ FutureOr connectToServer(ConnectToServerRef ref) async { ref.read(serverInstancesProvider.notifier).saveNewInstance(serverInstance); // ref.watch(routerProvider).replace(RoutesPaths.links); } else { - showSnacbkar(label: "Invalida auth", color: Colors.red); + showSnacbkar(label: t.connect.cannotConnectToServer, color: Colors.red); } return false; diff --git a/lib/screens/links/ui/links.dart b/lib/screens/links/ui/links.dart index 7a04800..6b4cafb 100644 --- a/lib/screens/links/ui/links.dart +++ b/lib/screens/links/ui/links.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:my_linkding/i18n/strings.g.dart'; + class Links extends StatelessWidget { const Links({Key? key}) : super(key: key); @@ -16,7 +18,7 @@ class Links extends StatelessWidget { floating: true, centerTitle: false, forceElevated: innerBoxIsScrolled, - title: Text("Links"), + title: Text(t.links.links), ), ), ], diff --git a/macos/Podfile.lock b/macos/Podfile.lock new file mode 100644 index 0000000..933b4d2 --- /dev/null +++ b/macos/Podfile.lock @@ -0,0 +1,35 @@ +PODS: + - dynamic_color (0.0.2): + - FlutterMacOS + - FlutterMacOS (1.0.0) + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + - url_launcher_macos (0.0.1): + - FlutterMacOS + +DEPENDENCIES: + - dynamic_color (from `Flutter/ephemeral/.symlinks/plugins/dynamic_color/macos`) + - FlutterMacOS (from `Flutter/ephemeral`) + - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) + - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) + +EXTERNAL SOURCES: + dynamic_color: + :path: Flutter/ephemeral/.symlinks/plugins/dynamic_color/macos + FlutterMacOS: + :path: Flutter/ephemeral + shared_preferences_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin + url_launcher_macos: + :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos + +SPEC CHECKSUMS: + dynamic_color: 2eaa27267de1ca20d879fbd6e01259773fb1670f + FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 + shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695 + url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95 + +PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367 + +COCOAPODS: 1.14.3 diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index f0924c4..1d69237 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -21,12 +21,14 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + 2C82BC3BDC8F3538F3565F25 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D782E92928080117BE6339AE /* Pods_RunnerTests.framework */; }; 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + D0434BDC47844E5C89663A09 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1FB5A738B70ED51CEAACDF2C /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -60,11 +62,13 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 14E0069015837F24128F4C80 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 1FB5A738B70ED51CEAACDF2C /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* my_linkding.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "my_linkding.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10ED2044A3C60003C045 /* my_linkding.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = my_linkding.app; sourceTree = BUILT_PRODUCTS_DIR; }; 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; @@ -78,6 +82,12 @@ 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + 9CB4A68230725B1605ABB9B5 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + AE76C16CF7FD949F1C440D8D /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + B0CB230F5A87B345D7B8FAE9 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + D782E92928080117BE6339AE /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + E92A18855CB6A3A7F902F028 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + FD6AFD021F96A1F86691E750 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -85,6 +95,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 2C82BC3BDC8F3538F3565F25 /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -92,12 +103,27 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + D0434BDC47844E5C89663A09 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 1B4525708D1C7A1890544101 /* Pods */ = { + isa = PBXGroup; + children = ( + FD6AFD021F96A1F86691E750 /* Pods-Runner.debug.xcconfig */, + AE76C16CF7FD949F1C440D8D /* Pods-Runner.release.xcconfig */, + E92A18855CB6A3A7F902F028 /* Pods-Runner.profile.xcconfig */, + 14E0069015837F24128F4C80 /* Pods-RunnerTests.debug.xcconfig */, + B0CB230F5A87B345D7B8FAE9 /* Pods-RunnerTests.release.xcconfig */, + 9CB4A68230725B1605ABB9B5 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; 331C80D6294CF71000263BE5 /* RunnerTests */ = { isa = PBXGroup; children = ( @@ -125,6 +151,7 @@ 331C80D6294CF71000263BE5 /* RunnerTests */, 33CC10EE2044A3C60003C045 /* Products */, D73912EC22F37F3D000D13A0 /* Frameworks */, + 1B4525708D1C7A1890544101 /* Pods */, ); sourceTree = ""; }; @@ -175,6 +202,8 @@ D73912EC22F37F3D000D13A0 /* Frameworks */ = { isa = PBXGroup; children = ( + 1FB5A738B70ED51CEAACDF2C /* Pods_Runner.framework */, + D782E92928080117BE6339AE /* Pods_RunnerTests.framework */, ); name = Frameworks; sourceTree = ""; @@ -186,6 +215,7 @@ isa = PBXNativeTarget; buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( + FA7823E03E9207CB76E87418 /* [CP] Check Pods Manifest.lock */, 331C80D1294CF70F00263BE5 /* Sources */, 331C80D2294CF70F00263BE5 /* Frameworks */, 331C80D3294CF70F00263BE5 /* Resources */, @@ -204,11 +234,13 @@ isa = PBXNativeTarget; buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + 654118FCF78DD717EBFB00E0 /* [CP] Check Pods Manifest.lock */, 33CC10E92044A3C60003C045 /* Sources */, 33CC10EA2044A3C60003C045 /* Frameworks */, 33CC10EB2044A3C60003C045 /* Resources */, 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, + D41BC943399F1ACBD0C0AA49 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -328,6 +360,67 @@ shellPath = /bin/sh; shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; }; + 654118FCF78DD717EBFB00E0 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + D41BC943399F1ACBD0C0AA49 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + FA7823E03E9207CB76E87418 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -379,6 +472,7 @@ /* Begin XCBuildConfiguration section */ 331C80DB294CF71000263BE5 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 14E0069015837F24128F4C80 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -393,6 +487,7 @@ }; 331C80DC294CF71000263BE5 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = B0CB230F5A87B345D7B8FAE9 /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -407,6 +502,7 @@ }; 331C80DD294CF71000263BE5 /* Profile */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 9CB4A68230725B1605ABB9B5 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; diff --git a/macos/Runner.xcworkspace/contents.xcworkspacedata b/macos/Runner.xcworkspace/contents.xcworkspacedata index 1d526a1..21a3cc1 100644 --- a/macos/Runner.xcworkspace/contents.xcworkspacedata +++ b/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/macos/Runner/Info.plist b/macos/Runner/Info.plist index 4789daa..1e4a2cb 100644 --- a/macos/Runner/Info.plist +++ b/macos/Runner/Info.plist @@ -1,32 +1,37 @@ - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIconFile - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - $(PRODUCT_COPYRIGHT) - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - - + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + CFBundleLocalizations + + en + es + + + \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index 13f438c..272bd03 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -193,6 +193,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.3" + csv: + dependency: transitive + description: + name: csv + sha256: "63ed2871dd6471193dffc52c0e6c76fb86269c00244d244297abbb355c84a86e" + url: "https://pub.dev" + source: hosted + version: "5.1.1" cupertino_icons: dependency: "direct main" description: @@ -294,6 +302,11 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.3" + flutter_localizations: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" flutter_riverpod: dependency: "direct main" description: @@ -376,6 +389,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + intl: + dependency: transitive + description: + name: intl + sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" + url: "https://pub.dev" + source: hosted + version: "0.18.1" io: dependency: transitive description: @@ -392,6 +413,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.1" + json2yaml: + dependency: transitive + description: + name: json2yaml + sha256: da94630fbc56079426fdd167ae58373286f603371075b69bf46d848d63ba3e51 + url: "https://pub.dev" + source: hosted + version: "3.0.1" json_annotation: dependency: transitive description: @@ -661,6 +690,30 @@ packages: description: flutter source: sdk version: "0.0.99" + slang: + dependency: "direct main" + description: + name: slang + sha256: "95dee03eb3fd1b36c99f365d4eace270a0d83c6148f8e7d1057806ef60cfaf12" + url: "https://pub.dev" + source: hosted + version: "3.29.0" + slang_build_runner: + dependency: "direct dev" + description: + name: slang_build_runner + sha256: "929ea4bf24f11e09afd2b01abd658f550da7eb4039ae83d91bc220f942e18cb3" + url: "https://pub.dev" + source: hosted + version: "3.29.0" + slang_flutter: + dependency: "direct main" + description: + name: slang_flutter + sha256: "34c7cf297c608e24d3957a29e75c6790f4dbbfb1a4783d261a6c1e33ede7ad0f" + url: "https://pub.dev" + source: hosted + version: "3.29.0" source_gen: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index dc67395..545d0cc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -30,6 +30,8 @@ environment: dependencies: flutter: sdk: flutter + flutter_localizations: + sdk: flutter cupertino_icons: ^1.0.2 flutter_riverpod: ^2.4.10 go_router: ^13.2.0 @@ -41,6 +43,8 @@ dependencies: segmented_button_slide: ^1.0.4 dio: ^5.4.1 uuid: ^4.3.3 + slang: ^3.29.0 + slang_flutter: ^3.29.0 dev_dependencies: build_runner: ^2.4.8 @@ -50,6 +54,7 @@ dev_dependencies: sdk: flutter riverpod_generator: ^2.3.11 riverpod_lint: ^2.3.9 + slang_build_runner: ^3.29.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec