Skip to content

Commit

Permalink
Skeleton for l10n
Browse files Browse the repository at this point in the history
  • Loading branch information
PrimozRatej committed Mar 12, 2024
1 parent 8087329 commit 467ffe0
Show file tree
Hide file tree
Showing 13 changed files with 332 additions and 92 deletions.
3 changes: 3 additions & 0 deletions l10n.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
86 changes: 86 additions & 0 deletions lib/components/language_switcher.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import 'package:flutter/material.dart';
import 'package:humhub/util/extensions.dart';
import 'package:humhub/util/override_locale.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

class LocaleSwitch extends StatefulWidget {
final double width;
static Key userProfileLocaleDropdown = const Key('user_profile_locale_dropdown');
const LocaleSwitch({
Key? key,
this.showTitle = false,
this.forceLight = false,
this.width = 100,
}) : super(key: key);

final bool showTitle;
final bool forceLight;

@override
State<LocaleSwitch> createState() => _LocaleSwitchState();
}

class _LocaleSwitchState extends State<LocaleSwitch> {
@override
Widget build(BuildContext context) {
return SizedBox(
width: widget.width,
child: DropdownButtonFormField<int>(
style: TextStyle(fontWeight: FontWeight.bold, color: Theme.of(context).primaryColor),
key: LocaleSwitch.userProfileLocaleDropdown,
selectedItemBuilder: (_) {
return _items
.map(
(e) => Text(
e.toUpperCase(),
),
)
.toList();
},
dropdownColor: widget.forceLight ? Colors.white : Theme.of(context).colorScheme.background,
decoration: widget.showTitle
? InputDecoration(
labelText: AppLocalizations.of(context)!.cancel,
enabledBorder: InputBorder.none,
fillColor: Colors.black,
)
: InputDecoration.collapsed(
hintText: AppLocalizations.of(context)!.cancel,
).copyWith(
enabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
),
isExpanded: true,
value: _value(context),
icon: Icon(Icons.arrow_drop_down, color: Theme.of(context).primaryColor),
items: _items
.mapIndexed(
(text, index) => DropdownMenuItem(
value: index,
child: Text(
text.toUpperCase(),
),
),
)
.toList(),
onChanged: (index) {
if (index == null) return;
Locale? locale = AppLocalizations.supportedLocales.elementAt(index);
OverrideLocale.of(context).changeLocale(locale);
},
),
);
}

Iterable<String> get _items => [
...AppLocalizations.supportedLocales.map((l) => l.languageCode),
];

int _value(BuildContext context) {
String localDef = Localizations.localeOf(context).toString();
final index = AppLocalizations.supportedLocales.indexWhere(
(locale) => localDef == locale.languageCode,
);
return index;
}
}
5 changes: 5 additions & 0 deletions lib/l10n/app_de.arb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"cancel" : "Abbrechen",
"help_title" : "Was ist HumHub?",
"help_first_par" : "HumHub ist eine Open-Source-Software, die von Organisationen, Vereinen und Unternehmen hauptsächlich als soziales Netzwerk, Intranet oder Kommunikationsplattform genutzt wird."
}
5 changes: 5 additions & 0 deletions lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"cancel" : "Cancel",
"help_title" : "What is HumHub?",
"help_first_par" : "HumHub is an Open Source software used by organizations, associations and companies mainly as social network, intranet or communication platform."
}
5 changes: 5 additions & 0 deletions lib/l10n/app_es.arb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"cancel" : "Cancelar",
"help_title" : "¿Qué es HumHub?",
"help_first_par" : "HumHub es un software de código abierto utilizado principalmente por organizaciones, asociaciones y empresas como red social, intranet o plataforma de comunicación."
}
43 changes: 26 additions & 17 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:humhub/util/intent/intent_plugin.dart';
import 'package:humhub/util/log.dart';
import 'package:humhub/util/notifications/plugin.dart';
import 'package:humhub/util/override_locale.dart';
import 'package:humhub/util/push/push_plugin.dart';
import 'package:humhub/util/router.dart';
import 'package:loggy/loggy.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

main() async {
Loggy.initLoggy(
Expand All @@ -35,22 +37,29 @@ class MyAppState extends ConsumerState<MyApp> {
return IntentPlugin(
child: NotificationPlugin(
child: PushPlugin(
child: FutureBuilder<String>(
future: MyRouter.getInitialRoute(ref),
builder: (context, snap) {
if (snap.hasData) {
return MaterialApp(
debugShowCheckedModeBanner: false,
initialRoute: snap.data,
routes: MyRouter.routes,
navigatorKey: navigatorKey,
theme: ThemeData(
fontFamily: 'OpenSans',
),
);
}
return const SizedBox.shrink();
},
child: OverrideLocale(
builder: (overrideLocale) => Builder(
builder: (context) => FutureBuilder<String>(
future: MyRouter.getInitialRoute(ref),
builder: (context, snap) {
if (snap.hasData) {
return MaterialApp(
debugShowCheckedModeBanner: false,
initialRoute: snap.data,
routes: MyRouter.routes,
navigatorKey: navigatorKey,
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
locale: overrideLocale,
theme: ThemeData(
fontFamily: 'OpenSans',
),
);
}
return const SizedBox.shrink();
},
),
),
),
),
),
Expand All @@ -62,7 +71,7 @@ clearSecureStorageOnReinstall() async {
String key = 'hasRunBefore';
SharedPreferences prefs = await SharedPreferences.getInstance();
bool hasRunBefore = prefs.getBool(key) ?? false;
if(!hasRunBefore) {
if (!hasRunBefore) {
FlutterSecureStorage storage = const FlutterSecureStorage();
await storage.deleteAll();
prefs.setBool(key, true);
Expand Down
5 changes: 3 additions & 2 deletions lib/pages/help/components/first_page.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:humhub/components/rotating_globe.dart';
import 'package:humhub/util/const.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';


class FirstPage extends StatelessWidget {
Expand All @@ -20,15 +21,15 @@ class FirstPage extends StatelessWidget {
child: Align(
alignment: Alignment.centerLeft,
child: Text(
Locales.helpTitle,
AppLocalizations.of(context)!.help_title,
style: getHeaderStyle(context),
),
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Text(
Locales.helpFirstPar,
AppLocalizations.of(context)!.help_first_par,
style: paragraphStyle,
),
),
Expand Down
5 changes: 4 additions & 1 deletion lib/pages/opener.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import 'dart:io';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:humhub/components/language_switcher.dart';
import 'package:humhub/pages/web_view.dart';
import 'package:humhub/util/const.dart';
import 'package:humhub/util/form_helper.dart';
Expand Down Expand Up @@ -51,7 +53,7 @@ class OpenerState extends ConsumerState<Opener> with SingleTickerProviderStateMi
});

String? urlIntent = InitFromIntent.usePayloadForInit();
if(urlIntent != null){
if (urlIntent != null) {
await RedirectNotificationChannel().onTap(urlIntent);
}
});
Expand Down Expand Up @@ -85,6 +87,7 @@ class OpenerState extends ConsumerState<Opener> with SingleTickerProviderStateMi
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Align(alignment: Alignment.topRight, child: LocaleSwitch(width: 70,)),
Expanded(
flex: 2,
child: AnimatedOpacity(
Expand Down
5 changes: 3 additions & 2 deletions lib/pages/web_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,9 @@ class WebViewAppState extends ConsumerState<WebViewApp> {
if (Platform.isAndroid ||
action.iosWKNavigationType == IOSWKNavigationType.LINK_ACTIVATED ||
action.iosWKNavigationType == IOSWKNavigationType.FORM_SUBMITTED) {
action.request.headers?.addAll(_initialRequest.headers!);
controller.loadUrl(urlRequest: action.request);
Map<String, String> mergedMap = {...?_initialRequest.headers, ...?action.request.headers};
URLRequest newRequest = action.request.copyWith(headers: mergedMap);
controller.loadUrl(urlRequest: newRequest);
return NavigationActionPolicy.CANCEL;
}
return NavigationActionPolicy.ALLOW;
Expand Down
89 changes: 74 additions & 15 deletions lib/util/extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,10 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:humhub/models/manifest.dart';
import 'package:humhub/pages/opener.dart';
import 'package:humhub/util/const.dart';
import 'package:humhub/util/providers.dart';
import 'package:loggy/loggy.dart';
import 'package:webview_flutter/webview_flutter.dart';

// ignore_for_file: use_build_context_synchronously
extension MyCookies on WebViewCookieManager {
Future<void> setMyCookies(Manifest manifest) async {
await setCookie(
WebViewCookie(
name: 'is_mobile_app',
value: 'true',
domain: manifest.baseUrl,
),
);
}
}

extension MyWebViewController on InAppWebViewController {
Future<bool> exitApp(BuildContext context, ref) async {
Expand Down Expand Up @@ -94,3 +79,77 @@ extension FutureAsyncValueX<T> on Future<AsyncValue<T>> {
(asyncValue) => asyncValue.asData?.value,
);
}

extension PrettyUri on Uri {
bool isUriPretty() {
RegExp regex = RegExp(r'index\.php.*[?&]r=');
String path = Uri.decodeComponent(toString());
return !regex.hasMatch(path);
}
}

extension URLRequestExtension on URLRequest {
URLRequest copyWith({
Uri? url,
String? method,
Uint8List? body,
Map<String, String>? headers,
bool? iosAllowsCellularAccess,
bool? iosAllowsConstrainedNetworkAccess,
bool? iosAllowsExpensiveNetworkAccess,
IOSURLRequestCachePolicy? iosCachePolicy,
bool? iosHttpShouldHandleCookies,
bool? iosHttpShouldUsePipelining,
IOSURLRequestNetworkServiceType? iosNetworkServiceType,
double? iosTimeoutInterval,
Uri? iosMainDocumentURL,
}) {
return URLRequest(
url: url ?? this.url,
method: method ?? this.method,
headers: headers ?? this.headers,
body: body ?? this.body,
iosAllowsCellularAccess: iosAllowsCellularAccess ?? this.iosAllowsCellularAccess,
iosAllowsConstrainedNetworkAccess: iosAllowsConstrainedNetworkAccess ?? this.iosAllowsConstrainedNetworkAccess,
iosAllowsExpensiveNetworkAccess: iosAllowsExpensiveNetworkAccess ?? this.iosAllowsExpensiveNetworkAccess,
iosCachePolicy: iosCachePolicy ?? this.iosCachePolicy,
iosHttpShouldHandleCookies: iosHttpShouldHandleCookies ?? this.iosHttpShouldHandleCookies,
iosHttpShouldUsePipelining: iosHttpShouldUsePipelining ?? this.iosHttpShouldUsePipelining,
iosNetworkServiceType: iosNetworkServiceType ?? this.iosNetworkServiceType,
iosTimeoutInterval: iosTimeoutInterval ?? this.iosTimeoutInterval,
iosMainDocumentURL: iosMainDocumentURL ?? this.iosMainDocumentURL,
);
}
}

extension IterableX<E> on Iterable<E> {
Iterable<T> mapIndexed<T>(T Function(E e, int i) f) {
var i = 0;
return map((e) => f(e, i++));
}

void forEachIndexed(void Function(E e, int i) f) {
var i = 0;
forEach((e) => f(e, i++));
}

Map<Y, List<E>> groupBy<Y>(Y Function(E e) fn) {
return Map.fromIterable(
map(fn).toSet(),
value: (i) => where((v) => fn(v) == i).toList(),
);
}

Iterable<E> distinctBy<Key>(Key Function(E element) by) {
final keys = <dynamic>{};
return where((item) {
final key = by(item);
if (!keys.contains(key)) {
keys.add(key);
return true;
} else {
return false;
}
});
}
}
Loading

0 comments on commit 467ffe0

Please sign in to comment.