From 171d808410a34827568752558a5ecda7b2771362 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 1 Feb 2021 16:58:08 +1100 Subject: [PATCH 1/7] Init basic localizations --- lib/main.dart | 16 ++++++++++++++++ pubspec.lock | 5 +++++ pubspec.yaml | 4 ++-- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index ff7bd8cb..ff94b80f 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,7 @@ import 'dart:async'; +import 'package:flutter_localizations/flutter_localizations.dart'; + import 'package:InvenTree/widget/category_display.dart'; import 'package:InvenTree/widget/company_list.dart'; import 'package:InvenTree/widget/location_display.dart'; @@ -77,6 +79,20 @@ class InvenTreeApp extends StatelessWidget { secondaryHeaderColor: Colors.blueGrey, ), home: MyHomePage(title: 'InvenTree'), + localizationsDelegates: [ + // ... app-specific localization delegate[s] here + // TODO: uncomment the line below after codegen + // AppLocalizations.delegate, + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: [ + const Locale('en', ''), // English, no country code + const Locale('de', ''), + const Locale('fr', ''), + const Locale('it', ''), + ], ); } } diff --git a/pubspec.lock b/pubspec.lock index 600009f4..389e467d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -174,6 +174,11 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.8.1" + flutter_localizations: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" flutter_plugin_android_lifecycle: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 7145d90c..c3baeaa6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -19,9 +19,9 @@ environment: dependencies: flutter: sdk: flutter + flutter_localizations: + sdk: flutter - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^0.1.3 http: ^0.12.1 shared_preferences: ^0.5.7 From a50883f2bde436060a00469b34789170aafee0ad Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 1 Feb 2021 17:02:52 +1100 Subject: [PATCH 2/7] Add l10n config file --- l10n.yaml | 3 +++ pubspec.yaml | 5 +++++ 2 files changed, 8 insertions(+) create mode 100644 l10n.yaml diff --git a/l10n.yaml b/l10n.yaml new file mode 100644 index 00000000..b2fcf348 --- /dev/null +++ b/l10n.yaml @@ -0,0 +1,3 @@ +arb-dir: lib/i18n +template-arb-file: app_en.arb +output-localization-file: app_localizations.dart \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index c3baeaa6..ec09a4c1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -19,9 +19,12 @@ environment: dependencies: flutter: sdk: flutter + flutter_localizations: sdk: flutter + intl: ^0.16.1 + cupertino_icons: ^0.1.3 http: ^0.12.1 shared_preferences: ^0.5.7 @@ -62,6 +65,8 @@ flutter: # the material Icons class. uses-material-design: true + generate: true + assets: - assets/image/icon.png From 0ba72a59c61120b0a0fb33c4f3d316bc937ebe42 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 1 Feb 2021 17:19:37 +1100 Subject: [PATCH 3/7] Separate main widget into separate file from app --- l10n.yaml | 3 +- lib/generated/i18n.dart | 110 ++++-------- lib/main.dart | 359 +--------------------------------------- lib/widget/home.dart | 337 +++++++++++++++++++++++++++++++++++++ pubspec.lock | 2 +- 5 files changed, 379 insertions(+), 432 deletions(-) create mode 100644 lib/widget/home.dart diff --git a/l10n.yaml b/l10n.yaml index b2fcf348..1baa7ccc 100644 --- a/l10n.yaml +++ b/l10n.yaml @@ -1,3 +1,4 @@ arb-dir: lib/i18n template-arb-file: app_en.arb -output-localization-file: app_localizations.dart \ No newline at end of file +output-localization-file: app_localizations.dart +output-class: I18N \ No newline at end of file diff --git a/lib/generated/i18n.dart b/lib/generated/i18n.dart index 2dcf8369..db983ef0 100644 --- a/lib/generated/i18n.dart +++ b/lib/generated/i18n.dart @@ -1,122 +1,78 @@ + import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; - // ignore_for_file: non_constant_identifier_names // ignore_for_file: camel_case_types // ignore_for_file: prefer_single_quotes -// This file is automatically generated. DO NOT EDIT, all your changes would be lost. +//This file is automatically generated. DO NOT EDIT, all your changes would be lost. + class S implements WidgetsLocalizations { const S(); static const GeneratedLocalizationsDelegate delegate = - GeneratedLocalizationsDelegate(); + const GeneratedLocalizationsDelegate(); - static S of(BuildContext context) => Localizations.of(context, S); + static S of(BuildContext context) => + Localizations.of(context, WidgetsLocalizations); @override TextDirection get textDirection => TextDirection.ltr; } -class $en extends S { - const $en(); +class en extends S { + const en(); } -class GeneratedLocalizationsDelegate extends LocalizationsDelegate { + +class GeneratedLocalizationsDelegate extends LocalizationsDelegate { const GeneratedLocalizationsDelegate(); List get supportedLocales { return const [ - Locale("en", ""), + + const Locale("en", ""), + ]; } - LocaleListResolutionCallback listResolution({Locale fallback, bool withCountry = true}) { - return (List locales, Iterable supported) { - if (locales == null || locales.isEmpty) { - return fallback ?? supported.first; - } else { - return _resolve(locales.first, fallback, supported, withCountry); - } - }; - } - - LocaleResolutionCallback resolution({Locale fallback, bool withCountry = true}) { + LocaleResolutionCallback resolution({Locale fallback}) { return (Locale locale, Iterable supported) { - return _resolve(locale, fallback, supported, withCountry); + final Locale languageLocale = new Locale(locale.languageCode, ""); + if (supported.contains(locale)) + return locale; + else if (supported.contains(languageLocale)) + return languageLocale; + else { + final Locale fallbackLocale = fallback ?? supported.first; + return fallbackLocale; + } }; } @override - Future load(Locale locale) { + Future load(Locale locale) { final String lang = getLang(locale); - if (lang != null) { - switch (lang) { - case "en": - return SynchronousFuture(const $en()); - default: - // NO-OP. - } + switch (lang) { + + case "en": + return new SynchronousFuture(const en()); + + default: + return new SynchronousFuture(const S()); } - return SynchronousFuture(const S()); } @override - bool isSupported(Locale locale) => _isSupported(locale, true); + bool isSupported(Locale locale) => supportedLocales.contains(locale); @override bool shouldReload(GeneratedLocalizationsDelegate old) => false; - - /// - /// Internal method to resolve a locale from a list of locales. - /// - Locale _resolve(Locale locale, Locale fallback, Iterable supported, bool withCountry) { - if (locale == null || !_isSupported(locale, withCountry)) { - return fallback ?? supported.first; - } - - final Locale languageLocale = Locale(locale.languageCode, ""); - if (supported.contains(locale)) { - return locale; - } else if (supported.contains(languageLocale)) { - return languageLocale; - } else { - final Locale fallbackLocale = fallback ?? supported.first; - return fallbackLocale; - } - } - - /// - /// Returns true if the specified locale is supported, false otherwise. - /// - bool _isSupported(Locale locale, bool withCountry) { - if (locale != null) { - for (Locale supportedLocale in supportedLocales) { - // Language must always match both locales. - if (supportedLocale.languageCode != locale.languageCode) { - continue; - } - - // If country code matches, return this locale. - if (supportedLocale.countryCode == locale.countryCode) { - return true; - } - - // If no country requirement is requested, check if this locale has no country. - if (true != withCountry && (supportedLocale.countryCode == null || supportedLocale.countryCode.isEmpty)) { - return true; - } - } - } - return false; - } } -String getLang(Locale l) => l == null - ? null - : l.countryCode != null && l.countryCode.isEmpty +String getLang(Locale l) => l.countryCode != null && l.countryCode.isEmpty ? l.languageCode : l.toString(); diff --git a/lib/main.dart b/lib/main.dart index ff94b80f..46b31b85 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,21 +1,12 @@ import 'dart:async'; import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -import 'package:InvenTree/widget/category_display.dart'; -import 'package:InvenTree/widget/company_list.dart'; -import 'package:InvenTree/widget/location_display.dart'; -import 'package:InvenTree/widget/search.dart'; -import 'package:InvenTree/widget/drawer.dart'; +import 'package:InvenTree/widget/home.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; - -import 'barcode.dart'; - -import 'api.dart'; import 'dsn.dart'; import 'preferences.dart'; @@ -73,16 +64,14 @@ class InvenTreeApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( - title: 'InvenTree', + onGenerateTitle: (BuildContext context) => I18N.of(context).appTitle, theme: ThemeData( primarySwatch: Colors.lightBlue, secondaryHeaderColor: Colors.blueGrey, ), - home: MyHomePage(title: 'InvenTree'), + home: InvenTreeHomePage(), localizationsDelegates: [ - // ... app-specific localization delegate[s] here - // TODO: uncomment the line below after codegen - // AppLocalizations.delegate, + I18N.delegate, GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, @@ -95,340 +84,4 @@ class InvenTreeApp extends StatelessWidget { ], ); } -} - - -class MyHomePage extends StatefulWidget { - MyHomePage({Key key, this.title}) : super(key: key); - - - // This widget is the home page of your application. It is stateful, meaning - // that it has a State object (defined below) that contains fields that affect - // how it looks. - - // This class is the configuration for the state. It holds the values (in this - // case the title) provided by the parent (in this case the App widget) and - // used by the build method of the State. Fields in a Widget subclass are - // always marked "final". - - final String title; - - @override - _MyHomePageState createState() => _MyHomePageState(); -} - -class _MyHomePageState extends State { - - _MyHomePageState() : super() { - _checkServerConnection(); - } - - String _serverAddress = ""; - - String _serverStatus = "Connecting to server"; - - String _serverMessage = ""; - - bool _serverConnection = false; - - FaIcon _serverIcon = new FaIcon(FontAwesomeIcons.spinner); - - Color _serverStatusColor = Color.fromARGB(255, 50, 50, 250); - - void onConnectSuccess(String msg) { - _serverConnection = true; - _serverMessage = msg; - _serverStatus = "Connected to $_serverAddress"; - _serverStatusColor = Color.fromARGB(255, 50, 250, 50); - _serverIcon = new FaIcon(FontAwesomeIcons.checkCircle, color: _serverStatusColor); - - setState(() {}); - } - - void onConnectFailure(String msg) { - _serverConnection = false; - _serverMessage = msg; - _serverStatus = "Could not connect to $_serverAddress"; - _serverStatusColor = Color.fromARGB(255, 250, 50, 50); - _serverIcon = new FaIcon(FontAwesomeIcons.timesCircle, color: _serverStatusColor); - - setState(() {}); - } - - /* - * Test the server connection - */ - void _checkServerConnection() async { - - var prefs = await SharedPreferences.getInstance(); - - _serverAddress = prefs.getString("server"); - - // Reset the connection status variables - _serverStatus = "Connecting to server"; - _serverMessage = ""; - _serverConnection = false; - _serverIcon = new FaIcon(FontAwesomeIcons.spinner); - _serverStatusColor = Color.fromARGB(255, 50, 50, 250); - - InvenTreeAPI().connect().then((bool result) { - - if (result) { - onConnectSuccess(""); - } else { - onConnectFailure("Could not connect to server"); - } - - }); - - // Update widget state - setState(() {}); - } - - void _search() { - if (!InvenTreeAPI().checkConnection(context)) return; - - Navigator.push(context, MaterialPageRoute(builder: (context) => SearchWidget())); - - } - - void _scan() { - if (!InvenTreeAPI().checkConnection(context)) return; - - scanQrCode(context); - } - - void _parts() { - if (!InvenTreeAPI().checkConnection(context)) return; - - Navigator.push(context, MaterialPageRoute(builder: (context) => CategoryDisplayWidget(null))); - } - - void _stock() { - if (!InvenTreeAPI().checkConnection(context)) return; - - Navigator.push(context, MaterialPageRoute(builder: (context) => LocationDisplayWidget(null))); - } - - void _suppliers() { - if (!InvenTreeAPI().checkConnection(context)) return; - - Navigator.push(context, MaterialPageRoute(builder: (context) => SupplierListWidget())); - } - - void _manufacturers() { - if (!InvenTreeAPI().checkConnection(context)) return; - - Navigator.push(context, MaterialPageRoute(builder: (context) => ManufacturerListWidget())); - } - - void _customers() { - if (!InvenTreeAPI().checkConnection(context)) return; - - Navigator.push(context, MaterialPageRoute(builder: (context) => CustomerListWidget())); - } - - void _unsupported() { - showDialog( - context: context, - child: new SimpleDialog( - title: new Text("Unsupported"), - children: [ - ListTile( - title: Text("This feature is not yet supported"), - subtitle: Text("It will be supported in an upcoming release"), - ) - ], - ) - ); - } - - @override - Widget build(BuildContext context) { - // This method is rerun every time setState is called, for instance as done - // by the _incrementCounter method above. - // - // The Flutter framework has been optimized to make rerunning build methods - // fast, so that you can just rebuild anything that needs updating rather - // than having to individually change instances of widgets. - return Scaffold( - appBar: AppBar( - // Here we take the value from the MyHomePage object that was created by - // the App.build method, and use it to set our appbar title. - title: Text(widget.title), - actions: [ - /* - IconButton( - icon: FaIcon(FontAwesomeIcons.search), - tooltip: 'Search', - onPressed: _search, - ), - */ - ], - ), - drawer: new InvenTreeDrawer(context), - body: Center( - // Center is a layout widget. It takes a single child and positions it - // in the middle of the parent. - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: ([ - Spacer(), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - /* - Column( - children: [ - - IconButton( - icon: new FaIcon(FontAwesomeIcons.search), - tooltip: 'Search', - onPressed: _search, - ), - Text("Search"), - ], - ), - */ - Column( - children: [ - IconButton( - icon: new FaIcon(FontAwesomeIcons.barcode), - tooltip: 'Scan Barcode', - onPressed: _scan, - ), - Text("Scan Barcode"), - ], - ), - ], - ), - Spacer(), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Column( - children: [ - IconButton( - icon: new FaIcon(FontAwesomeIcons.shapes), - tooltip: 'Parts', - onPressed: _parts, - ), - Text("Parts"), - ], - ), - Column( - children: [ - IconButton( - icon: new FaIcon(FontAwesomeIcons.boxes), - tooltip: 'Stock', - onPressed: _stock, - ), - Text('Stock'), - ], - ), - ], - ), - Spacer(), - // TODO - Re-add these when the features actually do something.. - /* - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Column( - children: [ - IconButton( - icon: new FaIcon(FontAwesomeIcons.building), - tooltip: "Suppliers", - onPressed: _suppliers, - ), - Text("Suppliers"), - ], - ), - Column( - children: [ - IconButton( - icon: FaIcon(FontAwesomeIcons.industry), - tooltip: "Manufacturers", - onPressed: _manufacturers, - ), - Text("Manufacturers") - ], - ), - Column( - children: [ - IconButton( - icon: FaIcon(FontAwesomeIcons.userTie), - tooltip: "Customers", - onPressed: _customers, - ), - Text("Customers"), - ] - ) - ], - ), - Spacer(), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Column( - children: [ - IconButton( - icon: new FaIcon(FontAwesomeIcons.tools), - tooltip: "Build", - onPressed: _unsupported, - ), - Text("Build"), - ], - ), - Column( - children: [ - IconButton( - icon: new FaIcon(FontAwesomeIcons.shoppingCart), - tooltip: "Order", - onPressed: _unsupported, - ), - Text("Order"), - ] - ), - Column( - children: [ - IconButton( - icon: new FaIcon(FontAwesomeIcons.truck), - tooltip: "Ship", - onPressed: _unsupported, - ), - Text("Ship"), - ] - ) - ], - ), - Spacer(), - */ - Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: ListTile( - title: Text("$_serverStatus", - style: TextStyle(color: _serverStatusColor), - ), - subtitle: Text("$_serverMessage", - style: TextStyle(color: _serverStatusColor), - ), - leading: _serverIcon, - onTap: () { - if (!_serverConnection) { - _checkServerConnection(); - } - }, - ), - ), - ], - ), - ]), - ), - ), - ); - } -} +} \ No newline at end of file diff --git a/lib/widget/home.dart b/lib/widget/home.dart new file mode 100644 index 00000000..b2d99479 --- /dev/null +++ b/lib/widget/home.dart @@ -0,0 +1,337 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import 'package:InvenTree/barcode.dart'; +import 'package:InvenTree/api.dart'; + +import 'package:InvenTree/widget/category_display.dart'; +import 'package:InvenTree/widget/company_list.dart'; +import 'package:InvenTree/widget/location_display.dart'; +import 'package:InvenTree/widget/search.dart'; +import 'package:InvenTree/widget/drawer.dart'; + +class InvenTreeHomePage extends StatefulWidget { + InvenTreeHomePage({Key key}) : super(key: key); + + @override + _InvenTreeHomePageState createState() => _InvenTreeHomePageState(); +} + +class _InvenTreeHomePageState extends State { + + _InvenTreeHomePageState() : super() { + _checkServerConnection(); + } + + String _serverAddress = ""; + + String _serverStatus = "Connecting to server"; + + String _serverMessage = ""; + + bool _serverConnection = false; + + FaIcon _serverIcon = new FaIcon(FontAwesomeIcons.spinner); + + Color _serverStatusColor = Color.fromARGB(255, 50, 50, 250); + + void onConnectSuccess(String msg) { + _serverConnection = true; + _serverMessage = msg; + _serverStatus = "Connected to $_serverAddress"; + _serverStatusColor = Color.fromARGB(255, 50, 250, 50); + _serverIcon = new FaIcon(FontAwesomeIcons.checkCircle, color: _serverStatusColor); + + setState(() {}); + } + + void onConnectFailure(String msg) { + _serverConnection = false; + _serverMessage = msg; + _serverStatus = "Could not connect to $_serverAddress"; + _serverStatusColor = Color.fromARGB(255, 250, 50, 50); + _serverIcon = new FaIcon(FontAwesomeIcons.timesCircle, color: _serverStatusColor); + + setState(() {}); + } + + /* + * Test the server connection + */ + void _checkServerConnection() async { + + var prefs = await SharedPreferences.getInstance(); + + _serverAddress = prefs.getString("server"); + + // Reset the connection status variables + _serverStatus = "Connecting to server"; + _serverMessage = ""; + _serverConnection = false; + _serverIcon = new FaIcon(FontAwesomeIcons.spinner); + _serverStatusColor = Color.fromARGB(255, 50, 50, 250); + + InvenTreeAPI().connect().then((bool result) { + + if (result) { + onConnectSuccess(""); + } else { + onConnectFailure("Could not connect to server"); + } + + }); + + // Update widget state + setState(() {}); + } + + void _search() { + if (!InvenTreeAPI().checkConnection(context)) return; + + Navigator.push(context, MaterialPageRoute(builder: (context) => SearchWidget())); + + } + + void _scan() { + if (!InvenTreeAPI().checkConnection(context)) return; + + scanQrCode(context); + } + + void _parts() { + if (!InvenTreeAPI().checkConnection(context)) return; + + Navigator.push(context, MaterialPageRoute(builder: (context) => CategoryDisplayWidget(null))); + } + + void _stock() { + if (!InvenTreeAPI().checkConnection(context)) return; + + Navigator.push(context, MaterialPageRoute(builder: (context) => LocationDisplayWidget(null))); + } + + void _suppliers() { + if (!InvenTreeAPI().checkConnection(context)) return; + + Navigator.push(context, MaterialPageRoute(builder: (context) => SupplierListWidget())); + } + + void _manufacturers() { + if (!InvenTreeAPI().checkConnection(context)) return; + + Navigator.push(context, MaterialPageRoute(builder: (context) => ManufacturerListWidget())); + } + + void _customers() { + if (!InvenTreeAPI().checkConnection(context)) return; + + Navigator.push(context, MaterialPageRoute(builder: (context) => CustomerListWidget())); + } + + void _unsupported() { + showDialog( + context: context, + child: new SimpleDialog( + title: new Text("Unsupported"), + children: [ + ListTile( + title: Text("This feature is not yet supported"), + subtitle: Text("It will be supported in an upcoming release"), + ) + ], + ) + ); + } + + @override + Widget build(BuildContext context) { + // This method is rerun every time setState is called, for instance as done + // by the _incrementCounter method above. + // + // The Flutter framework has been optimized to make rerunning build methods + // fast, so that you can just rebuild anything that needs updating rather + // than having to individually change instances of widgets. + return Scaffold( + appBar: AppBar( + title: Text(I18N.of(context).appTitle), + actions: [ + /* + IconButton( + icon: FaIcon(FontAwesomeIcons.search), + tooltip: 'Search', + onPressed: _search, + ), + */ + ], + ), + drawer: new InvenTreeDrawer(context), + body: Center( + // Center is a layout widget. It takes a single child and positions it + // in the middle of the parent. + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: ([ + Spacer(), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + /* + Column( + children: [ + + IconButton( + icon: new FaIcon(FontAwesomeIcons.search), + tooltip: 'Search', + onPressed: _search, + ), + Text("Search"), + ], + ), + */ + Column( + children: [ + IconButton( + icon: new FaIcon(FontAwesomeIcons.barcode), + tooltip: 'Scan Barcode', + onPressed: _scan, + ), + Text("Scan Barcode"), + ], + ), + ], + ), + Spacer(), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Column( + children: [ + IconButton( + icon: new FaIcon(FontAwesomeIcons.shapes), + tooltip: 'Parts', + onPressed: _parts, + ), + Text("Parts"), + ], + ), + Column( + children: [ + IconButton( + icon: new FaIcon(FontAwesomeIcons.boxes), + tooltip: 'Stock', + onPressed: _stock, + ), + Text('Stock'), + ], + ), + ], + ), + Spacer(), + // TODO - Re-add these when the features actually do something.. + /* + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Column( + children: [ + IconButton( + icon: new FaIcon(FontAwesomeIcons.building), + tooltip: "Suppliers", + onPressed: _suppliers, + ), + Text("Suppliers"), + ], + ), + Column( + children: [ + IconButton( + icon: FaIcon(FontAwesomeIcons.industry), + tooltip: "Manufacturers", + onPressed: _manufacturers, + ), + Text("Manufacturers") + ], + ), + Column( + children: [ + IconButton( + icon: FaIcon(FontAwesomeIcons.userTie), + tooltip: "Customers", + onPressed: _customers, + ), + Text("Customers"), + ] + ) + ], + ), + Spacer(), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Column( + children: [ + IconButton( + icon: new FaIcon(FontAwesomeIcons.tools), + tooltip: "Build", + onPressed: _unsupported, + ), + Text("Build"), + ], + ), + Column( + children: [ + IconButton( + icon: new FaIcon(FontAwesomeIcons.shoppingCart), + tooltip: "Order", + onPressed: _unsupported, + ), + Text("Order"), + ] + ), + Column( + children: [ + IconButton( + icon: new FaIcon(FontAwesomeIcons.truck), + tooltip: "Ship", + onPressed: _unsupported, + ), + Text("Ship"), + ] + ) + ], + ), + Spacer(), + */ + Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: ListTile( + title: Text("$_serverStatus", + style: TextStyle(color: _serverStatusColor), + ), + subtitle: Text("$_serverMessage", + style: TextStyle(color: _serverStatusColor), + ), + leading: _serverIcon, + onTap: () { + if (!_serverConnection) { + _checkServerConnection(); + } + }, + ), + ), + ], + ), + ]), + ), + ), + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index 389e467d..6569a05d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -253,7 +253,7 @@ packages: source: hosted version: "1.1.1" intl: - dependency: transitive + dependency: "direct main" description: name: intl url: "https://pub.dartlang.org" From d0905d97c3c7c599e9fe255971b4cfb6cfb50445 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 1 Feb 2021 17:26:16 +1100 Subject: [PATCH 4/7] Add submodule --- .gitmodules | 3 +++ lib/l10n | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 lib/l10n diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..d82de0d3 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib/l10n"] + path = lib/l10n + url = https://github.com/inventree/inventree-app-i18n diff --git a/lib/l10n b/lib/l10n new file mode 160000 index 00000000..aa48825b --- /dev/null +++ b/lib/l10n @@ -0,0 +1 @@ +Subproject commit aa48825bd15bb294e705be0bcfe584208292ea31 From ff879bd14b5582169106001e7d01d613342d16f4 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 1 Feb 2021 17:46:18 +1100 Subject: [PATCH 5/7] Update plist file --- ios/Runner/Info.plist | 7 +++++++ l10n.yaml | 2 +- lib/l10n | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 0337b954..1e3e35de 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -4,6 +4,13 @@ CFBundleDevelopmentRegion en + CFBundleLocalizations + + en + de + fr + it + CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier diff --git a/l10n.yaml b/l10n.yaml index 1baa7ccc..a5b40b9e 100644 --- a/l10n.yaml +++ b/l10n.yaml @@ -1,4 +1,4 @@ -arb-dir: lib/i18n +arb-dir: lib/l10n template-arb-file: app_en.arb output-localization-file: app_localizations.dart output-class: I18N \ No newline at end of file diff --git a/lib/l10n b/lib/l10n index aa48825b..0b80ffb6 160000 --- a/lib/l10n +++ b/lib/l10n @@ -1 +1 @@ -Subproject commit aa48825bd15bb294e705be0bcfe584208292ea31 +Subproject commit 0b80ffb67aa3483b1e0f9e9e6832bfce660933cf From 32fd8efddc14fae0675c38dc92f5670b3cadc340 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 1 Feb 2021 22:36:46 +1100 Subject: [PATCH 6/7] Make a bunch o' strings translateable --- lib/l10n | 2 +- lib/widget/category_display.dart | 16 +++---- lib/widget/company_detail.dart | 17 +++---- lib/widget/fields.dart | 6 ++- lib/widget/home.dart | 12 ++--- lib/widget/part_detail.dart | 16 +++---- lib/widget/part_stock_detail.dart | 4 +- lib/widget/refreshable_state.dart | 2 +- lib/widget/search.dart | 10 ++-- lib/widget/stock_detail.dart | 62 +++++++++++++------------ lib/widget/stock_item_test_results.dart | 20 +++++--- 11 files changed, 88 insertions(+), 79 deletions(-) diff --git a/lib/l10n b/lib/l10n index 0b80ffb6..bd7d3270 160000 --- a/lib/l10n +++ b/lib/l10n @@ -1 +1 @@ -Subproject commit 0b80ffb67aa3483b1e0f9e9e6832bfce660933cf +Subproject commit bd7d32707b3987a954038deaf21816cdf55d8780 diff --git a/lib/widget/category_display.dart b/lib/widget/category_display.dart index 46ddbe94..a429f0d7 100644 --- a/lib/widget/category_display.dart +++ b/lib/widget/category_display.dart @@ -3,6 +3,8 @@ import 'package:InvenTree/api.dart'; import 'package:InvenTree/inventree/part.dart'; import 'package:InvenTree/preferences.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + import 'package:InvenTree/widget/part_detail.dart'; import 'package:InvenTree/widget/drawer.dart'; import 'package:InvenTree/widget/refreshable_state.dart'; @@ -19,8 +21,6 @@ class CategoryDisplayWidget extends StatefulWidget { final InvenTreePartCategory category; - final String title = "Category"; - @override _CategoryDisplayState createState() => _CategoryDisplayState(category); } @@ -29,14 +29,14 @@ class CategoryDisplayWidget extends StatefulWidget { class _CategoryDisplayState extends RefreshableState { @override - String getAppBarTitle(BuildContext context) { return "Part Category"; } + String getAppBarTitle(BuildContext context) => I18N.of(context).partCategory; @override List getAppBarActions(BuildContext context) { return [ IconButton( icon: FaIcon(FontAwesomeIcons.edit), - tooltip: 'Edit', + tooltip: I18N.of(context).edit, onPressed: null, ) ]; @@ -94,7 +94,7 @@ class _CategoryDisplayState extends RefreshableState { if (category == null) { return Card( child: ListTile( - title: Text("Part Categories"), + title: Text(I18N.of(context).partCategories), subtitle: Text("Top level part category"), ) ); @@ -107,7 +107,7 @@ class _CategoryDisplayState extends RefreshableState { subtitle: Text("${category.description}"), ), ListTile( - title: Text("Parent Category"), + title: Text(I18N.of(context).parentCategory), subtitle: Text("${category.parentpathstring}"), leading: FaIcon(FontAwesomeIcons.sitemap), onTap: () { @@ -154,7 +154,7 @@ class _CategoryDisplayState extends RefreshableState { ExpansionPanel( headerBuilder: (BuildContext context, bool isExpanded) { return ListTile( - title: Text("Subcategories"), + title: Text(I18N.of(context).subcategories), leading: FaIcon(FontAwesomeIcons.stream), trailing: Text("${_subcategories.length}"), onTap: () { @@ -173,7 +173,7 @@ class _CategoryDisplayState extends RefreshableState { ExpansionPanel( headerBuilder: (BuildContext context, bool isExpanded) { return ListTile( - title: Text("Parts"), + title: Text(I18N.of(context).parts), leading: FaIcon(FontAwesomeIcons.shapes), trailing: Text("${_parts.length}"), onTap: () { diff --git a/lib/widget/company_detail.dart b/lib/widget/company_detail.dart index f98566c0..9716c378 100644 --- a/lib/widget/company_detail.dart +++ b/lib/widget/company_detail.dart @@ -8,6 +8,7 @@ import 'package:InvenTree/widget/refreshable_state.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class CompanyDetailWidget extends StatefulWidget { @@ -28,7 +29,7 @@ class _CompanyDetailState extends RefreshableState { final _editCompanyKey = GlobalKey(); @override - String getAppBarTitle(BuildContext context) { return "Company"; } + String getAppBarTitle(BuildContext context) => I18N.of(context).company; @override Future request(BuildContext context) async { @@ -54,17 +55,17 @@ class _CompanyDetailState extends RefreshableState { var _description; var _website; - showFormDialog(context, "Edit Company", + showFormDialog(context, I18N.of(context).edit, key: _editCompanyKey, actions: [ FlatButton( - child: Text("Cancel"), + child: Text(I18N.of(context).cancel), onPressed: () { Navigator.pop(context); }, ), FlatButton( - child: Text("Save"), + child: Text(I18N.of(context).save), onPressed: () { if (_editCompanyKey.currentState.validate()) { _editCompanyKey.currentState.save(); @@ -80,21 +81,21 @@ class _CompanyDetailState extends RefreshableState { ], fields: [ StringField( - label: "Company Name", + label: I18N.of(context).name, initial: company.name, onSaved: (value) { _name = value; }, ), StringField( - label: "Company Description", + label: I18N.of(context).description, initial: company.description, onSaved: (value) { _description = value; }, ), StringField( - label: "Website", + label: I18N.of(context).website, initial: company.website, allowEmpty: true, onSaved: (value) { @@ -192,7 +193,7 @@ class _CompanyDetailState extends RefreshableState { if (company.notes.isNotEmpty) { tiles.add(ListTile( - title: Text("Notes"), + title: Text(I18N.of(context).notes), leading: FaIcon(FontAwesomeIcons.stickyNote), onTap: null, )); diff --git a/lib/widget/fields.dart b/lib/widget/fields.dart index c8cba169..9878df9f 100644 --- a/lib/widget/fields.dart +++ b/lib/widget/fields.dart @@ -3,6 +3,8 @@ import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:image_picker/image_picker.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + import 'dart:async'; import 'dart:io'; @@ -44,12 +46,12 @@ class ImagePickerField extends FormField { field.didChange(image); } - ImagePickerField({String label = "Attach Image", Function onSaved, bool required = false}) : + ImagePickerField(BuildContext context, {String label = "Attach Image", Function onSaved, bool required = false}) : super( onSaved: onSaved, validator: (File img) { if (required && (img == null)) { - return "Required"; + return I18N.of(context).required; } return null; diff --git a/lib/widget/home.dart b/lib/widget/home.dart index b2d99479..73c28cb3 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -197,10 +197,10 @@ class _InvenTreeHomePageState extends State { children: [ IconButton( icon: new FaIcon(FontAwesomeIcons.barcode), - tooltip: 'Scan Barcode', + tooltip: I18N.of(context).scanBarcode, onPressed: _scan, ), - Text("Scan Barcode"), + Text(I18N.of(context).scanBarcode), ], ), ], @@ -213,20 +213,20 @@ class _InvenTreeHomePageState extends State { children: [ IconButton( icon: new FaIcon(FontAwesomeIcons.shapes), - tooltip: 'Parts', + tooltip: I18N.of(context).parts, onPressed: _parts, ), - Text("Parts"), + Text(I18N.of(context).parts), ], ), Column( children: [ IconButton( icon: new FaIcon(FontAwesomeIcons.boxes), - tooltip: 'Stock', + tooltip: I18N.of(context).stock, onPressed: _stock, ), - Text('Stock'), + Text(I18N.of(context).stock), ], ), ], diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart index d1b7ba11..372e4e1f 100644 --- a/lib/widget/part_detail.dart +++ b/lib/widget/part_detail.dart @@ -2,7 +2,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; - +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -31,7 +31,7 @@ class _PartDisplayState extends RefreshableState { final _editPartKey = GlobalKey(); @override - String getAppBarTitle(BuildContext context) { return "Part"; } + String getAppBarTitle(BuildContext context) => I18N.of(context).part; @override List getAppBarActions(BuildContext context) { @@ -39,7 +39,7 @@ class _PartDisplayState extends RefreshableState { // TODO: Hide the 'edit' button if the user does not have permission!! IconButton( icon: FaIcon(FontAwesomeIcons.edit), - tooltip: 'Edit', + tooltip: I18N.of(context).edit, onPressed: _editPartDialog, ) ]; @@ -88,17 +88,17 @@ class _PartDisplayState extends RefreshableState { var _revision; var _keywords; - showFormDialog(context, "Edit Part", + showFormDialog(context, I18N.of(context).editPart, key: _editPartKey, actions: [ FlatButton( - child: Text("Cancel"), + child: Text(I18N.of(context).cancel), onPressed: () { Navigator.pop(context); }, ), FlatButton( - child: Text("Save"), + child: Text(I18N.of(context).save), onPressed: () { if (_editPartKey.currentState.validate()) { _editPartKey.currentState.save(); @@ -115,12 +115,12 @@ class _PartDisplayState extends RefreshableState { ], fields: [ StringField( - label: "Part Name", + label: I18N.of(context).name, initial: part.name, onSaved: (value) => _name = value, ), StringField( - label: "Part Description", + label: I18N.of(context).description, initial: part.description, onSaved: (value) => _description = value, ), diff --git a/lib/widget/part_stock_detail.dart b/lib/widget/part_stock_detail.dart index 7f73476c..0bd6a5f9 100644 --- a/lib/widget/part_stock_detail.dart +++ b/lib/widget/part_stock_detail.dart @@ -3,7 +3,7 @@ import 'package:InvenTree/inventree/stock.dart'; import 'package:InvenTree/widget/refreshable_state.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; - +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; // InvenTree packages import 'package:InvenTree/api.dart'; import 'package:InvenTree/inventree/part.dart'; @@ -27,7 +27,7 @@ class PartStockDetailWidget extends StatefulWidget { class _PartStockDisplayState extends RefreshableState { @override - String getAppBarTitle(BuildContext context) { return "Part Stock"; } + String getAppBarTitle(BuildContext context) => I18N.of(context).partStock; _PartStockDisplayState(this.part) { // TODO diff --git a/lib/widget/refreshable_state.dart b/lib/widget/refreshable_state.dart index 84cf35ab..7bf1bbde 100644 --- a/lib/widget/refreshable_state.dart +++ b/lib/widget/refreshable_state.dart @@ -2,7 +2,7 @@ import 'package:InvenTree/widget/drawer.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; - +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:InvenTree/widget/drawer.dart'; diff --git a/lib/widget/search.dart b/lib/widget/search.dart index 2b3e2c84..86e6488e 100644 --- a/lib/widget/search.dart +++ b/lib/widget/search.dart @@ -2,7 +2,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; - +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:InvenTree/widget/refreshable_state.dart'; import 'package:InvenTree/inventree/part.dart'; import 'package:InvenTree/inventree/stock.dart'; @@ -23,9 +23,7 @@ class _SearchState extends RefreshableState { List _stockItems = List(); @override - String getAppBarTitle(BuildContext context) { - return "Search"; - } + String getAppBarTitle(BuildContext context) => I18N.of(context).search; Future _search(BuildContext context) { print("Search: $_searchText}"); @@ -76,14 +74,14 @@ class _SearchState extends RefreshableState { children: [ TextField( decoration: InputDecoration( - hintText: "Search" + hintText: I18N.of(context).search, ), onChanged: (String text) { _searchText = text; } ), RaisedButton( - child: Text("Search"), + child: Text(I18N.of(context).search), onPressed: () { _search(context); }, diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index 46b83764..14b1cf21 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -12,6 +12,8 @@ import 'package:InvenTree/widget/stock_item_test_results.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + import 'package:InvenTree/api.dart'; import 'package:InvenTree/widget/drawer.dart'; @@ -35,7 +37,7 @@ class StockDetailWidget extends StatefulWidget { class _StockItemDisplayState extends RefreshableState { @override - String getAppBarTitle(BuildContext context) { return "Stock Item"; } + String getAppBarTitle(BuildContext context) => I18N.of(context).stockItem; @override List getAppBarActions(BuildContext context) { @@ -43,7 +45,7 @@ class _StockItemDisplayState extends RefreshableState { // TODO: Hide the 'edit' button if the user does not have permission!! IconButton( icon: FaIcon(FontAwesomeIcons.edit), - tooltip: "Edit", + tooltip: I18N.of(context).edit, onPressed: _editStockItemDialog, ) ]; @@ -121,11 +123,11 @@ class _StockItemDisplayState extends RefreshableState { _quantityController.clear(); _notesController.clear(); - showFormDialog(context, "Add Stock", + showFormDialog(context, I18N.of(context).addStock, key: _addStockKey, actions: [ FlatButton( - child: Text("Add"), + child: Text(I18N.of(context).add), onPressed: () { if (_addStockKey.currentState.validate()) _addStock(); }, @@ -134,12 +136,12 @@ class _StockItemDisplayState extends RefreshableState { fields: [ Text("Current stock: ${item.quantity}"), QuantityField( - label: "Add Stock", + label: I18N.of(context).addStock, controller: _quantityController, ), TextFormField( decoration: InputDecoration( - labelText: "Notes", + labelText: I18N.of(context).notes, ), controller: _notesController, ) @@ -168,11 +170,11 @@ class _StockItemDisplayState extends RefreshableState { _quantityController.clear(); _notesController.clear(); - showFormDialog(context, "Remove Stock", + showFormDialog(context, I18N.of(context).removeStock, key: _removeStockKey, actions: [ FlatButton( - child: Text("Remove"), + child: Text(I18N.of(context).remove), onPressed: () { if (_removeStockKey.currentState.validate()) _removeStock(); }, @@ -181,13 +183,13 @@ class _StockItemDisplayState extends RefreshableState { fields: [ Text("Current stock: ${item.quantity}"), QuantityField( - label: "Remove stock", + label: I18N.of(context).removeStock, controller: _quantityController, max: item.quantity, ), TextFormField( decoration: InputDecoration( - labelText: "Notes", + labelText: I18N.of(context).notes, ), controller: _notesController, ), @@ -217,11 +219,11 @@ class _StockItemDisplayState extends RefreshableState { _quantityController.text = item.quantity.toString(); _notesController.clear(); - showFormDialog(context, "Count Stock", + showFormDialog(context, I18N.of(context).countStock, key: _countStockKey, actions: [ FlatButton( - child: Text("Count"), + child: Text(I18N.of(context).count), onPressed: () { if (_countStockKey.currentState.validate()) _countStock(); }, @@ -229,13 +231,13 @@ class _StockItemDisplayState extends RefreshableState { ], fields: [ QuantityField( - label: "Count Stock", + label: I18N.of(context).countStock, hint: "${item.quantity}", controller: _quantityController, ), TextFormField( decoration: InputDecoration( - labelText: "Notes", + labelText: I18N.of(context).notes, ), controller: _notesController, ) @@ -271,11 +273,11 @@ class _StockItemDisplayState extends RefreshableState { _quantityController.text = "${item.quantity}"; - showFormDialog(context, "Transfer Stock", + showFormDialog(context, I18N.of(context).transferStock, key: _moveStockKey, actions: [ FlatButton( - child: Text("Transfer"), + child: Text(I18N.of(context).transfer), onPressed: () { if (_moveStockKey.currentState.validate()) { _moveStockKey.currentState.save(); @@ -285,7 +287,7 @@ class _StockItemDisplayState extends RefreshableState { ], fields: [ QuantityField( - label: "Quantity", + label: I18N.of(context).quantity, controller: _quantityController, max: item.quantity, ), @@ -358,7 +360,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( - title: Text("Part"), + title: Text(I18N.of(context).part), subtitle: Text("${item.partName}"), leading: FaIcon(FontAwesomeIcons.shapes), onTap: () { @@ -377,7 +379,7 @@ class _StockItemDisplayState extends RefreshableState { if ((item.locationId > 0) && (item.locationName != null) && (item.locationName.isNotEmpty)) { tiles.add( ListTile( - title: Text("Stock Location"), + title: Text(I18N.of(context).stockLocation), subtitle: Text("${item.locationPathString}"), leading: FaIcon(FontAwesomeIcons.mapMarkerAlt), onTap: () { @@ -393,7 +395,7 @@ class _StockItemDisplayState extends RefreshableState { } else { tiles.add( ListTile( - title: Text("Stock Location"), + title: Text(I18N.of(context).stockLocation), leading: FaIcon(FontAwesomeIcons.mapMarkerAlt), subtitle: Text("No location set"), ) @@ -412,7 +414,7 @@ class _StockItemDisplayState extends RefreshableState { } else { tiles.add( ListTile( - title: Text("Quantity"), + title: Text(I18N.of(context).quantity), leading: FaIcon(FontAwesomeIcons.cubes), trailing: Text("${item.quantity}"), ) @@ -457,7 +459,7 @@ class _StockItemDisplayState extends RefreshableState { if (item.trackingItemCount > 0) { tiles.add( ListTile( - title: Text("History"), + title: Text(I18N.of(context).history), leading: FaIcon(FontAwesomeIcons.history), trailing: Text("${item.trackingItemCount}"), onTap: null, @@ -468,7 +470,7 @@ class _StockItemDisplayState extends RefreshableState { if (item.notes.isNotEmpty) { tiles.add( ListTile( - title: Text("Notes"), + title: Text(I18N.of(context).notes), leading: FaIcon(FontAwesomeIcons.stickyNote), trailing: Text(""), onTap: null, @@ -487,7 +489,7 @@ class _StockItemDisplayState extends RefreshableState { if (!item.isSerialized()) { tiles.add( ListTile( - title: Text("Count Stock"), + title: Text(I18N.of(context).countStock), leading: FaIcon(FontAwesomeIcons.checkCircle), onTap: _countStockDialog, ) @@ -495,7 +497,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( - title: Text("Remove Stock"), + title: Text(I18N.of(context).removeStock), leading: FaIcon(FontAwesomeIcons.minusCircle), onTap: _removeStockDialog, ) @@ -503,7 +505,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( - title: Text("Add Stock"), + title: Text(I18N.of(context).addStock), leading: FaIcon(FontAwesomeIcons.plusCircle), onTap: _addStockDialog, ) @@ -512,7 +514,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( - title: Text("Transfer Stock"), + title: Text(I18N.of(context).transferStock), leading: FaIcon(FontAwesomeIcons.exchangeAlt), onTap: _transferStockDialog, ) @@ -601,14 +603,14 @@ class _StockItemDisplayState extends RefreshableState { return BottomNavigationBar( currentIndex: tabIndex, onTap: onTabSelectionChanged, - items: const [ + items: [ BottomNavigationBarItem( icon: FaIcon(FontAwesomeIcons.infoCircle), - title: Text("Details"), + title: Text(I18N.of(context).details), ), BottomNavigationBarItem( icon: FaIcon(FontAwesomeIcons.wrench), - title: Text("Actions"), + title: Text(I18N.of(context).actions), ), ] ); diff --git a/lib/widget/stock_item_test_results.dart b/lib/widget/stock_item_test_results.dart index c40302fb..0563b355 100644 --- a/lib/widget/stock_item_test_results.dart +++ b/lib/widget/stock_item_test_results.dart @@ -5,6 +5,8 @@ import 'package:InvenTree/api.dart'; import 'package:InvenTree/widget/dialogs.dart'; import 'package:InvenTree/widget/fields.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + import 'dart:io'; import 'package:flutter/cupertino.dart'; @@ -30,7 +32,7 @@ class _StockItemTestResultDisplayState extends RefreshableState(); @override - String getAppBarTitle(BuildContext context) { return "Test Results"; } + String getAppBarTitle(BuildContext context) => I18N.of(context).testResults; @override Future request(BuildContext context) async { @@ -56,7 +58,10 @@ class _StockItemTestResultDisplayState extends RefreshableState[ FlatButton( - child: Text("Cancel"), + child: Text(I18N.of(context).cancel), onPressed: () { Navigator.pop(context); }, ), FlatButton( - child: Text("Save"), + child: Text(I18N.of(context).save), onPressed: () { if (_addResultKey.currentState.validate()) { _addResultKey.currentState.save(); @@ -97,13 +102,13 @@ class _StockItemTestResultDisplayState extends RefreshableState _name = value, ), CheckBoxField( - label: "Result", + label: I18N.of(context).result, hint: "Test passed or failed", initial: true, onSaved: (value) => _result = value, ), StringField( - label: "Value", + label: I18N.of(context).value, initial: value, allowEmpty: true, onSaved: (value) => _value = value, @@ -115,13 +120,14 @@ class _StockItemTestResultDisplayState extends RefreshableState _attachment = attachment, ), StringField( allowEmpty: true, - label: "Notes", + label: I18N.of(context).notes, onSaved: (value) => _notes = value, ), ] From 0421dc535310937e9c9c3e794469c64a6ef5330d Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 1 Feb 2021 22:46:04 +1100 Subject: [PATCH 7/7] Update translation script --- lib/l10n | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n b/lib/l10n index bd7d3270..6b50ee70 160000 --- a/lib/l10n +++ b/lib/l10n @@ -1 +1 @@ -Subproject commit bd7d32707b3987a954038deaf21816cdf55d8780 +Subproject commit 6b50ee704cacfb3d9b45d89de31b1ce05e94959a