From 26912431028dfc97d55b8941d25572b44103f36b Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 8 Jul 2021 16:43:24 +0530 Subject: [PATCH] Remove json translations approach, add example for adding language Signed-off-by: Sahil Kumar --- .../stream_chat_flutter/example/lib/main.dart | 46 +++++++- .../stream_chat_flutter/example/pubspec.yaml | 2 + .../lib/src/extension.dart | 6 +- .../lib/src/message_text.dart | 3 + .../lib/src/stream_chat_localizations.dart | 5 +- packages/stream_chat_flutter/pubspec.yaml | 1 + .../lib/src/i18n/en.json | 0 .../lib/src/stream_chat_localizations.dart | 103 +++++++++++------- .../lib/src/stream_chat_localizations_en.dart | 11 ++ .../lib/stream_chat_localizations.dart | 7 +- .../stream_chat_localizations/pubspec.yaml | 37 ------- .../test/stream_chat_localization_test.dart | 22 ++-- 12 files changed, 144 insertions(+), 99 deletions(-) delete mode 100644 packages/stream_chat_localizations/lib/src/i18n/en.json create mode 100644 packages/stream_chat_localizations/lib/src/stream_chat_localizations_en.dart diff --git a/packages/stream_chat_flutter/example/lib/main.dart b/packages/stream_chat_flutter/example/lib/main.dart index d3522886..c1246a31 100644 --- a/packages/stream_chat_flutter/example/lib/main.dart +++ b/packages/stream_chat_flutter/example/lib/main.dart @@ -1,10 +1,35 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'package:stream_chat_persistence/stream_chat_persistence.dart'; +import 'package:stream_chat_localizations/stream_chat_localizations.dart'; -final chatPersistentClient = StreamChatPersistenceClient( - logLevel: Level.INFO, -); +/// A custom set of localizations for the 'hi' locale. +class StreamChatLocalizationsHi extends GlobalStreamChatLocalizations { + const StreamChatLocalizationsHi() : super(localeName: 'hi'); + + static const LocalizationsDelegate delegate = + _HindiStreamChatLocalizationsDelegate(); + + @override + String get launchUrlError => 'URL लॉन्च नहीं कर सकता'; +} + +class _HindiStreamChatLocalizationsDelegate + extends LocalizationsDelegate { + const _HindiStreamChatLocalizationsDelegate(); + + @override + bool isSupported(Locale locale) => locale.languageCode == 'hi'; + + @override + Future load(Locale locale) => + SynchronousFuture(const StreamChatLocalizationsHi()); + + @override + bool shouldReload(_HindiStreamChatLocalizationsDelegate old) => false; +} void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -14,7 +39,7 @@ void main() async { final client = StreamChatClient( 's2dxdhpxd94g', logLevel: Level.INFO, - )..chatPersistenceClient = chatPersistentClient; + ); /// Set the current user and connect the websocket. In a production scenario, this should be done using /// a backend to generate a user token using our server SDK. @@ -58,6 +83,17 @@ class MyApp extends StatelessWidget { theme: ThemeData.light(), darkTheme: ThemeData.dark(), themeMode: ThemeMode.system, + supportedLocales: [ + Locale('en', 'US'), + Locale('hi', 'IN'), + ], + localizationsDelegates: [ + GlobalStreamChatLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + StreamChatLocalizationsHi.delegate, + ], builder: (context, widget) { return StreamChat( client: client, diff --git a/packages/stream_chat_flutter/example/pubspec.yaml b/packages/stream_chat_flutter/example/pubspec.yaml index 408bf9e1..4eb99d86 100644 --- a/packages/stream_chat_flutter/example/pubspec.yaml +++ b/packages/stream_chat_flutter/example/pubspec.yaml @@ -29,6 +29,8 @@ dependencies: # path: ../../stream_chat_flutter_core stream_chat_flutter: path: ../ + stream_chat_localizations: + path: ../../stream_chat_localizations stream_chat_persistence: path: ../../stream_chat_persistence diff --git a/packages/stream_chat_flutter/lib/src/extension.dart b/packages/stream_chat_flutter/lib/src/extension.dart index 1a80d19e..3a495ca5 100644 --- a/packages/stream_chat_flutter/lib/src/extension.dart +++ b/packages/stream_chat_flutter/lib/src/extension.dart @@ -104,11 +104,7 @@ extension BuildContextX on BuildContext { double get textScaleFactor => MediaQuery.maybeOf(this)?.textScaleFactor ?? 1.0; - String translate({ - required String key, - required String defaultValue, - }) => - StreamChatLocalizations.of(this)?.translate(key) ?? defaultValue; + StreamChatLocalizations? get translations => StreamChatLocalizations.of(this); } /// Extension on [BorderRadius] diff --git a/packages/stream_chat_flutter/lib/src/message_text.dart b/packages/stream_chat_flutter/lib/src/message_text.dart index 6d006085..b0bd13ca 100644 --- a/packages/stream_chat_flutter/lib/src/message_text.dart +++ b/packages/stream_chat_flutter/lib/src/message_text.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; +import 'package:stream_chat_flutter/src/extension.dart'; /// Text widget to display in message class MessageText extends StatelessWidget { @@ -29,6 +30,8 @@ class MessageText extends StatelessWidget { @override Widget build(BuildContext context) { + final texts = context.translations?.launchUrlError ?? 'defaultValue'; + return Text(texts); final text = _replaceMentions(message.text ?? '').replaceAll('\n', '\n\n'); final themeData = Theme.of(context); diff --git a/packages/stream_chat_flutter/lib/src/stream_chat_localizations.dart b/packages/stream_chat_flutter/lib/src/stream_chat_localizations.dart index 3ed1a9c3..b1d81fde 100644 --- a/packages/stream_chat_flutter/lib/src/stream_chat_localizations.dart +++ b/packages/stream_chat_flutter/lib/src/stream_chat_localizations.dart @@ -71,9 +71,6 @@ import 'package:flutter/widgets.dart'; /// * [GlobalStreamChatLocalizations], which provides material localizations /// for many languages. abstract class StreamChatLocalizations { - /// - String? translate(String key); - /// The `StreamChatLocalizations` from the closest [Localizations] instance /// that encloses the given context. /// @@ -94,4 +91,6 @@ abstract class StreamChatLocalizations { context, StreamChatLocalizations, ); + + String get launchUrlError; } diff --git a/packages/stream_chat_flutter/pubspec.yaml b/packages/stream_chat_flutter/pubspec.yaml index 342914d4..e15f51c7 100644 --- a/packages/stream_chat_flutter/pubspec.yaml +++ b/packages/stream_chat_flutter/pubspec.yaml @@ -7,6 +7,7 @@ issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues environment: sdk: '>=2.12.0 <3.0.0' + flutter: ">=1.17.0" dependencies: cached_network_image: ^3.0.0 diff --git a/packages/stream_chat_localizations/lib/src/i18n/en.json b/packages/stream_chat_localizations/lib/src/i18n/en.json deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations.dart index 25ca28ea..b0ca6cd5 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations.dart @@ -1,12 +1,45 @@ -import 'dart:convert'; - +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart' show rootBundle; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart' show StreamChatLocalizations; -const kStreamChatSupportedLanguages = []; +part 'stream_chat_localizations_en.dart'; + +/// The set of supported languages, as language code strings. +/// +/// The [GlobalStreamChatLocalizations.delegate] can generate localizations for +/// any [Locale] with a language code from this set. +/// +/// See also: +/// +/// * [getStreamChatTranslation], whose documentation describes these values. +const kStreamChatSupportedLanguages = {'en'}; + +/// Creates a [GlobalStreamChatLocalizations] instance for the given `locale`. +/// +/// All of the function's arguments except `locale` will be passed to the +/// [GlobalStreamChatLocalizations] constructor. (The `localeName` argument of that +/// constructor is specified by the actual subclass constructor by this +/// function.) +/// +/// The following locales are supported by this package: +/// +/// * `en` - English +/// +/// Generally speaking, this method is only intended to be used by +/// [GlobalStreamChatLocalizations.delegate]. +GlobalStreamChatLocalizations? getStreamChatTranslation(Locale locale) { + switch (locale.languageCode) { + case 'en': + return const StreamChatLocalizationsEn(); + } + assert( + false, + 'getStreamChatTranslation() called for unsupported locale "$locale"', + ); + return null; +} /// Implementation of localized strings for the stream chat widgets /// @@ -30,43 +63,21 @@ const kStreamChatSupportedLanguages = []; /// localizationsDelegates: GlobalStreamChatLocalizations.delegates, /// supportedLocales: [ /// const Locale('en', 'US'), // American English -/// const Locale('he', 'IL'), // Israeli Hebrew /// // ... /// ], /// // ... /// ) /// ``` /// -class GlobalStreamChatLocalizations implements StreamChatLocalizations { - /// Construct an object that defines the localized values for the widgets - /// library for US English (only). - /// - /// [LocalizationsDelegate] implementations typically call the static [load] - const GlobalStreamChatLocalizations(this.locale, this.translations); +abstract class GlobalStreamChatLocalizations + implements StreamChatLocalizations { + /// Initializes an object that defines the StreamChat widget's localized + /// strings for the given `localeName`. + const GlobalStreamChatLocalizations({ + required String localeName, + }) : _localeName = localeName; - final Locale locale; - - final Map translations; - - static String getLocalePath(Locale locale) => - 'packages/stream_chat_localizations/i18n/${locale.languageCode}.json'; - - /// Creates an object that provides US English resource values for the - /// lowest levels of the widgets library. - /// - /// The [locale] parameter is ignored. - /// - /// This method is typically used to create a [LocalizationsDelegate]. - /// The [WidgetsApp] does so by default. - static Future load(Locale locale) async { - final localePath = getLocalePath(locale); - final rawTranslations = await rootBundle.loadString(localePath); - Map translations = json.decode(rawTranslations); - translations = translations.map( - (key, value) => MapEntry(key, value?.toString()), - ); - return GlobalStreamChatLocalizations(locale, translations); - } + final String _localeName; /// A [LocalizationsDelegate] for [StreamChatLocalizations]. /// @@ -74,7 +85,7 @@ class GlobalStreamChatLocalizations implements StreamChatLocalizations { /// as the value of [MaterialApp.localizationsDelegates] to include /// the localizations for both the flutter and stream chat widget libraries. static const LocalizationsDelegate delegate = - _StreamChatLocalizationsDelegate(); + _StreamChatLocalizationsDelegate(); /// A value for [MaterialApp.localizationsDelegates] that's typically used by /// internationalized apps. @@ -92,20 +103,19 @@ class GlobalStreamChatLocalizations implements StreamChatLocalizations { /// localizationsDelegates: GlobalStreamChatLocalizations.delegates, /// supportedLocales: [ /// const Locale('en', 'US'), // English - /// const Locale('he', 'IL'), // Hebrew /// ], /// // ... /// ) /// ``` static const List delegates = [ - delegate, + GlobalStreamChatLocalizations.delegate, GlobalCupertinoLocalizations.delegate, GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, ]; @override - String? translate(String key) => translations[key]; + String get launchUrlError; } class _StreamChatLocalizationsDelegate @@ -116,14 +126,25 @@ class _StreamChatLocalizationsDelegate bool isSupported(Locale locale) => kStreamChatSupportedLanguages.contains(locale.languageCode); + static final _loadedTranslations = + >{}; + @override - Future load(Locale locale) => - GlobalStreamChatLocalizations.load(locale); + Future load(Locale locale) { + assert(isSupported(locale), ''); + return _loadedTranslations.putIfAbsent( + locale, + () => + SynchronousFuture( + getStreamChatTranslation(locale)!, + ), + ); + } @override bool shouldReload(_StreamChatLocalizationsDelegate old) => false; @override - String toString() => 'StreamChatLocalizations.delegate(' + String toString() => 'GlobalStreamChatLocalizations.delegate(' '${kStreamChatSupportedLanguages.length} locales)'; } diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_en.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_en.dart new file mode 100644 index 00000000..7566be30 --- /dev/null +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_en.dart @@ -0,0 +1,11 @@ +part of 'stream_chat_localizations.dart'; + +/// The translations for English (`en`). +class StreamChatLocalizationsEn extends GlobalStreamChatLocalizations { + /// Create an instance of the translation bundle for English. + const StreamChatLocalizationsEn({String localeName = 'en'}) + : super(localeName: localeName); + + @override + String get launchUrlError => 'Cannot launch the url'; +} diff --git a/packages/stream_chat_localizations/lib/stream_chat_localizations.dart b/packages/stream_chat_localizations/lib/stream_chat_localizations.dart index 9c1146d8..0cfb60ba 100644 --- a/packages/stream_chat_localizations/lib/stream_chat_localizations.dart +++ b/packages/stream_chat_localizations/lib/stream_chat_localizations.dart @@ -1,4 +1,9 @@ /// Localizations for the StreamChat Flutter library. library stream_chat_localization; -export 'src/stream_chat_localizations.dart'; +export 'package:flutter_localizations/flutter_localizations.dart' + show + GlobalCupertinoLocalizations, + GlobalMaterialLocalizations, + GlobalWidgetsLocalizations; +export 'src/stream_chat_localizations.dart' hide getStreamChatTranslation; diff --git a/packages/stream_chat_localizations/pubspec.yaml b/packages/stream_chat_localizations/pubspec.yaml index 34986658..b755a6dd 100644 --- a/packages/stream_chat_localizations/pubspec.yaml +++ b/packages/stream_chat_localizations/pubspec.yaml @@ -18,40 +18,3 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter. -flutter: - - # To add assets to your package, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - # - # For details regarding assets in packages, see - # https://flutter.dev/assets-and-images/#from-packages - # - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. - - # To add custom fonts to your package, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts in packages, see - # https://flutter.dev/custom-fonts/#from-packages diff --git a/packages/stream_chat_localizations/test/stream_chat_localization_test.dart b/packages/stream_chat_localizations/test/stream_chat_localization_test.dart index 9ea48cb5..0324dd17 100644 --- a/packages/stream_chat_localizations/test/stream_chat_localization_test.dart +++ b/packages/stream_chat_localizations/test/stream_chat_localization_test.dart @@ -1,12 +1,20 @@ +import 'dart:ui'; + import 'package:flutter_test/flutter_test.dart'; -import 'package:stream_chat_localization/stream_chat_localizations.dart'; +import 'package:stream_chat_localizations/stream_chat_localizations.dart'; void main() { - test('adds one to input values', () { - final calculator = Calculator(); - expect(calculator.addOne(2), 3); - expect(calculator.addOne(-7), -6); - expect(calculator.addOne(0), 1); - }); + for (final language in kStreamChatSupportedLanguages) { + test('translations exist for $language', () async { + final locale = Locale(language); + expect( + GlobalStreamChatLocalizations.delegate.isSupported(locale), + isTrue, + ); + final localizations = + await GlobalStreamChatLocalizations.delegate.load(locale); + expect(localizations.launchUrlError, isNotNull); + }); + } }