2
0
mirror of https://github.com/inventree/inventree-app.git synced 2025-04-28 05:26:47 +00:00

Locale switch (#200)

* Add function to set app locale

* Setting for selecting app language

- Adds requirement for "flutter_localized_locales"
- Change main app to stateless

* Reload entire app tree when language is changed

* Update release notes

* linting
This commit is contained in:
Oliver 2022-08-02 15:54:59 +10:00 committed by GitHub
parent 19ff6eb526
commit 9559b8602e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 158 additions and 1 deletions

View File

@ -6,6 +6,7 @@
- Allow serial numbers to be specified when creating new stock items - Allow serial numbers to be specified when creating new stock items
- Allow serial numbers to be edited for existing stock items - Allow serial numbers to be edited for existing stock items
- Allow app locale to be changed manually
### 0.8.1 - August 2022 ### 0.8.1 - August 2022
--- ---

View File

@ -473,6 +473,16 @@
"labelTemplate": "Label Template", "labelTemplate": "Label Template",
"@labelTemplate": {}, "@labelTemplate": {},
"language": "Language",
"@language": {},
"languageDefault": "Default system language",
"@languageDefault": {},
"languageSelect": "Select Language",
"@languageSelect": {},
"lastStocktake": "Last Stocktake", "lastStocktake": "Last Stocktake",
"@lastStocktake": {}, "@lastStocktake": {},

View File

@ -4,12 +4,14 @@ import "package:flutter_localizations/flutter_localizations.dart";
import "package:flutter_gen/gen_l10n/app_localizations.dart"; import "package:flutter_gen/gen_l10n/app_localizations.dart";
import "package:flutter/material.dart"; import "package:flutter/material.dart";
import "package:flutter_localized_locales/flutter_localized_locales.dart";
import "package:one_context/one_context.dart"; import "package:one_context/one_context.dart";
import "package:package_info_plus/package_info_plus.dart"; import "package:package_info_plus/package_info_plus.dart";
import "package:sentry_flutter/sentry_flutter.dart"; import "package:sentry_flutter/sentry_flutter.dart";
import "package:inventree/inventree/sentry.dart"; import "package:inventree/inventree/sentry.dart";
import "package:inventree/dsn.dart"; import "package:inventree/dsn.dart";
import "package:inventree/preferences.dart";
import "package:inventree/widget/home.dart"; import "package:inventree/widget/home.dart";
// Supported translations are automatically updated // Supported translations are automatically updated
@ -60,9 +62,43 @@ Future<void> main() async {
} }
class InvenTreeApp extends StatelessWidget { class InvenTreeApp extends StatefulWidget {
// This widget is the root of your application. // This widget is the root of your application.
@override
InvenTreeAppState createState() => InvenTreeAppState();
static InvenTreeAppState? of(BuildContext context) => context.findAncestorStateOfType<InvenTreeAppState>();
}
class InvenTreeAppState extends State<StatefulWidget> {
// Custom _locale (default = null; use system default)
Locale? _locale;
@override
void initState() {
super.initState();
// Load selected locale
loadDefaultLocale();
}
// Load the default app locale
Future<void> loadDefaultLocale() async {
Locale? locale = await InvenTreeSettingsManager().getSelectedLocale();
setLocale(locale);
}
// Update the app locale
void setLocale(Locale? locale) {
setState(() {
_locale = locale;
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -78,11 +114,13 @@ class InvenTreeApp extends StatelessWidget {
home: InvenTreeHomePage(), home: InvenTreeHomePage(),
localizationsDelegates: [ localizationsDelegates: [
I18N.delegate, I18N.delegate,
LocaleNamesLocalizationsDelegate(),
GlobalMaterialLocalizations.delegate, GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate, GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate, GlobalWidgetsLocalizations.delegate,
], ],
supportedLocales: supported_locales, supportedLocales: supported_locales,
locale: _locale,
); );
} }
} }

View File

@ -1,5 +1,7 @@
import "dart:async"; import "dart:async";
import "dart:ui";
import "package:inventree/l10n/supported_locales.dart";
import "package:path_provider/path_provider.dart"; import "package:path_provider/path_provider.dart";
import "package:sembast/sembast.dart"; import "package:sembast/sembast.dart";
import "package:sembast/sembast_io.dart"; import "package:sembast/sembast_io.dart";
@ -83,6 +85,26 @@ class InvenTreeSettingsManager {
Future<Database> get _db async => InvenTreePreferencesDB.instance.database; Future<Database> get _db async => InvenTreePreferencesDB.instance.database;
Future<Locale?> getSelectedLocale() async {
final String locale_name = await getValue("customLocale", "") as String;
if (locale_name.isEmpty) {
return null;
}
for (var locale in supported_locales) {
if (locale.toString() == locale_name) {
return locale;
}
}
// No matching locale found
return null;
}
Future<void> setSelectedLocale(Locale? locale) async {
await setValue("customLocale", locale?.toString() ?? "");
}
Future<void> removeValue(String key) async { Future<void> removeValue(String key) async {
await store.record(key).delete(await _db); await store.record(key).delete(await _db);

View File

@ -1,8 +1,12 @@
import "package:flutter/material.dart"; import "package:flutter/material.dart";
import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart";
import "package:flutter_localized_locales/flutter_localized_locales.dart";
import "package:inventree/api_form.dart";
import "package:inventree/l10.dart"; import "package:inventree/l10.dart";
import "package:inventree/l10n/supported_locales.dart";
import "package:inventree/main.dart";
import "package:inventree/preferences.dart"; import "package:inventree/preferences.dart";
@ -27,6 +31,8 @@ class _InvenTreeAppSettingsState extends State<InvenTreeAppSettingsWidget> {
bool reportErrors = true; bool reportErrors = true;
bool strictHttps = false; bool strictHttps = false;
Locale? locale;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@ -46,14 +52,78 @@ class _InvenTreeAppSettingsState extends State<InvenTreeAppSettingsWidget> {
reportErrors = await InvenTreeSettingsManager().getValue(INV_REPORT_ERRORS, true) as bool; reportErrors = await InvenTreeSettingsManager().getValue(INV_REPORT_ERRORS, true) as bool;
strictHttps = await InvenTreeSettingsManager().getValue(INV_STRICT_HTTPS, false) as bool; strictHttps = await InvenTreeSettingsManager().getValue(INV_STRICT_HTTPS, false) as bool;
locale = await InvenTreeSettingsManager().getSelectedLocale();
if (mounted) { if (mounted) {
setState(() {}); setState(() {});
} }
} }
Future<void> _selectLocale(BuildContext context) async {
List<Map<String, dynamic>> options = [
{
"display_name": L10().languageDefault,
"value": null,
}
];
// Construct a list of available locales
for (var locale in supported_locales) {
options.add({
"display_name": LocaleNames.of(context)!.nameOf(locale.toString()),
"value": locale.toString()
});
}
Map<String, dynamic> fields = {
"locale": {
"label": L10().language,
"type": "choice",
"choices": options,
"value": locale?.toString(),
}
};
launchApiForm(
context,
L10().languageSelect,
"",
fields,
icon: FontAwesomeIcons.checkCircle,
onSuccess: (Map<String, dynamic> data) async {
String locale_name = (data["locale"] ?? "") as String;
Locale? selected_locale;
for (var locale in supported_locales) {
if (locale.toString() == locale_name) {
selected_locale = locale;
}
}
await InvenTreeSettingsManager().setSelectedLocale(selected_locale);
setState(() {
locale = selected_locale;
});
// Refresh the entire app locale
InvenTreeApp.of(context)?.setLocale(locale);
}
);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
String languageName = L10().languageDefault;
if (locale != null) {
languageName = LocaleNames.of(context)!.nameOf(locale.toString()) ?? L10().languageDefault;
}
return Scaffold( return Scaffold(
key: _settingsKey, key: _settingsKey,
appBar: AppBar( appBar: AppBar(
@ -142,6 +212,14 @@ class _InvenTreeAppSettingsState extends State<InvenTreeAppSettingsWidget> {
}, },
), ),
), ),
ListTile(
title: Text(L10().language),
subtitle: Text(languageName),
leading: FaIcon(FontAwesomeIcons.language),
onTap: () async {
_selectLocale(context);
},
),
ListTile( ListTile(
title: Text(L10().errorReportUpload), title: Text(L10().errorReportUpload),
subtitle: Text(L10().errorReportUploadDetails), subtitle: Text(L10().errorReportUploadDetails),

View File

@ -284,6 +284,13 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_localized_locales:
dependency: "direct main"
description:
name: flutter_localized_locales
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.3"
flutter_markdown: flutter_markdown:
dependency: "direct main" dependency: "direct main"
description: description:

View File

@ -21,6 +21,7 @@ dependencies:
flutter_cache_manager: ^3.3.0 flutter_cache_manager: ^3.3.0
flutter_localizations: flutter_localizations:
sdk: flutter sdk: flutter
flutter_localized_locales: 2.0.3
flutter_markdown: ^0.6.9 # Rendering markdown flutter_markdown: ^0.6.9 # Rendering markdown
flutter_overlay_loader: ^2.0.0 # Overlay screen support flutter_overlay_loader: ^2.0.0 # Overlay screen support
font_awesome_flutter: ^9.1.0 # FontAwesome icon set font_awesome_flutter: ^9.1.0 # FontAwesome icon set